interrupt_agent(agent_id) passes the calling agent as the ancestor
authority for ctx.subagents.interrupt(); the service verifies live
registry identity and recorded lineage, so a direct child or deeper
descendant stops with the same generic parameter while send_message keeps
its exact-direct-parent authority.
Discovery: list_agents gains an optional scope. descendants walks the new
SubagentService.listDescendants() — one lineage trace flattened in stable
pre-order across ordinary and one-shot intermediates, each entry carrying
its verified parentId and depth — and every status now comes from the
live Agent registry (running/idle/complete).
Refs #1535
- listChildren() takes an optional AbortSignal and rechecks it after every
un-signalled session-query await (the cold-resume cooperative-cancellation
boundary); list_agents forwards exec.signal so the registry's drain of
started tool bodies cannot block on a slow or large catalog.
- The list_agents description now presents running/complete as a stored-record
snapshot and defers deliverability to send_message, matching the ownership-
conflict semantics the service tests pin.
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.
- 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.
Every scenario compares its live tool schemas and system prompt against the
shared header pins, so the Task-free subagent and send_message descriptions
change all 14 pin sidecars. The diff is only that wording plus the tools'
output-type shapes.
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.
Stack the parallel-in_progress change on the web todo display (#497): the
GUI is now the surface where several active items are visible, so the two
land as a chain rather than colliding on tool-todo at merge time.
Conflicts combined rather than resolved to one side: tool-todo keeps this
branch's parallel-allowing validation AND web2-todo's additionalProperties
unknown-key rejection, in src/index.ts and both README sides; the spec
drops web2-todo's 'two in_progress' rejection case and keeps its unknown-key
case; the two headless advanced-toolchain session fixtures keep this
branch's parallel transcripts.
The origin/master merge added the session-query-spill and
escalation-approved acp scenarios, whose pinned tool-schemas still
carried additionalProperties: true on the todo_write item schema. This
PR tightens that to false (model-visible via the request header), so
re-record it in the two new expected outputs. session-sandbox-root,
escalation-rejected, and fs-escalation-approved compare against the
escalation-approved pinned header and pass once it is fixed.
Remove the single-in_progress cap from todo_write execute validation and
the durable-log invariant so a task list can mirror genuinely parallel
work (concurrent subagents, background commands). Update the tool
description to instruct marking every actively worked task in_progress,
refresh the tool catalog and keyless snapshot expected outputs, and
record the decision in a new Agent Note superseding the original cap.