Commit Graph

61 Commits

Author SHA1 Message Date
pku-xht
a93968bf93 fix(subagent-codex): await managed tree exit 2026-08-04 22:36:31 +08:00
Dudu-0223
431fb4b035 feat(subagent): add explicit child reports 2026-08-02 12:51:10 +08:00
Dudu-0223
a977ef30ee fix(subagent): preserve published run failures 2026-08-02 12:51:09 +08:00
Dudu-0223
774ee34b9a feat(subagent): catalog one-shot child sessions 2026-08-02 12:51:09 +08:00
Dudu-0223
4240c7dd7b feat(subagent): durable child catalog and list_agents
Implements the durable-subagent-catalog RFC: SubagentControlService.listChildren()
enumerates a parent's direct continuable children from one sessionQuery trace,
validates each child's sole subagent/descriptor event (now carrying the durable
creation label), and returns one ordered SubagentListEntry[] with per-child
corrupt/unsupported/unavailable diagnostics. The list_agents tool ships as a
separately loadable plugin of dsh-tool-subagent-control requiring sessionQuery
at load; send_message stays usable without it.
2026-08-02 12:51:09 +08:00
Dudu-0223
7428cdf41e fix(subagent): address codex review round 3
- Make host-user authority unforgeable. `{ kind: 'user' }` was a bare
  discriminant, so any plugin holding `ctx.subagents` — including
  model-generated cordis_mount code, which the advanced ACP composition ships
  alongside continuable subagents — could construct it and skip the
  direct-parent check for any known child id. It now carries an opaque grant
  that only SubagentService.userAuthority() mints, which composition hands to
  trusted host adapters; a model-facing tool uses parent authority from its own
  execution context.
- Reconcile a delivery discarded inside its own admission window. An enqueue
  listener that cancels fires the discard before followup() returns, so the
  discard listener could not clear an id it had not seen; submit() retained it
  and residency stayed `running` until an explicit drain.
- Recheck the caller signal after materialization. An abort landing between
  publication and inbox acceptance still submitted the prompt and returned both
  ids; it now rolls the child back.
- Stop promising the model transcript access that no shipped continuable config
  mounts. The tools now state only that a background child does not report back.
- Restate the implemented note as shipped state rather than a proposal, so it
  works as current authority.
2026-08-02 12:51:08 +08:00
Dudu-0223
26a117f842 feat(subagent): activation-based continuable subagents (source)
Replace the Task-backed continuation manager with one durable Session plus at
most one process-local Activation — a residency epoch for a reconstructed child
Agent, not a request, result, cancellation, or Task boundary. The manager owns
activation admission, authority, the live ownership graph, cold resume, and
child-first disposal; the Agent inbox is the only turn FIFO.

- startContinuable() is async and returns { childId, messageId } at inbox
  acceptance; followup() takes a SubagentAuthority and returns AgentMessageId.
- SubagentProvider.resume?(), SubagentProviderResumeRequest, SubagentRun.steer?(),
  SubagentProviderStartRequest and SubagentContinuation are deleted;
  prepareContinuable?() is the continuable-creation capability.
- Cold resume calls ctx.agents.resume() from the manager through a private
  activation-owner scope, never dispatching through a provider.
- Extract shared child composition, descriptor seeding, depth accounting, and
  one-shot run settlement so the manager and one-shot driver keep one home
  per fact.

Tests and docs follow in subsequent commits.
2026-08-02 12:51:08 +08:00
Dudu
88f913a9ae refactor(subagent): merge continuation control service 2026-08-02 04:34:16 +08:00
Dudu-0223
4eda48d002 fix: address codex review round 2
- Wire the control service and send_message tool into every shipped
  composition with a resumable provider and background enabled
  (headless-agent, tui-agent, and the SDK helper's subagent feature
  base resources); jsonrpc-agent disables background and is unchanged.
- Resolve the send_message availability check in the CALLER's tool
  scope so a restriction that removes the follow-up tool from one
  agent also blocks that agent's continuable start.
- Control-service disposal now cancels live activations and awaits
  producer settlement instead of stranding them: TaskService keeps
  producer Tasks across a reload, so the disposing service aborts each
  activation-owned controller, resolves its terminal gate (the
  effect-scoped onTaskDone listener is already gone), and awaits done.
  A new test kills a mid-start activation through HMR disposal.
