@deepseek-ai/dsh-subagent 0.2.1-alpha.1 → 0.2.1-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.i18n.yaml +34 -34
  2. package/README.md +32 -26
  3. package/README.zh.md +32 -26
  4. package/lib/index.js +1436 -1304
  5. package/lib/typert.host.js +59 -48
  6. package/lib/typert.remote-client.js +2 -2
  7. package/lib/types/activation.d.ts +114 -0
  8. package/lib/types/activation.js +112 -0
  9. package/lib/types/catalog.d.ts +14 -6
  10. package/lib/types/catalog.js +34 -30
  11. package/lib/types/child-agent.d.ts +1 -3
  12. package/lib/types/child-agent.js +1 -3
  13. package/lib/types/continuation-messages.d.ts +4 -3
  14. package/lib/types/continuation-messages.js +13 -5
  15. package/lib/types/control-types.d.ts +7 -0
  16. package/lib/types/descriptor.d.ts +7 -46
  17. package/lib/types/descriptor.js +20 -21
  18. package/lib/types/index.d.ts +52 -51
  19. package/lib/types/index.js +75 -95
  20. package/lib/types/internal.d.ts +1 -1
  21. package/lib/types/lifecycle.d.ts +28 -58
  22. package/lib/types/lifecycle.js +9 -74
  23. package/lib/types/list-children.js +1 -1
  24. package/lib/types/manager.d.ts +247 -0
  25. package/lib/types/manager.js +1294 -0
  26. package/lib/types/out-of-process.d.ts +2 -28
  27. package/lib/types/out-of-process.js +3 -44
  28. package/lib/types/projection-types.d.ts +3 -0
  29. package/lib/types/structured.d.ts +49 -0
  30. package/lib/types/structured.js +130 -0
  31. package/lib/types/types.d.ts +57 -81
  32. package/lib/types/types.js +1 -1
  33. package/package.json +50 -49
  34. package/lib/types/continuation-activation.d.ts +0 -267
  35. package/lib/types/continuation-activation.js +0 -700
  36. package/lib/types/continuation.d.ts +0 -124
  37. package/lib/types/continuation.js +0 -455
  38. package/lib/types/inbox.d.ts +0 -43
  39. package/lib/types/inbox.js +0 -61
  40. package/lib/types/run-settlement.d.ts +0 -17
  41. package/lib/types/run-settlement.js +0 -70
package/README.i18n.yaml CHANGED
@@ -9,50 +9,50 @@
9
9
  en: 425344cec61f5c70
10
10
  zh: 48e8f2a2e3c1f418
11
11
  /deepseek-ai-dsh-subagent/summary:
12
- en: 300242b82e87aa3e
13
- zh: a4a1319487072484
12
+ en: 6c90e012a583b27f
13
+ zh: 2ec29c0e91fdef60
14
14
  /deepseek-ai-dsh-subagent/table-of-contents:
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
17
  /deepseek-ai-dsh-subagent/use-this-package:
18
- en: 4651aec03a1d2e21
19
- zh: 7b6d1d604bdb1bf1
18
+ en: 924b8c15f9529028
19
+ zh: 9fb0c399b5a79e3e
20
20
  /deepseek-ai-dsh-subagent/use-this-package/enabling-delegation:
21
- en: f66e74a5fa4e49b6
22
- zh: 8c3a793cc29fcc1b
21
+ en: 388ae5427c869173
22
+ zh: aff830f4986cf1b3
23
23
  /deepseek-ai-dsh-subagent/use-this-package/delegation-settings:
24
24
  en: 86c982223fab1a3a
25
25
  zh: 3d220d8ed84eab9a
26
- /deepseek-ai-dsh-subagent/use-this-package/continuable-capacity:
27
- en: 8346a0de39204c1c
28
- zh: 9dd1d926790e5e8c
29
- /deepseek-ai-dsh-subagent/use-this-package/one-shot-and-continuable-children:
30
- en: 10d0a7e0513bf04b
31
- zh: 0cf2c2d81e85d7a9
26
+ /deepseek-ai-dsh-subagent/use-this-package/activation-capacity:
27
+ en: 7c9548b9d02efe1f
28
+ zh: e23bd30b4c9cdabd
29
+ /deepseek-ai-dsh-subagent/use-this-package/local-and-external-children:
30
+ en: 013644290e74493e
31
+ zh: 05014c3c3773edeb
32
32
  /deepseek-ai-dsh-subagent/use-this-package/messaging-interrupting-and-discovering:
33
- en: ff41ac0e770ed865
34
- zh: 27dcf055badf217d
33
+ en: 050177fbbaade432
34
+ zh: 99f2b9f98088314d
35
35
  /deepseek-ai-dsh-subagent/use-this-package/failure-and-recovery:
36
- en: 782aaaf8639c211c
37
- zh: e2a873eece366e74
36
+ en: 245fb0d5c3df5ccf
37
+ zh: e69eed9e5070ce25
38
38
  /deepseek-ai-dsh-subagent/understand-the-implementation:
39
39
  en: 74d91b364b23f88d
40
40
  zh: 19cc558105efe8df
41
41
  /deepseek-ai-dsh-subagent/understand-the-implementation/design-concept:
42
- en: 26c4eb7592b77d14
43
- zh: c166fb6ee1a1c7d8
42
+ en: ed526b6f34a3d6bf
43
+ zh: 47a90717b89d4c79
44
44
  /deepseek-ai-dsh-subagent/understand-the-implementation/source-map:
45
- en: d9afc0d9548afe58
46
- zh: 0e11526b6c001dc6
47
- /deepseek-ai-dsh-subagent/understand-the-implementation/one-shot-flow:
48
- en: 9439bd15ee2129c9
49
- zh: 6c275cf484efa0cf
50
- /deepseek-ai-dsh-subagent/understand-the-implementation/continuable-flow:
51
- en: 9703c868342826cc
52
- zh: e300484cecf15835
45
+ en: 410b6215e3a29221
46
+ zh: d17d6ea102fe8f87
47
+ /deepseek-ai-dsh-subagent/understand-the-implementation/provider-preparation-and-structured-output:
48
+ en: f78c5e931f3a3676
49
+ zh: 3c63f637dbaa8101
50
+ /deepseek-ai-dsh-subagent/understand-the-implementation/activation-settlement:
51
+ en: 2ce43d94b6f7025b
52
+ zh: 970f35558aa1fab5
53
53
  /deepseek-ai-dsh-subagent/understand-the-implementation/ownership-and-invariants:
54
- en: 7384d01be46a2f0a
55
- zh: 83373486ad10d6d5
54
+ en: b74886a091a327d4
55
+ zh: 2124546878ba1aa2
56
56
  /deepseek-ai-dsh-subagent/further-exploration:
57
57
  en: 5b0f408dd901d90a
58
58
  zh: e11866d5fd878327
@@ -63,11 +63,11 @@
63
63
  en: f7cec22ba9d3fb4f
64
64
  zh: 67b1d40f9b136f71
65
65
  /deepseek-ai-dsh-subagent/model-experience/settlement-notice/what-the-model-sees:
66
- en: 44ba290ef9896de9
67
- zh: 21d207c31228c0ce
66
+ en: b61ce5a34e154028
67
+ zh: 861b809745f47672
68
68
  /deepseek-ai-dsh-subagent/model-experience/settlement-notice/token-effect:
