Commit Graph
8463 Commits
Author SHA1 Message Date
Dudu-0223 ceaef2c3d0 Clarify durable subagent catalog and list_agents behavior 2026-08-02 12:51:09 +08:00
Dudu-0223 fc59b63c8c docs: propose durable subagent catalog 2026-08-02 12:51:09 +08:00
imccyu 7b3920801b fix(subagent): deduplicate activation teardown 2026-08-02 12:51:08 +08:00
imccyu 4d0a24d8ed test(subagent): preserve durability failure after rebase 2026-08-02 12:51:08 +08:00
imccyu 9cd3c57b75 test(subagent): align continuation fixtures with session API 2026-08-02 12:51:08 +08:00
Dudu-0223 f4a65a34e6 cleanup(subagent): hide manager-wide continuation drain 2026-08-02 12:51:08 +08:00
Dudu-0223 191c8cd640 fix(acp): scope connection-owned continuation drain 2026-08-02 12:51:08 +08:00
Dudu-0223 8f3613c4b7 fix(subagent): close final continuation races 2026-08-02 12:51:08 +08:00
Dudu-0223 a91b20f6be fix(subagent): close continuation lifecycle gaps 2026-08-02 12:51:08 +08:00
Dudu-0223 853f4d5cfb refactor(subagent): drop host-user authority and split lifecycle publication
Remove the host-user continuation capability and the public residency query,
then separate the seam's public event payloads from its internal lifecycle
control interfaces.

`followup()` now takes the exact live direct parent `Agent` instead of a
`SubagentAuthority` union. No production adapter ever supplied user authority,
so the `UserAuthorityGrant` brand token existed only to stop a forged
discriminant from bypassing the direct-parent check — deleting the branch
retires the token, its mint method, and that attack surface together.

Narrowing `parent` from `Agent | undefined` to `Agent` removes three special
cases, including the path where a parentless epoch dispatched its lifecycle
events unscoped. Scoped-versus-global dispatch is now decided by the event, not
by whether a caller happened to have a parent.

`activationState()` had no caller; `ActivationState`, `ActivationObserver`, and
`ContinuationHost` are package-private.

New `src/lifecycle.ts` owns the contained emitter, the one-shot run observer,
and the Activation observer, while `SubagentRunInfo`/`SubagentRunEndInfo` move
to `src/types.ts` beside the other consumer-facing contracts. Those payloads are
public API — dsh-jsonrpc, hooks-claude, and the package invariant all consume
them — whereas the observer is a contract between two in-package collaborators,
so they no longer share a home merely for both being lifecycle-shaped. The
service keeps ownership of the scope carrier: `scopeTarget()` composes the
service's own context filter, so a narrowed stand-in would silently change
scope filtering.

Also drops now-unused dsh-tasks-local and dsh-tool-tasks dev dependencies, and
corrects the README claim that a pre-residency failure emits a terminal edge —
that path only ever rethrew.
2026-08-02 12:51:08 +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 cbaceb73a9 fix(subagent): address codex review round 2
Round 1 traded one teardown ordering problem for another. The observer now
splits capture from emission, which satisfies both consumers at once:

- Terminal facts are captured while the child is still registered, so consumers
  that resolve it for the child's log and scope still work.
- The edge is emitted only after handle disposal settles, so a rejecting scoped
  cleanup is reported as a failed epoch instead of a successful one.

Also:

- Keep the Activation in the map until disposal settles. Removing it first let a
  racing followup() see no Activation and cold-resume into the still-registered
  agent, and let a concurrent forest drain skip a still-disposing child and
  release its parent first.
- Derive terminal telemetry from this epoch's event suffix rather than the whole
  session, so a cold resume whose prompt is blocked no longer reports the
  previous epoch's answer and turn reason.
- Cancel the ACP bridge's own prompts before awaiting the descendant drain: a
  drain can block on persistence, and the top-level agents must not keep running
  model and tool work for its whole duration.
2026-08-02 12:51:08 +08:00
Dudu-0223 c485b6136d fix(subagent): address codex review round 1
All five findings were real:

- The terminal lifecycle edge derived its stop reason from teardown success, so a
  child that errored, hit its token ceiling, or was cancelled reported as
  completed once its checkpoint and disposal succeeded. It now reads the child's
  own last message turn/end, which is authoritative.
- Live delivery never rechecked the caller signal after authorization yielded, so
  an abort that won before acceptance still enqueued the message and returned an
  id. Admission now re-checks at the boundary that owns the decision.
- Drain flushed before cancelling, letting a running turn keep appending events
  the checkpoint could not cover and letting model work continue through a slow
  flush. It now cancels to quiescence first.