2026-08-02 04:34:15 +08:00
Dudu-0223
71570d7bec fix: address codex review round 1
- Strict steer now rejects the two windows where an acknowledged
  message would be silently dropped: the closed-turn durability-flush
  window (status still running, loop strands drained steering) and a
  committed structured capture (terminal turn-stop discards late
  steering). Seam JSDoc, catalog doc, README, and the Agent Note
  bilingual pair state the tightened contract; new keyless tests pin
  both rejections.
- Continuable background delegation now fails loud when the advertised
  send_message tool is not registered, instead of starting a durable
  child the model cannot continue. The acp-agent example already loads
  the control tool; the tool-catalog boot recipe is unaffected because
  capability wording is harvested at mount.
2026-08-02 04:34:15 +08:00
Dudu-0223
99a778d63f feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.

- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
  run-level resume, add SubagentProvider.resume dispatch via
  SubagentService.resume, the continuation start field, and the
  versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
  child id, append the descriptor inside the initial turn, implement
  cold resume from the child's own transcript under the live parent
  scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
  child ids, descriptor snapshot/fold/authorization, Task-backed
  activation with settle-then-dispose ordering, the process-local
  active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
  resume capability (continuable via the control service; one-shot
  task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
  tool rendering steered/started routes.

Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-08-02 04:34:15 +08:00
Yichen Jiang
5358168787 feat(sdk): support max output tokens 2026-07-28 17:36:44 +08:00
Tianyi Cui
7d3cb39047 Merge branch 'codex/tool-json-schema-dsl' into codex/canonical-tool-output
# Conflicts:
#	.agents/notes/implemented/feature/2026-06-30-interception-seams.md
#	docs/config-catalog.md
#	docs/cookbook/adding-a-tool.i18n.yaml
#	docs/cookbook/adding-a-tool.md
#	docs/cookbook/adding-a-tool.zh.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/tools.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	packages/bash/tool-bash/src/index.ts
#	packages/core/agent-loop/src/tool-calls.ts
#	packages/core/agent-loop/tests/cancel.spec.ts
#	packages/core/agent-loop/tests/contract-regressions.spec.ts
#	packages/core/agent-loop/tests/tool-calls.spec.ts
#	packages/core/tools/README.md
#	packages/core/tools/src/index.ts
#	packages/core/tools/tests/code-mode.spec.ts
#	packages/core/tools/tests/tools.spec.ts
#	packages/fs/tool-fs-search/tests/integration.spec.ts
#	packages/fs/tool-fs-search/tests/tools.spec.ts
#	packages/fs/tool-fs/tests/integration.spec.ts
#	packages/mcp/mcp-client/src/tools.ts
#	packages/timeout/timeout-policy/tests/timeout-policy.spec.ts
#	packages/web/tool-web/tests/integration.spec.ts
#	packages/web/tool-web/tests/tool-web.spec.ts
2026-07-21 23:39:03 +08:00
Tianyi Cui
0004b8675f Merge remote-tracking branch 'origin/master' into codex/enforce-tool-cancellation
# Conflicts:
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/snapshots/bash-spill/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/acp-agent/tests/snapshots/fs-escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	packages/context/workspace-context/tests/workspace-context.spec.ts
#	packages/core/agent/src/index.ts
#	packages/support/invariants/tests/invariants.spec.ts
#	packages/ui/acp/src/index.ts
#	packages/ui/tui/tests/harness.ts
#	packages/ui/tui/tests/tui.spec.ts
2026-07-21 20:03:00 +08:00
Tianyi Cui
72a48fede6 Merge branch 'codex/tool-json-schema-dsl' into codex/canonical-tool-output
# Conflicts:
#	docs/event-producer-consumer.md
#	packages/context/time-context/tests/time-context.spec.ts
#	packages/context/workspace-context/tests/workspace-context.spec.ts
2026-07-21 19:56:43 +08:00
Tianyi Cui
66c36e7325 feat: add canonical typed tool outputs 2026-07-21 03:22:14 +08:00
Tianyi Cui
4311aaabb0 Merge remote-tracking branch 'origin/master' into codex/enforce-tool-cancellation
# Conflicts:
#	docs/cookbook/adding-a-tool.i18n.yaml
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	packages/bash/tool-bash/src/index.ts
#	packages/core/agent-loop/README.md
#	packages/core/tools/README.md
#	packages/core/tools/tests/scoped.spec.ts
#	packages/fs/tool-fs-search/tests/tools.spec.ts
#	website/zh-CN/api/harness/events.md
#	website/zh-CN/api/harness/tools.md
2026-07-20 23:00:21 +08:00
Tianyi Cui
8ee54bcb22 Merge latest invariant registration gate
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-20 20:20:10 +08:00
Tianyi Cui
5f806b96f0 Merge latest invariant service seam 2026-07-20 20:19:14 +08:00
Tianyi Cui
1145ee5fc3 fix(invariants): assert runtime relationships, not API shapes 2026-07-20 19:34:19 +08:00
Tianyi Cui
3b7ce2e682 fix(invariants): require justified empty companions 2026-07-20 18:39:37 +08:00
Tianyi Cui
46d60d6d90 fix(tool-subagent): enforce depth only at runtime 2026-07-20 17:58:57 +08:00
Tianyi Cui
1a1ff56ab7 fix(tool-subagent): default maxDepth to 3 2026-07-20 17:12:14 +08:00
Tianyi Cui
941b0411d8 feat(invariants): implement package runtime checks 2026-07-20 00:38:37 +08:00
Tianyi Cui
e8b95c8754 feat(tools): require cancellation signal on every invocation 2026-07-19 23:38:54 +08:00
Tianyi Cui
433670a754 feat(invariants): require package-owned companions 2026-07-19 22:13:50 +08:00
Yichen Jiang
cb74477d42 feat(tool-subagent): default maxDepth 1 with at-cap schema hiding
An omitted maxDepth meant unbounded recursion, and the shipped examples
shipped that default. maxDepth now defaults to 1; a numeric cap requires
the provider's depthLimit capability (the mount fails loud and points to
the explicit 'provider-managed' opt-out for out-of-process providers),
and a child AT the cap loses the delegating tool from its own schema via
the child toolFilter — prompt-face hiding on top of the execution-face
depth check. Examples pin maxDepth explicitly. The ACP snapshot harness
gains Scenario.childToolOmissions so a child session may legitimately
omit declared delegation tools from its pinned header and prompt;
affected subagent/workflow goldens are re-recorded.
2026-07-19 17:20:49 +08:00
Tianyi Cui
6b18db92d6 Merge branch 'codex/simp-hide-concrete-agent-loop' into codex/simp-hide-subagent-internals 2026-07-18 12:34:11 +08:00
Yichen Jiang
97190c81ba Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts:
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
2026-07-16 16:39:13 +08:00
Tianyi Cui
9bba95ff7c Merge branch 'codex/simp-hide-concrete-agent-loop' into codex/simp-hide-subagent-internals 2026-07-15 23:34:36 +08:00
Tianyi Cui
8bb8ac8b3c docs(tasks): condense background task prose
The background-task change repeated its lifecycle design across implemented RFCs, package READMEs, JSDoc, test commentary, and model-visible schemas. That repetition obscured the contracts that maintainers must preserve and added avoidable prompt tokens.