69
- en: 45dc428c61f606f5
70
- zh: 7e9a2587e98c8ca6
69
+ en: f98ad834e8ce8950
70
+ zh: cf509805dd934094
71
71
  /deepseek-ai-dsh-subagent/model-experience/settlement-notice/kv-cache-effect:
72
72
  en: d6b1d618083da79b
73
73
  zh: 9a28942b7d53c382
@@ -87,8 +87,8 @@
87
87
  en: 59e848fca82a46fb
88
88
  zh: fcd6a8a2bb58609f
89
89
  /deepseek-ai-dsh-subagent/known-limitations-and-deferred-work:
90
- en: b2182809471f0780
91
- zh: cfab217025442ae8
90
+ en: b663a2e94185901c
91
+ zh: 8d2937aa203bda59
92
92
  /deepseek-ai-dsh-subagent/known-limitations-and-deferred-work/dev-note:
93
93
  en: 25cc0909348666bb
94
94
  zh: 95517f12de100049
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- Use `dsh-subagent` to delegate work to named child agents, collect their results, and continue supported child conversations across turns. A composition can offer in-process, ACP, SDK, Codex, or Claude Code children side by side. Choose one-shot children for a single result or continuable children for later messages and interruption. You can also inspect available children, their mode, live activity, latest closed-turn completion, and lineage without loading or resuming them. Enable at least one supported child backend and a delegation tool.
12
+ Use `dsh-subagent` to delegate work through named providers and collect managed activation results. Local spawn and fork children retain durable sessions for later messages; ACP, DSH SDK, Codex, and Claude Code execute once. Every child shares admission, cancellation, ownership, and discovery. Compose the service with a provider and a delegation tool.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -25,11 +25,13 @@ Use `dsh-subagent` to delegate work to named child agents, collect their results
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
+ Each start accepts an optional `cwd`; relative paths resolve against the parent's current working directory, and omission captures that current directory. The child keeps its parent's origin metadata and permission roots. A child-owned directory value follows any inherited history, survives continuation and restart, and is independent of later parent changes.
29
+
28
30
  This package is the contract every delegation setup shares. You enable it by mounting the service together with one or more provider backends and the model-facing delegation tool; from then on, an agent can delegate work and the service routes each request to the named provider.
29
31
 
30
32
  ### Enabling delegation
31
33
 
32
- Mount the service with a provider and the delegation tool. The provider registers under the name you configure (the in-process spawn backend defaults to `spawn`); the tool row names that provider so the model sees a static tool. A minimal one-shot setup:
34
+ Mount the service with a provider and the delegation tool. The provider registers under its configured name; each tool row selects one provider. A minimal setup:
33
35
 
34
36
  ```yaml
35
37
  - name: '@deepseek-ai/dsh-subagent'
@@ -40,31 +42,31 @@ Mount the service with a provider and the delegation tool. The provider register
40
42
  toolName: subagent
41
43
  ```
42
44
 
43
- An agent that calls the tool gets the child's final answer as the tool result. Mounting the service alone changes nothing: nothing can delegate until a provider and a tool are composed.
45
+ The tool returns a child session id immediately. The parent receives a completion notice when the background activation settles. Mounting the service alone enables no delegation.
44
46
 
45
47
  ### Delegation settings
46
48
 
47
49
  The limits section on the **Plugins → Subagent** page edits the Host’s `subagent` settings section. User values override this plugin's composition; reset removes the user override. `maxDepth` defaults to `1` and supplies the delegation tools' depth when their own configuration omits it. An explicit tool depth, including `provider-managed`, takes precedence. Depth `0` disables delegation through tools inheriting this setting; depth `1` permits direct children only. Changes apply on the next delegation attempt. Direct service callers continue to supply their own optional request depth.
48
50
 
49
- ### Continuable capacity
51
+ ### Activation capacity
50
52
 
51
- Set `maxActiveSubagents` on the host `dsh-subagent` plugin to limit live children sharing uninterrupted continuable parent links. It defaults to `8` and accepts positive safe integers. A non-continuable parent starts a separate pool and does not consume a slot; continuable descendants inherit that pool. Fresh creation and cold resume reserve before reconstructing the Agent, and cleanup returns the slot after handle disposal. A waiting parent, pending inbox work, and an Activation being stopped still occupy slots. Messages to a resident child reuse its slot. One-shot and external-provider runs are outside this limit. Pool inheritance does not cross a one-shot parent; its continuable children share a separate pool. Depth remains the delegation tool's separate policy.
53
+ Set `maxActiveSubagents` on the host plugin to limit live and materializing children in each activation tree. It defaults to `8` and accepts positive safe integers. A top-level parent starts a pool shared by its local and external descendants; the root parent consumes no slot. Creation and cold resume reserve before yielding, and disposal returns the slot only after cleanup. Waiting parents, pending inbox work, and stopping activations remain counted. Sending to a resident child reuses its slot. Delegation depth is a separate policy.
52
54
 
53
55
  The current `maxActiveSubagents` value is sampled before every new or cold-resumed Activation. Raising it admits more children in existing trees; lowering it leaves resident children running and refuses further admissions until usage is below the limit.
54
56
 
55
57
  At capacity, creation or cold resume rejects with `ACTIVATION_LIMIT_REACHED` (browser prompts receive `subagent/delivery-unavailable`): wait for a child to finish or continue using the existing agents. Admission does not queue, because a parent waiting for descendants must not wait for its own occupied slot. Slots are process-local and do not constrain cumulative Session history or token usage.
56
58
 
57
- ### One-shot and continuable children
59
+ ### Local and external children
58
60
 
59
- One-shot children run once and settle with a single result, plus an optional structured output and a safe diagnostic on failure. A start request may override the child Agent's provider, model, reasoning effort, and output-token limit through `agentOptions`; every requested option requires the provider's matching capability. Continuable children keep a durable session and accept later messages in order: the caller receives a stable child id, sends adjacent-Agent messages, and can interrupt the current turn without destroying the child. The tool row's `backgroundMode` picks the shape (`one-shot` by default, or `continuable` on providers that support it).
61
+ `startActivation({ provider, label, request, signal, delivery })` returns `{ childId, messageId?, result, dispose }`. Supplying `childId` selects a local backend and guarantees `messageId`. Local children accept later messages and can cold-resume; external children expose one execution and reject continuation. `request.agentOptions` overrides supported child model settings. `delivery: 'parent'` supplies the model-facing completion notice; `delivery: 'caller'` lets workflows await the result without a parent notice or initial return guidance. Local parent delivery requires persistence; caller delivery can use an ephemeral local session. Cold resume requires persistence and Session query.
60
62
 
61
63
  ### Messaging, interrupting, and discovering
62
64
 