- subagent/end fired after AgentHandle.dispose() unregistered the child, so the
  hooks bridge could not resolve it for the child's cwd and scope. The edge now
  publishes while the child is still registered.
- activationState() read Agent.status alone, which stays idle between an accepted
  waking send and the microtask that admits it, so a synchronous inbox observer
  could see settled with a queued turn. Residency now also counts messages this
  manager admitted but has not seen leave the inbox.
2026-08-02 12:51:08 +08:00
Dudu-0223 19d034169e docs: regenerate the config catalog source line
The ACP bridge's new structural teardown type shifts its Config declaration.
2026-08-02 12:51:08 +08:00
Dudu-0223 542a01c407 test(acp): cover the continuable drain ordering and its failure path
Pins that the bridge releases the Activation forest before its own sessions, and
that a failed drain is reported without stranding that teardown. Reads the one
teardown method structurally so the bridge keeps no dependency on the subagent
seam.
2026-08-02 12:51:08 +08:00
Dudu-0223 03973cb074 test(acp-agent): refresh header pins for the new subagent tool wording
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.
2026-08-02 12:51:08 +08:00
Dudu-0223 4435616a04 test(acp-agent): rewrite the continuable snapshot for the Task-free surface
The authored transcript drove task_output, which no longer exists for a
continuable child and is not registered in this config, so the scenario hung.
It now demonstrates the RFC criteria directly: a delegation returning only the
durable subagent id, two send_message follow-ups queueing as later FIFO turns on
one inbox, an unknown id failing without delivery, and child-first disposal
despite a failed final durability checkpoint.

The snapshot-only overlay remaps the transcript's placeholder child id onto the
randomly minted live child, since the scripted model cannot know that id.

Also drops probe logging accidentally committed in cf0138258.
2026-08-02 12:51:08 +08:00
Dudu-0223 c8fbc111db fix(acp): drain continuable subagents before disposing top-level agents
A continuable Activation outlives the turn that started it and owns descendant
teardown, so the bridge must drain that forest child-first before releasing the
top-level agents whose runtime the descendants depend on.

Also rewrites the authored continuable snapshot transcript for the Task-free
tool surface; the scenario's keyless replay is still under diagnosis.
2026-08-02 12:51:08 +08:00
Dudu-0223 3911b7117e test(subagent): reach full continuable coverage and simplify unreachable paths
Adds coverage for the fork-seeded descriptor turn numbering, omitted and declared
descriptor composition fields, a routeless cold resume, and the drain no-op.

Splits materialize's create-versus-resume inputs so the impossible
create-without-meta case disappears, drops the observer's unreachable
pre-residency guard, and annotates the three remaining paths that only a
non-deterministic send-versus-dispose race can reach.
2026-08-02 12:51:08 +08:00
Dudu-0223 bc504195df test(subagent): close continuable coverage and drop unreachable guards
Restores the one-shot settleRun coverage in its own file beside the helper,
covers fork's seed contribution, the post-transfer rollback, the descriptor
model route on cold resume, manager-unload drain, and a failing teardown branch.

Removes three redundant checks the surrounding contracts already own: the
duplicate-Activation and live-id pre-checks (AgentRegistry.enter is the
authoritative collision boundary) and a rollback lifecycle edge that could never
publish because the epoch had no start edge.
2026-08-02 12:51:08 +08:00
Dudu-0223 55f86367ad test(subagent): update in-process specs and pin both durability failure modes
Deletes the in-process durability, resume, and steering tests whose premises the
seam no longer has, keeping a one-shot analogue for agent-option resolution, and
covers both a false and a rejecting final checkpoint in the manager spec.
2026-08-02 12:51:08 +08:00
Dudu-0223 694b078365 docs(subagent): update package READMEs for the activation lifecycle
Rewrites the service API table, authority-versus-provenance contract, residency
routing, and deferred-work list; scopes the in-process driver README to one-shot
runs; and restates both model-facing tools' outputs, which no longer carry a
task id.
2026-08-02 12:51:08 +08:00
Dudu-0223 ae6976cbbd docs(subagent): regenerate catalogs for the activation-based seam
Adds the new continuable types to the cordis-catalog type-link map and
regenerates the cordis api/service/event catalogs, tool catalog, config
catalog, and doc graphs.
2026-08-02 12:51:08 +08:00
Dudu-0223 72f8f47335 docs(subagent): land the continuable-subagents note and supersede its predecessors
Moves the RFC to implemented/, restates it as current-state prose under the
implemented note format, and records what the Task-backed continuable-subagents
note and the two subagent-service simplification notes retain versus what this
record replaces.
2026-08-02 12:51:08 +08:00
Dudu-0223 4e7a5f19cf docs(subagent): rewrite the subagent data-structure doc for activations
wip: Chinese pair and remaining generated catalogs follow.
2026-08-02 12:51:08 +08:00
Dudu-0223 357f317b4c test(subagent): update service, send_message, and delegation specs
The continuable path has no Task, so send_message reports a queued next turn
and continuable delegation returns only the durable child id. Pins that a
follow-up queues behind an open turn rather than steering it, and that a
non-parent caller is rejected.