Rewrite the implemented RFCs around the current design, keep authorization, exact-owner cleanup, wait/abort ordering, producer quiescence, and teardown-failure guarantees at their owning surfaces, and remove peer surveys, review history, control-flow narration, and emphatic restatement.

Shorten the task and subagent schema wording, synchronize the bilingual tool cookbook, and regenerate the config, service, RFC, tool, and replay snapshot derivatives. Runtime behavior is unchanged; test edits update prose-only assertions and descriptions.
2026-07-15 21:08:58 +08:00
Tianyi Cui
ed3654da00 docs: reconcile hidden internals with prose standard 2026-07-14 23:38:53 +08:00
Yichen Jiang
815365dbbe Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
#	examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl
#	examples/acp-agent/tests/snapshots/skill-load/session.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/session.jsonl
#	examples/sandbox-acp-agent/cordis.yml
#	examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/mode-switching/session.jsonl
#	packages/compact/compact-basic/README.md
#	packages/compact/compact-basic/src/index.ts
#	packages/compact/compact-basic/tests/compact-basic.spec.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent-loop/tests/properties.spec.ts
#	packages/core/session/README.md
#	packages/core/session/src/types.ts
#	packages/core/session/tests/derived-cache.spec.ts
#	packages/llm/llm-deepseek/src/index.ts
#	packages/llm/llm-pi-ai/README.md
#	packages/llm/llm-pi-ai/src/adapter.ts
#	packages/llm/llm-pi-ai/src/convert.ts
#	packages/llm/llm-pi-ai/tests/adapter.spec.ts
#	packages/llm/llm/README.md
#	packages/llm/llm/src/call-config.ts
#	packages/llm/llm/src/index.ts
#	packages/ui/acp-agent/src/index.ts
#	packages/ui/acp/tests/harness.ts
#	packages/ui/jsonrpc/README.md
#	packages/ui/jsonrpc/src/server.ts
#	packages/ui/stdio-agent/README.md
#	packages/ui/stdio-agent/src/index.ts
#	python/sdk/README.i18n.yaml
2026-07-14 22:17:50 +08:00
Yichen Jiang
e547980d77 feat(llm): route adapters by provider 2026-07-14 21:57:52 +08:00
Yichen Jiang
9956528495 Merge remote-tracking branch 'origin/master' into codex/rfc-subagent-background-tasks
# Conflicts:
#	docs/architecture.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/bash.md
#	docs/event-producer-consumer.md
#	docs/rfc/implemented/feature/2026-07-06-sandbox.md
#	docs/rfc/proposed/architecture/2026-06-20-generic-long-running-tool-runtime.md
#	examples/AGENTS.md
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.golden.md
#	examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.golden.md
#	examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.golden.md
#	examples/acp-agent/tests/snapshots/permission-switching/system-prompt.golden.md
#	examples/acp-agent/tests/snapshots/skill-load/session.jsonl
#	examples/acp-agent/tests/snapshots/skill-load/system-prompt.golden.md
#	examples/acp-agent/tests/snapshots/text-turn/session.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/system-prompt.golden.md
#	examples/coding-agent/cordis.yml
#	examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl
#	examples/sandbox-acp-agent/tests/snapshots/mode-switching/session.jsonl
#	packages/bash/bash-local/README.md
#	packages/bash/bash-local/src/index.ts
#	packages/bash/bash-local/tests/executor.spec.ts
#	packages/bash/bash-sandbox/README.md
#	packages/bash/bash-sandbox/src/index.ts
#	packages/bash/bash/README.md
#	packages/bash/bash/src/index.ts
#	packages/bash/bash/src/types.ts
#	packages/bash/tool-bash/README.md
#	packages/bash/tool-bash/src/index.ts
#	packages/bash/tool-bash/tests/tools.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-core/README.md
#	packages/core/agent-core/src/index.ts
#	packages/subagent/subagent/README.md
#	packages/subagent/tool-subagent/README.md
#	packages/subagent/tool-subagent/src/index.ts
#	packages/ui/acp-agent/README.md
#	packages/ui/acp/README.md
#	packages/ui/stdio-agent/README.md
#	packages/util/brand/src/index.ts
#	scripts/doc-budgets.manifest.json
2026-07-14 18:05:46 +08:00
Tianyi Cui
8ada835396 docs: remove links to private subagent helpers 2026-07-14 08:03:33 +08:00
Tianyi Cui
65521b589f refactor: hide remaining subagent helpers 2026-07-14 02:45:34 +08:00
Tianyi Cui
148046b9c8 docs: rebalance prose cleanup and add trimming skill 2026-07-13 23:27:00 +08:00
Tianyi Cui
c45d7927cf docs: tighten prose audit after master retarget 2026-07-13 16:24:32 +08:00
Yichen Jiang
e2bc79a0ef Merge remote-tracking branch 'origin/master' into codex/rfc-subagent-background-tasks
# Conflicts:
#	docs/architecture.md
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	docs/tool-catalog.md
#	packages/bash/tool-bash/tests/integration.spec.ts
#	packages/bash/tool-bash/tests/tools.spec.ts
#	packages/core/agent-core/tests/agent-core.spec.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/index.ts
#	packages/core/agent/README.md
#	packages/core/agent/src/index.ts
#	packages/core/agent/tests/agent.spec.ts
#	packages/subagent/subagent/README.md
#	packages/subagent/subagent/src/index.ts
#	packages/subagent/tool-subagent/README.md
#	packages/subagent/tool-subagent/src/index.ts
#	pnpm-lock.yaml
#	scripts/doc-budgets.manifest.json
2026-07-13 15:57:17 +08:00
Tianyi Cui
f32cfafa1a refactor: narrow synchronous extension contracts 2026-07-13 11:58:55 +08:00
Tianyi Cui
bb3f6bd736 refactor(subagent): unify async readiness and cancellation 2026-07-12 22:41:59 +08:00
Tianyi Cui
cb03c8c284 fix(scope): align trust and input boundaries
Rewrite the agent-scope RFC with executable examples and an explicit security non-goal. Harden subagent scalar and depth validation, and pin live tool-filter semantics across code, tests, and generated docs.
2026-07-12 11:17:57 +08:00
Tianyi Cui
d427478c44 fix(subagent): validate direct depth boundaries 2026-07-12 10:48:20 +08:00
Tianyi Cui
48067c3a7a fix(subagent): validate depth config at load 2026-07-12 10:33:29 +08:00
Yichen Jiang
35acd34fd9 fix(tools): enforce a disabled run_in_background at execution time (review findings)
enableRunInBackground: false removed the parameter from the advertised
schema only — the arg validator deliberately allows undeclared keys, so
a caller (or a model that has seen the parameter elsewhere) could still
force run_in_background: true and start background work past the
deployment's opt-out, in both tool-bash and tool-subagent. Both
producers now refuse the forced key loud in execute(); tests pin the
refusal (and that nothing spawns) alongside the untouched foreground
path; the schema-omission-is-advertising rule is recorded in the
runtime RFC and both READMEs.
2026-07-09 23:37:51 +08:00
Yichen Jiang
bd59fddacd refactor(tasks): declare-then-execute — ctx.tasks.start() replaces register()
start({ kind, label, owner, run }) preflights everything that can fail
(the attachSurface fence, validation, the owner-cleanup attach) BEFORE
invoking the producer's run() starter, then commits atomically —
'work started but never got a collectable id' is now structurally
impossible instead of a producer try/catch rollback obligation (the
P1 review fix, rebuilt on #185's declare/execute split). Producers
lose their catch-wraps; the leak tests now pin the stronger property
that a failed preflight never spawns anything. TaskRegistration splits
into TaskStart (identity + run) and TaskHooks (cancel/done/readOutput);
docs, type-equiv manifest, catalogs, and both RFCs move with it.
2026-07-09 21:55:07 +08:00
Yichen Jiang
184e164091 feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
Tianyi Cui
7c5133488a refactor(core): every registry register-method returns the exact effect disposer
The exact-disposer fix (5fbac8be B1) repaired agents.register but left the
same wrapper (return () => void dispose()) at seven sibling sites:
tools.register, tools.restrict, systemPrompt.section/tools/variable,
agents.setFactory, and subagents.registerProvider. A wrapper makes correct
composite usage unrepresentable — the exact disposer cannot be recovered, so
a generator effect yielding it leaves the inner effect disposing as a
CONCURRENT SIBLING on owner unload, silently reproducing B1's ordering
corruption. The exact disposer serves both usages (composite-nestable AND
fire-and-forget callable); all seven now return it, typed
() => Promise<void> | void, with the convention pinned by a discriminating
test: an async-link composite probe that passes with the exact disposer and
observes the sibling unregistration firing mid-drain with a wrapper.

Re-auditing also surfaced that B1 itself SHIPPED a full-lint failure: it
changed register()'s return type without updating cross-file consumers
(agent.spec.ts dispose() statements, tool-bash's disposer list), which the
staged-scoped pre-commit lint never saw — pnpm run lint was red at HEAD.
Those three sites and this change's own fallout are fixed together: tests
now await disposers (stronger — they observe the full unwind), sync
paths void them, and the two annotation sites carry the honest union type.
agents.register's README line had drifted the same way (B1 updated the
JSDoc, not the README) — all seven README signatures now match; services
catalog regenerated.
2026-07-09 13:05:44 +08:00
Tianyi Cui
a3244a5774 fix(tool-subagent): an omitted agentOptions must not materialize an empty object
The partial-toolFilter materialization fix (da6c6d58) stopped one field
short: the adjacent agentOptions key in the SAME Config has the same
schemastery trap. An omitted agentOptions materializes {}, which is truthy —
so every yml-configured load put a dishonest agentOptions: {} on every start
request and the presence check in execute() could never be false through
config (only unit tests bypassing schemastery ever exercised that branch).
Harmless downstream today (the driver only spreads it), but the request
shape lied and the check was production-dead.

Same discipline as its toolFilter sibling: the omitted key now defaults to
undefined, the presence check is spelled !== undefined like its neighbors,
and a regression test (fails against the unfixed schema) pins that an
omitted agentOptions stays absent from the request. Swept every other
Config in the repo for the class: no further instances — omitted primitives
inside a materialized object stay ABSENT (verified empirically), so
subagent-mock's capabilities spread is safe, and the remaining object/array
fields all carry explicit defaults or the forced-undefined discipline
already.
2026-07-09 12:33:18 +08:00