63
- Every exact live Agent can use `sendMessage()` with a direct continuable child; a resident continuable child can also use it with its direct parent. A working target receives the Agent message through Steer at its nearest step; an idle target starts a turn, and only a direct child can be cold-resumed. The parent can also interrupt a running descendant or list its children at any time. A browser continuation prompt independently selects Queue or Steer and may carry image parts: the Host admits and persists each image batch through the attachment store before the child inbox accepts the message, and refuses delivery when the child's declared model does not accept image input. Direct-child discovery reads the parent-owned `subagentCatalog` projection. `listChildren(parentSessionId, signal?)` owns a live-preferred Session observation and returns the catalog asynchronously without reading child logs. It forwards cancellation and releases the observation after materialization. Materialization preserves parent event order in O(D) time for D facts. Descendant discovery recursively reads those child catalogs in parent event order, observing each reachable Session once. It skips branches whose catalogs cannot be read and returns diagnostics for them; neither path loads or resumes a child Agent.
65
+ Every exact live Agent can use `sendMessage()` with a direct continuable child; a resident continuable child can also use it with its direct parent. A working target receives the Agent message through Steer at its nearest step; an idle target starts a turn, and only a direct child can be cold-resumed. The parent can also interrupt a running descendant or list its children at any time. A browser continuation prompt independently selects Queue or Steer and may carry image parts: the Host admits and persists each image batch through the attachment store before the child inbox accepts the message, and refuses delivery when the child's declared model does not accept image input. Direct-child discovery reads the parent-owned `subagentCatalog` projection. `listChildren(parentSessionId, signal?)` owns a live-preferred Session observation and returns the catalog asynchronously without reading child logs. It forwards cancellation and releases the observation after materialization. Materialization preserves parent event order in O(D) time for D facts. External entries are leaves and require no child Session observation. Descendant discovery recursively reads local child catalogs in parent event order, observing each reachable Session once. It skips branches whose catalogs cannot be read and returns diagnostics for them; neither path loads or resumes a child Agent.
64
66
 
65
67
  ### Failure and recovery
66
68
 
67
- Requests that need a capability the chosen provider lacks fail loudly at start rather than being silently ignored. A failed child run returns a stop reason, and provider backends add a safe diagnostic; a cancelled request settles as `aborted`. Children are isolated: a crashed or misbehaving child cannot corrupt the parent's session.
69
+ Starting without the `agents` service rejects with `CONTINUATION_UNAVAILABLE`; an available runtime rejects a missing or replaced parent with `UNAUTHORIZED`. Providers implementing neither execution method are rejected at registration with `UNSUPPORTED_CAPABILITY`; unsupported requested capabilities reject creation with the same code. The caller signal cancels only unpublished work; after publication, `dispose()` cancels the exact activation and waits for its descendants, including pending startups, and their resource cleanup. `result` settles after teardown and notifications, carrying output, optional structured data, and a stop reason; capture failures reject it after teardown. Cleanup failures reject `dispose()` and mark the lifecycle end as failed; the result promise and parent notification retain the captured execution result.
68
70
 
69
71
  -----
70
72
 
@@ -79,8 +81,8 @@ This section explains how the service is built and where the observable behavior
79
81
  ### Design concept
80
82
 
81
83
  - **One service, many providers.** The service is a named-provider registry; each backend registers under a unique name and a request picks one by name.
82
- - **Two child shapes.** One-shot runs transfer ownership at publication; continuable children keep a durable Session and at most one process-local Activation.
83
- - **Fulfillment is publication.** A provider's `start()` fulfills only after a real child exists, so the caller always owns a live run or nothing.
84
+ - **One managed lifetime.** `SubagentManager` owns startup, message admission, capacity, parent relationships, and disposal. Each activation retains a local AgentHandle or external SubagentRun directly; local inbox and idle state belong only to the local variant.
85
+ - **Fulfillment is publication.** `startActivation()` returns only after the child is accepted and its handle can cancel that exact execution.
84
86
  - **Trusted same-process values.** Requests, descriptors, and results are borrowed immutable; serialization and hostile-input validation belong at process and wire boundaries.
85
87
 
86
88
  ### Source map
@@ -88,11 +90,11 @@ This section explains how the service is built and where the observable behavior
88
90
  | File | Role |
89
91
  |---|---|
90
92
  | [`src/index.ts`](src/index.ts) | Service entry: provider registry, start and continuation API, lifecycle events |
91
- | [`src/continuation.ts`](src/continuation.ts) | Continuable orchestration: identity reservation, provider preparation, cold resume, authorization, routing |
92
- | [`src/continuation-activation.ts`](src/continuation-activation.ts) | Process-local Activation graph, admission, settlement, and child-first disposal |
93
+ | [`src/manager.ts`](src/manager.ts) | Unified startup, message admission, cold resume, parent ownership, settlement, and disposal |
94
+ | [`src/activation.ts`](src/activation.ts) | Execution records, capacity slots, child locks, and local output capture |
93
95
  | [`src/continuation-messages.ts`](src/continuation-messages.ts) | Adjacent-Agent messages, return guidance, and settlement notices |
94
96
  | [`src/internal.ts`](src/internal.ts) | Host-only Queue and Steer adapters plus standard adjacent-Agent messaging markers |
95
- | [`src/inbox.ts`](src/inbox.ts) | Activation-local Queue and Steer admission plus the synchronous closing cutoff |
97
+ | [`src/structured.ts`](src/structured.ts) | Activation-scoped structured capture and guards |
96
98
  | [`src/types.ts`](src/types.ts) | Public request, result, and provider contracts |
97
99
  | [`src/descriptor.ts`](src/descriptor.ts) | Versioned `subagent/descriptor` session-event vocabulary |
98
100
  | [`src/catalog.ts`](src/catalog.ts) | Parent-owned `subagent/catalog` event and chunked host projection |
@@ -102,22 +104,26 @@ This section explains how the service is built and where the observable behavior
102
104
  | [`src/control-types.ts`](src/control-types.ts) | Client-safe catalog row, control requests, receipts, and failures |
103
105
  | [`src/archive-admission.ts`](src/archive-admission.ts) | The `subagent` family of the Workspace registry's archive admission: running descendants and their parent-cause cancel |
104
106
 
105
- ### One-shot flow
107
+ ### Provider preparation and structured output
108
+
109
+ The service validates requested capabilities before creation. Local providers supply only `prepareContinuable()`: spawn returns fresh state and fork returns a completed-turn seed. The manager captures the parent model settings, delegated permissions, and composition before creating the child. External providers retain `start()` as a transport adapter and retain their own permission systems. The common manager owns their published execution. Structured tools, instructions, validation, and terminal guards belong to one local activation; they are not persisted as resume configuration. The child can submit its structured result after consuming accepted input and releasing owned descendants. Staging a result closes further input through tool-result policy and any enclosing PTC execution; a rejected result reopens input, while a committed result keeps it closed. Later cold resume has no structured schema.
110
+
111
+ External providers mint a fresh `SubagentRun.id` for each execution in the runtime's shared Session id namespace, across all parents and providers. A collision with a resident Agent, Session, or activation rejects startup with `DUPLICATE_CHILD` and disposes the new external handle without replacing the existing execution.
106
112
 
107
- A request is validated against the provider's advertised capabilities, a durable descriptor is snapshotted, and the provider builds the child. Both in-process providers advertise `agentOptions`: child creation merges requested fields over the provider, model, and reasoning effort in the parent's latest logged request, falls back to creation options before the first request, and retains the configured token limit. They also snapshot delegated permission state before the first await: an Auto or Full access parent gives the child the same `permission/preset` identity, while the existing sandbox override and approval-policy pin continue to apply. Recording both identities prevents an older same-bundle fork value from winning. Auto then reviews every supported child call independently: ordinary project-local work is low risk and allowed, medium-risk work requires explicit action, exact-target and scope authorization from the existing creation prompt or an authenticated human/direct-parent message, without conflicting human limits, while high-risk work is always denied. The reviewer derives that context from `parentSession` and existing messages; delegation adds no parent call metadata, delegation records, review receipt, or Session format. A route change without an explicit effort clears the inherited route-owned effort so the selected model resolves its default. DSH SDK also advertises `agentOptions` but runs a separate child runtime, so it does not inherit Auto; ACP, Codex, and Claude Code likewise retain their own permission systems after the parent delegation call passes review. On success the run is published and ownership transfers to the caller; on failure the provider rolls back every unpublished resource. The result carries the child's final output, an optional structured value, a stop reason, and an optional safe diagnostic.
113
+ ### Activation settlement
108
114
 