Also makes startContinuable/followup reject rather than throw synchronously
when continuation services are absent, so callers have one failure mode.
2026-08-02 12:51:08 +08:00
Dudu-0223 1c30548068 test(subagent): rewrite continuation spec for activation lifecycle
Covers the inbox-acceptance return boundary, pre-acceptance rollback,
caller-signal ownership on both sides of acceptance, residency-only routing,
single-inbox FIFO ordering across parent and user origins, waiting wakeup with
a retained handle, cold resume without the historical parent, ownership
registration and release, child-first disposal, send-versus-dispose races,
durability failure without an ownership leak, per-epoch lifecycle pairing, and
the absence of cancellation, steering, and report surfaces.
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-0223 dabd50e067 Merge pull request #506 from deepseek-harness/codex/subagent-send-message-rfc
feat(subagent): add continuable background subagents with follow-ups
2026-08-02 12:51:05 +08:00
imccyu bb6e6d6f3b fix(subagent): preserve continuable behavior after rebase 2026-08-02 04:35:23 +08:00
Dudu-0223 264bc41a13 fix(subagent): preserve ordinary start requests 2026-08-02 04:34:17 +08:00
Tianyi Cui f14121a4c2 refactor(subagent): narrow continuation interface 2026-08-02 04:34:17 +08:00
Dudu-0223 644bf00b86 fix(subagent): cancel pending live delivery 2026-08-02 04:34:17 +08:00
Dudu-0223 fea31a012d fix(subagent): persist descriptor before admission 2026-08-02 04:34:17 +08:00
Dudu-0223 52002791a4 test(acp): stabilize continuable subagent snapshot 2026-08-02 04:34:17 +08:00
Dudu-0223 112e25bb05 refactor(subagent): unify service errors 2026-08-02 04:34:17 +08:00
Dudu-0223 0821ceb033 fix(sdk): mount local task registry for subagents 2026-08-02 04:34:17 +08:00
Dudu-0223 ddab8b84c0 test(goal-session): cover unsettled attempt yield 2026-08-02 04:34:16 +08:00
Dudu-0223 efc47b6a76 fix(subagent): require durability participant 2026-08-02 04:34:16 +08:00
Dudu 88f913a9ae refactor(subagent): merge continuation control service 2026-08-02 04:34:16 +08:00
Dudu-0223 0a95ad8cc0 fix(sdk): mount task controls for subagents 2026-08-02 04:34:16 +08:00
Dudu-0223 43151ed9c0 fix(subagent): preserve cancellation during durability 2026-08-02 04:34:16 +08:00
Dudu-0223 e1f7eeeb95 fix(subagent): confirm steering request admission 2026-08-02 04:34:16 +08:00
Dudu-0223 189502e4ac fix(subagent): preserve follow-up provenance 2026-08-02 04:34:16 +08:00
Dudu-0223 1ab3cbf673 fix(subagent): harden continuable persistence 2026-08-02 04:34:16 +08:00
Dudu-0223 bb8ea2be51 fix(subagent): make strict steering atomic 2026-08-02 04:34:15 +08:00
Dudu-0223 9e5ae0d12e fix: address codex review round 3
- Strict steer additionally requires an OPEN STEP: between steps the
  loop may be awaiting its continuation/turn-stop checkpoints, where
  pending steering was already folded and a terminal stop discards a
  later arrival. A message accepted during an open step is drained and
  recorded at that step's settlement before any terminal decision, so
  the acknowledged-then-discarded window is closed. New keyless test
  holds agent/turn-stop open and pins the rejection.
- tool-subagent-control README: distinguish synchronous not-delivered
  errors from started-Task failures (unknown/foreign/descriptor-less
  ids settle the started Task as failed), and drop the claim that the
  completion notice carries the child's response.
2026-08-02 04:34:15 +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 3be7ca8664 test(loader-smoke): normalize /private/tmp temp paths
macOS realpaths temp dirs into /private. The normalizer only stripped
the /private prefix for TMPDIR under /var; a TMPDIR under /tmp (any
explicitly relocated temp root) left one side canonicalized and the
comparison failing. Accept both shapes.
2026-08-02 04:34:15 +08:00