109
- ### Continuable flow
115
+ The manager reserves child identity and capacity, materializes a local Agent or external execution, and accepts the initial task. Local admission closes after Agent activity, pending input, and owned descendants finish, with activity revalidated after the final Session flush. Both local and external activations deliver their result after handle cleanup, capacity release, and settlement notifications. Host waits join progressing descendants and their cleanup, including failed executions; idle parked subtrees remain resident without delaying host completion. Closing admission and disposing the handle prevent late work from entering a released Agent. Parent delivery emits its notice after settlement; caller delivery leaves collection to the awaiting workflow. Headless hosts repeat `agent.whenIdle()` and `waitForChildren(agent)` until no child work remains and the parent stays idle with an unchanged Session sequence across the child check, so completion notices can produce the final parent answer.
110
116
 
111
- The manager reserves a child identity, resolves the durable descriptor, creates (or cold-resumes) the child Agent, installs it in an Activation, and submits the prompt. Model-authored messages cross one parent/child edge through fixed Steer scheduling; browser human prompts choose Queue or best-effort Steer through an internal adapter, while other host protocols may retain Queue for distinct turns. A Session queue command admits a live subagent-owned Agent only from its own continuable descriptor. Settlement waits for Agent activity to finish, an empty Inbox, and no owned children, then flushes final Session state with admission open. Under the child lock, the manager revalidates the wake generation, Session sequence, Inbox, and owned children; the synchronous task entry of `Agent.runMaintenance()` claims the idle phase and closes the private subagent Inbox in the same JavaScript turn before handle disposal. An absent direct-child Activation cold-resumes from the persisted session. When a resident Activation settles, the manager tells the child's direct parent in the parent's own turn stream.
117
+ A local Agent failure without a subsequently committed `turn/end` settles as `error` after its owned descendants finish. Unclaimed input cannot keep that failed activation resident. A later committed turn ending supersedes the live failure and supplies the recovered outcome.
112
118
 
113
- Successful local child creation appends a `subagent/catalog` fact to the parent Session. One-shot creation records it after the provider returns; continuable creation records it after initial inbox admission and before returning the child id. Failure releases the child without publishing a compensating catalog event. A one-shot catalog append failure handles the run’s result rejection and preserves the catalog error; disposal failures are logged separately. The `subagentCatalog` projection excludes fork-inherited facts and exposes a direct-child list through `projections.values.subagentCatalog` in Session observations and client snapshots. Each child's `subagentTiming` projection accumulates post-descriptor duration and records whether its latest closed turn ended with `completed`, clearing that completion when another turn opens. Invalid own catalog payloads, including unsupported versions, reject projection restoration. Projection state-version changes refold cached rows from the durable log. The catalog view preserves parent event order in O(D) time for D facts, and its immutable storage and checkpoint validation use [`dsh-chunked-list`](../../util/chunked-list/README.md). [The parent-catalog decision](../../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md) owns ordering, persistence costs, and alternatives. Catalog payload v0 records known modes; v1 also accepts unknown mode. Readers support both versions. Historical migration appends a v1 `subagent/catalog` from a readable child header when its descriptor is unavailable; normal creation retains v0. Its `mode: 'unknown'` projection keeps the child visible without claiming continuation support; an existing complete entry remains authoritative.
119
+ Successful local creation appends a `subagent/catalog` fact to the parent Session regardless of result delivery. External creation appends a catalog fact only with `delivery: 'parent'`; caller-owned external executions retain their caller's membership records. External entries use `mode: 'external'` to identify children without a local Session. Catalog entries record membership once at creation and carry no execution status. Complete results go to the caller or the parent completion notice. Projections exclude inherited facts. Direct lists read one parent projection, so completed local workflow children remain discoverable and can be opened or continued. Catalog payload v0 records local modes; v1 also accepts unknown mode; v2 records external executions. Readers support all three versions. Historical migration appends a v1 `subagent/catalog` from a readable child header when its descriptor is unavailable; local creation retains v0. Its `mode: 'unknown'` projection keeps the child visible without claiming continuation support; an existing complete entry remains authoritative.
114
120
 
115
121
  ### Ownership and invariants
116
122
 
117
- - **Publication is the boundary** — before it the provider owns the setup and must roll back on failure; after it the caller owns the run and must dispose it.
123
+ - **The manager owns accepted work** — unpublished failures roll back; published handles cancel their exact activation and await child-first disposal.
118
124
  - **Registration is effect-scoped** — removing a provider blocks new starts but never revokes accepted runs.
119
125
  - **Agent-message authority is exact adjacency** — `sendMessage()` requires the exact live sender; every sender may target a direct continuable child, while only a sender with a resident continuable Activation may target its direct parent.
120
- - **The descriptor is log-only** — a session event absent from model history and retained across compaction; a continuable descriptor records the resolved child provider, model, and reasoning effort explicitly for cold resume.
126
+ - **The descriptor is log-only** — a session event absent from model history and retained across compaction; the writer records the resolved child provider, model, and reasoning effort for cold resume. Historical one-shot descriptors remain readable.
121
127
  - **This runtime answers archive admission for children** ([seam](../../workspace/workspace/README.md)) — `workspace/session-activity` reports the live subagent descendants inside a turn as the `subagent` family, found by the durable lineage this package records (`parentSession` with the subagent origin, any depth, never a fork) and labelled from each child's descriptor through a live Session observation when the Session query service is composed, otherwise by id; `workspace/session-stop` cancels each of them with the parent cause, one at a time, so one child refusing its cancel is logged while its siblings still stop. The parent's own turn, its jobs, and the archived-lineage step gate belong to the API Session Controller.
122
128
 
123
129
  </details>
@@ -147,11 +153,11 @@ Read these pages when the package-level contract is not enough. They move from t
147
153
 
148
154
  #### What the model sees
149
155
 
150
- One user-role parent message opening with the outcome — `Background subagent <child-id> finished and will do no further work unless you send it more.`, or the matching line for a child that was stopped, ran out of room, declined, or failed — followed by `Its closing message:` and the nonempty text blocks from the child's final assistant output, preserving their content and order. Reasoning and other nontext blocks are excluded; when no nonempty text remains, the notice says `It left no closing message.` This runtime-owned notice is distinct from model-authored parent/child messages, which use `sendMessage()` and `AgentMessageSource`; delegation schemas and model controls belong to the Consumer packages.
156
+ Parent delivery emits a user-role status notice containing the child’s nonempty final text blocks, regardless of `send_message` availability or use. External notices also state that further messages are unsupported. Reasoning and other nontext blocks are excluded. Every parent notice includes available structured output as `Structured result: <JSON>` and the provider’s safe diagnostic as a separate text block. Empty closing text is reported as `It left no closing message.` Caller delivery emits no notice; SDK lifecycle notifications retain complete child output when cleanup succeeds.
151
157
 
152
158
  #### Token effect
153
159
 
154
- One notice per settled Activation in the parent's request, sized by the child's final text. A child that sends its own message and then settles costs the parent both.
160
+ One notice per settled activation using parent delivery. Caller delivery adds no completion message; its consumer owns result presentation.
155
161
 
156
162
  #### KV Cache effect
157
163
 
@@ -185,11 +191,11 @@ Prefix-stable within a child: the statement never changes during the child's lif
185
191
  These limits define when the seam is a poor fit or needs special operational care. They are current package constraints, not a general delegation comparison or a task backlog.
186
192
 
187
193
  - **Descendant reads are sequential** — each reachable catalog, including one-shot children, takes one observation. A cold Session without a valid prepared observation requires a full-log read; large cold trees can accumulate storage latency.
188
- - **ACP children remain one-shot and are not trace-enumerable** — an ACP run has no local child session in the parent's session corpus, and remote providers need an Activation ownership contract before they can support continuable children.
194
+ - **External children execute once** — ACP, DSH SDK, Codex, and Claude Code have no local child Session and accept no follow-up input. Their parent-owned records remain discoverable after disposal.
189
195
  - **Adjacent model messaging only** — `sendMessage()` requires an exact live sender; every sender may target a direct continuable child, while only a sender with a resident continuable Activation may target its direct parent. Browser prompts use a separate human Queue-or-Steer control path.
190
196
  - **A direct parent must remain live for child-to-parent delivery** — the service has no durable parent mailbox; a missing parent rejects the message instead of accepting work it cannot wake.
191
- - **Wake gap during cancellation convergence** — a follow-up accepted after an interrupt signal but before the driver becomes idle stays queued until another waking send.
192
- - **Pending injected context retains an Activation** — settlement conservatively treats every Inbox occurrence as unfinished. Context parked after the Agent becomes idle keeps the child and its live ancestors resident until a waking delivery claims it, a queue mutation removes it, or manager teardown discards it.
197
+ - **Wake gap during cancellation convergence** — a follow-up accepted after an interrupt signal but before the Agent becomes idle stays queued until another waking send.
198
+ - **Pending injected context retains an Activation** — settlement conservatively treats every Inbox occurrence as unfinished. Context parked after the Agent becomes idle keeps the child and its live ancestors resident until a waking delivery claims it, a queue mutation removes it, or manager teardown discards it. Host completion joins active work, pending child creation, and resource cleanup, but does not wait for a subtree containing only idle parked inboxes; it neither completes those activation results nor discards their messages.
193
199
  - **Process-local residency** — the Activation inbox and ownership graph do not coordinate two harness processes; concurrent access to one persistence store needs a durable mailbox and cross-process lease protocol.
194
200
  - **No replay of accepted-but-unlogged messages** — a crash can lose an accepted prompt that never reached the child's session log; the lost message is not replayed automatically.
195
201
  - **No durable parent mailbox** — child-to-parent messages require a resident continuable child and live direct parent, and provide acceptance identity rather than exactly-once delivery.
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 使用 `dsh-subagent` 把工作委派给具名子 agent、收集结果,并跨轮次继续受支持的子级对话。一个组合可以并排提供进程内、ACP(Agent Client Protocol)、SDK、Codex 或 Claude Code 子级。需要单个结果时选择一次性子级;需要后续消息与中断能力时选择可继续子级。你还可以检查可用子级及其模式、在线活动状态、最近已结束轮次的完成状态与谱系,而无需加载或恢复它们。启用时需要至少一个受支持的子级后端和一个委派工具。
12
+ `dsh-subagent` 通过具名提供方委派工作,并收集受管理 activation 的结果。本地 spawn 和 fork 子级保留持久会话以接受后续消息;ACP、DSH SDK、Codex 与 Claude Code 执行一次。所有子级共享准入、取消、所有权与发现机制。使用时组合服务、提供方和委派工具。
13
13
 
14
14
  ## 目录
15
15
 
@@ -25,11 +25,13 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
+ 每次启动可传入可选的 `cwd`;相对路径以父级当前工作目录解析,省略时捕获该当前目录。子级保留父级的起始目录元数据与权限根目录。子级自己的目录值位于继承历史之后,在继续与重启后保留,并独立于父级之后的目录变化。
29
+
28
30
  本包是每个委派组合都共享的约定。你通过把服务与一个或多个提供方后端以及面向模型的委派工具一起挂载来启用它;此后 agent 即可委派工作,服务会把每个请求路由到具名提供方。
29
31
 
30
32
  ### 启用委派
31
33
 
32
- 把服务与一个提供方和委派工具一起挂载。提供方以你配置的名称注册(进程内 spawn 后端默认为 `spawn`);工具行指名该提供方,让模型看到一个静态工具。一个最小的一次性配置:
34
+ 挂载服务、提供方与委派工具。提供方按配置名称注册,每个工具行选择一个提供方。最小配置如下:
33
35
 
34
36
  ```yaml
35
37
  - name: '@deepseek-ai/dsh-subagent'
@@ -40,31 +42,31 @@ kind: "package-reference"
40
42
  toolName: subagent
41
43
  ```
42
44
 
43
- 调用该工具的 agent 会把子 agent 的最终答案作为工具结果收到。只挂载服务本身不会改变任何行为:在组合出提供方和工具之前,什么都不能委派。
45
+ 工具立即返回子会话 ID,后台 activation 结算后父级收到完成通知。仅挂载服务本身不会启用委派。
44
46
 
45
47
  ### 委派设置
46
48
 
47
49
  **插件 → 子智能体**页面的限制部分编辑 Host 的 `subagent` 设置分节。用户值覆盖本插件的组合配置;恢复默认会删除用户覆盖。`maxDepth` 默认为 `1`,在委派工具自身未配置深度时提供默认值。工具显式指定的深度(包括 `provider-managed`)优先。深度 `0` 禁止继承此设置的工具委派;深度 `1` 只允许直接子代理。修改在下一次委派时生效。直接调用服务的调用方仍自行提供可选的请求深度。
48
50
 
49
- ### 可续接子代理容量
51
+ ### Activation 容量
50
52
 
51
- 在 Host 的 `dsh-subagent` 插件上设置 `maxActiveSubagents`,限制通过连续可续接父子关系共享名额的存活子代理数。默认值为 `8`,接受正安全整数。非可续接父代理建立独立的池,自身不占名额;可续接后代继承该池。新建和冷恢复在重建 Agent 前预占名额,清理在 handle 释放后归还名额。等待后代的父代理、有待处理收件箱内容的代理以及正在停止的 Activation 仍占名额。向驻留子代理发送消息复用其名额。一次性和外部提供方运行不受此限制。池的继承不会跨越一次性父代理;其可续接子代理共享独立的池。深度仍由委派工具的独立策略决定。
53
+ 在 Host 插件上设置 `maxActiveSubagents`,限制每棵 activation 树中在线和正在创建的子级数量。默认值为 `8`,接受正安全整数。顶层父级建立由本地和外部后代共享的池,根父级不占名额。新建和冷恢复在让出执行前预留名额,资源释放完成后才归还。等待后代、有待处理收件箱内容以及正在停止的 activation 仍计入容量;向驻留子级发送消息复用其名额。委派深度是独立策略。
52
54
 
53
55
  每次新建或冷恢复 Activation 前都会读取当前 `maxActiveSubagents`。调高后已有树可接纳更多子代理;调低后驻留子代理继续运行,使用量降至上限以下前拒绝新接纳。
54
56
 
55
57
  容量耗尽时,新建或冷恢复以 `ACTIVATION_LIMIT_REACHED` 拒绝(浏览器消息返回 `subagent/delivery-unavailable`):等待子代理完成,或继续使用现有代理。接纳不会排队,避免等待后代的父代理又等待自己占用的名额。名额仅存在于当前进程,不限制累计 Session 历史或 token 用量。
56
58
 
57
- ### 一次性与可继续子级
59
+ ### 本地与外部子级
58
60
 
59
- 一次性子 agent 只运行一次,并以单个结果结算,可附带可选的结构化输出与失败时的安全诊断。启动请求可以通过 `agentOptions` 覆盖子 Agent 的提供方、模型、推理强度与输出 token 上限;每个请求的选项都要求提供方声明对应能力。可继续子 agent 保留持久会话并按顺序接受后续消息:调用方收到稳定的子 agent id、发送相邻 Agent 消息,并可中断当前轮次而不销毁子 agent。工具行的 `backgroundMode` 选择形态(默认 `one-shot`,或在支持的提供方上使用 `continuable`)。
61
+ `startActivation({ provider, label, request, signal, delivery })` 返回 `{ childId, messageId?, result, dispose }`。提供 `childId` 会选择本地后端,并保证返回 `messageId`。本地子级接受后续消息并支持冷恢复;外部子级只暴露一次执行,拒绝继续输入。`request.agentOptions` 覆盖后端支持的子级模型设置。`delivery: 'parent'` 提供面向模型的完成通知;`delivery: 'caller'` 让工作流等待结果,不发送父级通知,也不附加初始返回指导。本地父级投递需要持久化,调用方投递可以使用临时本地会话;冷恢复需要持久化与 Session 查询服务。
60
62
 
61
63
  ### 消息、中断与发现
62
64
 
63
- 每个确切在线 Agent 都可以对直接可继续 child 使用 `sendMessage()`;驻留的可继续 child 还可以对自己的直接 parent 使用它。正在工作的目标通过 Steer 在最近 step 接收 Agent 消息;空闲目标启动轮次,且只有直接 child 可以冷恢复。parent 也可以随时中断正在运行的后代或列举自己的子级。浏览器发出的继续执行 prompt 会独立选择 Queue 或 Steer,并且可以携带图片部分:Host 先通过附件存储完成整批图片的准入与持久化,子级 inbox 才接受这条消息;当子级声明的模型不接受图片输入时拒绝投递。 直接子级发现读取 parent 自有的 `subagentCatalog` projection。`listChildren(parentSessionId, signal?)` 持有一次优先实时来源的 Session 观察,异步返回目录,不读取子级日志。它转发取消信号,并在物化后释放观察。物化以 O(D) 时间保留 D 条事实的父日志事件顺序。后代发现按父事件顺序递归读取子级目录,每个可达 Session 观察一次。无法读取目录的分支会被跳过,并返回诊断;两条路径都不加载或恢复子级 Agent。
65
+ 每个确切在线 Agent 都可以对直接可继续 child 使用 `sendMessage()`;驻留的可继续 child 还可以对自己的直接 parent 使用它。正在工作的目标通过 Steer 在最近 step 接收 Agent 消息;空闲目标启动轮次,且只有直接 child 可以冷恢复。parent 也可以随时中断正在运行的后代或列举自己的子级。浏览器发出的继续执行 prompt 会独立选择 Queue 或 Steer,并且可以携带图片部分:Host 先通过附件存储完成整批图片的准入与持久化,子级 inbox 才接受这条消息;当子级声明的模型不接受图片输入时拒绝投递。 直接子级发现读取 parent 自有的 `subagentCatalog` projection。`listChildren(parentSessionId, signal?)` 持有一次优先实时来源的 Session 观察,异步返回目录,不读取子级日志。它转发取消信号,并在物化后释放观察。物化以 O(D) 时间保留 D 条事实的父日志事件顺序。外部条目是叶节点,不需要观察子 Session。后代发现按父事件顺序递归读取子级目录,每个可达 Session 观察一次。无法读取目录的分支会被跳过,并返回诊断;两条路径都不加载或恢复子级 Agent。
64
66
 
65
67
  ### 失败与恢复
66
68
 
67
- 需要所选提供方不具备的能力的请求会在启动时明确报错,而不会被静默忽略。失败的子 agent 运行会返回停止原因,提供方后端还会附加安全诊断;被取消的请求以 `aborted` 结算。子 agent 相互隔离:崩溃或行为异常的子 agent 无法破坏父级会话。
69
+ 缺少 `agents` 服务时,启动请求以 `CONTINUATION_UNAVAILABLE` 拒绝;运行时可用但父级缺失或被替换时,以 `UNAUTHORIZED` 拒绝。未实现任何执行方法的提供方会在注册时以 `UNSUPPORTED_CAPABILITY` 被拒绝;请求不受支持的能力会以同一码使创建失败。调用方信号仅取消尚未发布的工作;发布后通过 `dispose()` 取消该次 activation,并等待其后代(包括正在启动的后代)及其资源清理完成。`result` 在清理与通知结束后完成,携带输出、可选结构化数据与停止原因;结果捕获故障在清理后使其拒绝。清理失败使 `dispose()` 拒绝,并将生命周期结束事件标记为失败;结果 promise 与父级通知保留已捕获的执行结果。
68
70
 
69
71
  -----
70
72
 
@@ -79,8 +81,8 @@ kind: "package-reference"
79
81
  ### 设计理念
80
82
 
81
83
  - **一个服务,多个提供方。** 服务是具名提供方注册表;每个后端以唯一名称注册,请求按名称选择一个。
82
- - **两种子级形态。** 一次性运行在发布时转移所有权;可继续子级保留持久 Session,且同一时刻至多一个进程内 Activation。
83
- - **兑现即发布。** 提供方的 `start()` 只有在真实子 agent 存在后才兑现,因此调用方要么拥有一段在线运行,要么一无所有。
84
+ - **统一受管理生命周期。** `SubagentManager` 统一管理启动、消息准入、容量、父子关系与释放。每条 activation 直接持有本地 AgentHandle 或外部 SubagentRun;本地 inbox 与空闲状态仅属于本地分支。
85
+ - **兑现即发布。** `startActivation()` 仅在子级已接受且句柄可取消该次执行后返回。
84
86
  - **同进程值可信。** 请求、描述符与结果按不可变约定借用;序列化与不可信输入校验属于进程与协议边界。
85
87
 
86
88
  ### 源码地图
@@ -88,11 +90,11 @@ kind: "package-reference"
88
90
  | 文件 | 职责 |
89
91
  |---|---|
90
92
  | [`src/index.ts`](src/index.ts) | 服务入口:提供方注册表、启动与继续 API、生命周期事件 |
91
- | [`src/continuation.ts`](src/continuation.ts) | 可继续子级编排:身份预留、提供方准备、冷恢复、授权与路由 |
92
- | [`src/continuation-activation.ts`](src/continuation-activation.ts) | 进程内 Activation 图、准入、结算与子级优先释放 |
93
+ | [`src/manager.ts`](src/manager.ts) | 统一管理启动、消息准入、冷恢复、父子所有权、结算与释放 |
94
+ | [`src/activation.ts`](src/activation.ts) | 执行期记录、容量槽、子级锁与本地输出捕获 |
93
95
  | [`src/continuation-messages.ts`](src/continuation-messages.ts) | 相邻 Agent 消息、返回指引与结算通知 |
94
96
  | [`src/internal.ts`](src/internal.ts) | Host 专用 Queue 与 Steer 适配器,以及标准相邻 Agent 消息标记 |
95
- | [`src/inbox.ts`](src/inbox.ts) | Activation 局部的 Queue 和 Steer 准入,以及同步 closing cutoff |
97
+ | [`src/structured.ts`](src/structured.ts) | Activation 局部结构化捕获与保护 |
96
98
  | [`src/types.ts`](src/types.ts) | 公开的请求、结果与提供方约定 |
97
99
  | [`src/descriptor.ts`](src/descriptor.ts) | 版本化的 `subagent/descriptor` 会话事件词汇 |
98
100
  | [`src/catalog.ts`](src/catalog.ts) | parent 自有的 `subagent/catalog` 事件与分块 host projection |
@@ -102,22 +104,26 @@ kind: "package-reference"
102
104
  | [`src/control-types.ts`](src/control-types.ts) | client-safe 的目录行、控制面请求、回执与失败 |
103
105
  | [`src/archive-admission.ts`](src/archive-admission.ts) | Workspace 注册表归档准入中的 `subagent` 族:运行中的子孙及其父级取消 |
104
106
 
105
- ### 一次性流程
107
+ ### 提供方准备与结构化输出
108
+
109
+ 服务在创建前校验请求能力。本地提供方只提供 `prepareContinuable()`:spawn 返回全新状态,fork 返回已完成轮次的初始内容。管理器在创建子级前捕获父级模型设置、委派权限和组合。外部提供方保留 `start()` 作为传输适配器,并保留各自的权限系统;统一管理器拥有已发布的执行。结构化工具、指令、校验与终止保护仅属于一次本地 activation,不作为恢复配置持久化。子代理只能在消费已接受的输入且所属后代释放后提交结构化结果。结果暂存后,在工具结果策略及外层 PTC 执行完成前拒绝继续输入;结果被拒绝后重新开放输入,提交成功后则保持关闭。后续冷恢复不带结构化 schema。
110
+
111
+ 外部提供方为每次执行生成新的 `SubagentRun.id`,在运行时共享的 Session id 命名空间中跨所有父级和提供方保持唯一。与驻留 Agent、Session 或 activation 冲突时,启动以 `DUPLICATE_CHILD` 拒绝,并释放新的外部句柄,不替换已有执行。
106
112
 
107
- 请求先对照提供方声明的能力进行校验,随后对持久化描述符做快照,再由提供方构建子 agent。两个进程内提供方都声明 `agentOptions`:创建子级时把请求字段叠加到父级最新已记录请求的提供方、模型与推理强度之上;父级还没有请求时回退到创建选项,并保留配置的 token 上限。它们还会在第一次 await 前快照委派权限状态:Auto 或 Full access 父级让子级获得相同的 `permission/preset` 身份,而既有沙箱覆盖与审批策略固定仍然生效;同时记录这两个身份可防止 fork 中更早的同旋钮组合身份胜出。Auto 随后会独立审查 child 的每个受支持调用:普通项目内工作为低风险并直接允许;中风险工作必须在既有创建 prompt 或已核验的 human/直接父级消息中获得动作、准确目标和范围的明确授权,且不与 human 限制冲突;高风险工作始终拒绝。reviewer 从 `parentSession` 与既有消息派生这份上下文;委派不会新增父 call metadata、委派记录、review receipt 或 Session format。更改路由而不显式指定推理强度时,会清除继承的路由自有强度,使所选模型解析自己的默认值。DSH SDK 也声明 `agentOptions`,但会运行独立子运行时,因此不继承 Auto;ACP、Codex 与 Claude Code 同样在父级委派调用通过审查后保留各自的权限系统。成功时运行被发布、所有权转移给调用方;失败时提供方回滚每个尚未发布的资源。结果携带子 agent 的最终输出、可选的结构化值、停止原因与可选的安全诊断。
113
+ ### Activation 结算
108
114
 
109
- ### 可继续流程
115
+ 管理器预留子级身份与容量,创建本地 Agent 或外部执行,并接受初始任务。本地 Agent 活动、待处理输入及所拥有的后代均结束后,管理器在最终 Session flush 后重新验证活动状态并关闭准入。本地与外部 activation 都在句柄清理、容量归还及结算通知结束后交付结果。宿主等待会汇合仍在推进的后代及其清理,包括失败的执行;空闲停放子树继续驻留,但不延迟宿主完成。关闭准入并释放句柄可防止迟到工作进入已释放的 Agent。父级投递在结算后发送通知;调用方投递由等待中的工作流收集。Headless 宿主交替等待 `agent.whenIdle()` 与 `waitForChildren(agent)`,直至没有子级工作,且父级在检查子级期间保持空闲、Session 序号不变,让完成通知可驱动父级生成最终答案。
110
116
 
111
- 管理器预留 child 身份、解析持久化描述符、创建(或冷恢复)child、把它安装进 Activation 并提交提示词。模型编写的消息通过固定 Steer 调度跨一条 parent/child 边;浏览器人类 prompt 通过内部适配器选择 Queue 或 best-effort Steer,其他 host 协议仍可保留 Queue 以创建独立轮次。Session queue command 仅根据 child 自身的 continuable descriptor 准入在线 subagent-owned Agent。Settlement 会等待 Agent 活动结束、Inbox 为空且没有所拥有子级,再在准入开放时 flush 最终 Session 状态。管理器随后在 child lock 内重新验证 wake generation、Session 序号、Inbox 与所拥有子级;`Agent.runMaintenance()` 的同步 task 入口会占用 idle 阶段,并在同一个 JavaScript turn 内关闭私有 subagent Inbox,然后才释放句柄。直接 child 不存在 Activation 时会从持久化会话冷恢复。当驻留 Activation 结算时,管理器会在 parent 自身的轮次流中告知该 child 的直接 parent。
117
+ 本地 Agent 发生失败且后续没有成功提交 `turn/end` 时,会在所拥有的后代结束后以 `error` 结算。未认领的输入不会使该失败 activation 一直驻留。后续成功提交的轮次结束记录会取代实时失败,提供恢复后的结果。
112
118
 
113
- 本地子级创建成功时,父 Session 追加一条 `subagent/catalog` 事实。一次性创建在提供方返回后记录;可继续创建在初始 inbox 准入后、返回子级 id 前记录。失败会释放子级,不发布补偿性目录事件。一次性目录追加失败时会处理 run 的结果拒绝,并保留目录错误;资源释放失败会单独记录。`subagentCatalog` projection 排除 fork 继承的事实,通过 Session 观察和客户端快照中的 `projections.values.subagentCatalog` 暴露直接子级列表。每个 child 的 `subagentTiming` projection 会累加 descriptor 之后的耗时,并记录最近一个已结束轮次是否以 `completed` 结束;新轮次打开时会清除该完成状态。无效的自身 catalog payload(包括不支持的版本)会使 projection 恢复失败。projection 状态版本变更会从持久日志重新折叠缓存行。目录视图对 D 条事实以 O(D) 时间保留父目录事件顺序,其不可变存储和检查点校验使用 [`dsh-chunked-list`](../../util/chunked-list/README.zh.md)。[父目录决策](../../../.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md) 说明排序、持久化成本和替代方案。Catalog 载荷 v0 记录已知模式,v1 还接受未知模式,读取器支持两版。历史迁移在 descriptor 不可用时根据可读子 header 追加 v1 `subagent/catalog`;正常创建保留 v0。其 `mode: 'unknown'` 投影让子会话保持可见,但不表示支持继续执行;已有完整条目仍具有权威性。
119
+ 本地创建成功后,无论结果交付给谁,都会向父 Session 追加 `subagent/catalog` 事实。外部创建仅在使用 `delivery: 'parent'` 时追加目录事实;调用方拥有的外部执行保留调用方自己的成员记录。外部条目以 `mode: 'external'` 标记没有本地 Session 的子级。目录仅在创建时记录一次成员关系,不携带执行状态。完整结果交给调用方或父级完成通知。投影排除继承事实。直接列表读取一个父级投影,因此已完成的本地工作流子级仍可被发现、打开或继续。Catalog 载荷 v0 记录本地模式,v1 还接受未知模式,v2 记录外部执行,读取器支持三版。历史迁移在 descriptor 不可用时根据可读子 header 追加 v1 `subagent/catalog`;本地创建保留 v0。其 `mode: 'unknown'` 投影让子会话保持可见,但不表示支持继续执行;已有完整条目仍具有权威性。
114
120
 
115
121
  ### 所有权与不变式
116
122
 
117
- - **发布即边界**——发布前提供方拥有设置并须在失败时回滚;发布后调用方拥有运行并须 dispose(资源释放)它。
123
+ - **管理器拥有已接受工作**——未发布的失败会回滚;已发布句柄取消对应 activation,并等待子级优先释放。
118
124
  - **注册受 effect 作用域约束**——移除提供方会阻止新启动,但绝不撤销已接受的运行。
119
125
  - **Agent 消息权限基于确切相邻关系**——`sendMessage()` 要求确切在线 sender;每个 sender 都可以指定直接可继续 child,只有具备驻留可继续 Activation 的 sender 可以指定自己的直接 parent。
120
- - **描述符仅进日志**——它是会话事件,不进入模型历史,并跨压缩(compaction)保留;可继续描述符会显式记录解析后的子级提供方、模型与推理强度,用于冷恢复。
126
+ - **描述符仅进日志**——它是会话事件,不进入模型历史,并跨压缩(compaction)保留;写入器记录解析后的子级提供方、模型与推理强度,用于冷恢复。历史 one-shot 描述符仍可读取。
121
127
  - **本 runtime 为子代理回答归档准入**([接缝](../../workspace/workspace/README.zh.md))——`workspace/session-activity` 把回合中的在线子代理子孙作为 `subagent` 族报告:按本包记录的持久化血缘查找(带 subagent 来源的 `parentSession`,任意深度,从不包括 fork),组合了 Session query 服务时经一次活会话 observation 从各 child 的描述符取名称,否则只报 id;`workspace/session-stop` 以父级原因逐个取消它们,一个拒绝取消的 child 只记日志,其兄弟仍会停止。父级自身的回合、它的任务以及已归档血缘的步骤门禁归 API Session Controller。
122
128
 
123
129
  </details>
@@ -147,11 +153,11 @@ kind: "package-reference"
147
153
 
148
154
  #### 模型看到什么
149
155
 
150
- 一条用户角色的父级消息,开头是结果本身——`Background subagent <child-id> finished and will do no further work unless you send it more.`,或子级被停止、耗尽额度、拒绝任务或失败时的对应句子——随后是 `Its closing message:` 与子级最终 assistant 输出中的非空文本块,保留原始内容与顺序。推理与其他非文本块不会进入通知;若没有剩余的非空文本,通知会写明 `It left no closing message.`。这条由运行时生成的通知与模型编写的父子消息相互独立;后者使用 `sendMessage()` 与 `AgentMessageSource`。委派 schema 与模型控制工具归消费方包所有。
156
+ 父级投递发送包含子级最终输出中非空文本块的 user-role 状态通知,不受 `send_message` 是否可用或是否调用影响。外部通知还说明不支持后续消息。推理及其他非文本块被排除。每条父级通知都会以 `Structured result: <JSON>` 附带可用的结构化输出,并以独立文本块附带提供方安全诊断。收尾文本为空时,通知使用 `It left no closing message.`。调用方投递不发送通知;清理成功时 SDK 生命周期通知保留完整子级输出。
151
157
 
152
158
  #### Token 影响
153
159
 
154
- 父级请求中,每个已结算的 Activation 一条通知,长度取决于子级的最终文本。如果子级先发送自己的消息再结算,父级请求会同时承担两者。
160
+ 父级投递为每个结算的 activation 添加一条通知。调用方投递不添加完成消息,由其消费者负责展示结果。
155
161
 
156
162
  #### KV Cache 影响
157
163
 
@@ -185,11 +191,11 @@ You are a delegated subagent: your permission scope was fixed when you were star
185
191
  这些限制说明该 seam 何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是通用委派对比或任务积压。
186
192
 
187
193
  - **后代读取串行执行**——每个可达目录(包括一次性子级)都需要一次观察。冷 Session 缺少有效的 prepared 观察时需要读取完整日志;大型冷会话树可能累积存储延迟。
188
- - **ACP 子级仍为一次性,且无法通过追踪枚举**——ACP 运行在父级会话语料中没有本地子会话,远程提供方需要 Activation 所有权约定才能支持可继续子级。
194
+ - **外部子级执行一次**——ACP、DSH SDK、Codex 与 Claude Code 没有本地子 Session,也不接受后续输入。释放后仍可发现父级拥有的执行记录。
189
195
  - **仅允许相邻模型消息**——`sendMessage()` 要求确切在线 sender;每个 sender 都可以指定直接可继续 child,只有具备驻留可继续 Activation 的 sender 可以指定自己的直接 parent。浏览器提示使用独立的人类 Queue 或 Steer 控制路径。
190
196
  - **child 到 parent 的投递要求直接 parent 保持在线**——服务没有持久 parent mailbox;parent 缺失时会拒绝消息,而非接受无法唤醒的工作。
191
- - **取消收敛期间存在唤醒缺口**——中断信号发出后、driver 进入 idle 前被接受的后续消息会保持排队,直到另一条唤醒发送到达。
192
- - **待处理的注入上下文会保留 Activation**——settlement 会保守地把每个 Inbox occurrence 都视为未完成。Agent 进入 idle 后停放的上下文会让 child 及其在线祖先继续驻留,直到唤醒投递将其 claim、queue 变更将其移除,或 manager teardown 将其丢弃。
197
+ - **取消收敛期间存在唤醒缺口**——中断信号发出后、Agent 进入 idle 前被接受的后续消息会保持排队,直到另一条唤醒发送到达。
198
+ - **待处理的注入上下文会保留 Activation**——settlement 会保守地把每个 Inbox occurrence 都视为未完成。Agent 进入 idle 后停放的上下文会让 child 及其在线祖先继续驻留,直到唤醒投递将其 claim、queue 变更将其移除,或 manager teardown 将其丢弃。宿主完成检查等待活动工作、待创建子级与资源清理,但不会等待仅包含空闲停放 Inbox 的子树;它既不结算这些 activation 的结果,也不丢弃其消息。
193
199
  - **驻留仅限进程内**——Activation inbox 与所有权图不会在两个 harness 进程之间协调;对单个持久化存储的并发访问需要持久化邮箱与跨进程租约协议。
194
200
  - **不回放已接受但未记录的消息**——崩溃可能丢失从未写入子会话日志、已被接受的提示词;丢失的消息不会自动回放。
195
201
  - **没有持久化 parent mailbox**——child 到 parent 的消息要求驻留的可继续 child 与在线直接 parent,提供的是接受标识,不保证恰好一次投递。