dsh-plugin-guide 0.3.2 → 0.3.4
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.
- package/README.es.md +5 -1
- package/README.hi.md +5 -1
- package/README.md +5 -1
- package/README.pt.md +5 -1
- package/README.zh.md +5 -1
- package/dist/dsh-plugin-dev.js +3 -3
- package/guide/plugin-dev-guide.md +2 -2
- package/guide/quick-reference.es.md +2 -2
- package/guide/quick-reference.hi.md +1 -1
- package/guide/quick-reference.md +2 -2
- package/guide/quick-reference.pt.md +2 -2
- package/guide/quick-reference.zh-CN.md +2 -2
- package/package.json +3 -3
- package/references/official-docs/AGENTS.md +3 -3
- package/references/official-docs/SNAPSHOT.md +4 -4
- package/references/official-docs/THIRD_PARTY_NOTICES.md +4 -6
- package/references/official-docs/docs/agent-lifecycle.i18n.yaml +2 -2
- package/references/official-docs/docs/agent-lifecycle.md +5 -3
- package/references/official-docs/docs/agent-lifecycle.zh.md +5 -3
- package/references/official-docs/docs/architecture.i18n.yaml +2 -2
- package/references/official-docs/docs/architecture.md +9 -4
- package/references/official-docs/docs/architecture.zh.md +9 -4
- package/references/official-docs/docs/capability-seams.i18n.yaml +2 -2
- package/references/official-docs/docs/capability-seams.md +8 -1
- package/references/official-docs/docs/capability-seams.zh.md +8 -1
- package/references/official-docs/docs/config-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/config-catalog.md +104 -68
- package/references/official-docs/docs/config-catalog.zh.md +101 -65
- package/references/official-docs/docs/cookbook/adding-a-package.i18n.yaml +2 -2
- package/references/official-docs/docs/cookbook/adding-a-package.md +1 -1
- package/references/official-docs/docs/cookbook/adding-a-package.zh.md +1 -1
- package/references/official-docs/docs/cookbook/extension-cookbook.i18n.yaml +2 -2
- package/references/official-docs/docs/cookbook/extension-cookbook.md +12 -10
- package/references/official-docs/docs/cookbook/extension-cookbook.zh.md +12 -10
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.i18n.yaml +2 -2
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.md +16 -12
- package/references/official-docs/docs/deepseek-llm-api-wire-extensions.zh.md +16 -12
- package/references/official-docs/docs/event-producer-consumer.i18n.yaml +2 -2
- package/references/official-docs/docs/event-producer-consumer.md +30 -29
- package/references/official-docs/docs/event-producer-consumer.zh.md +35 -34
- package/references/official-docs/docs/module-graph.i18n.yaml +2 -2
- package/references/official-docs/docs/module-graph.md +214 -360
- package/references/official-docs/docs/module-graph.zh.md +214 -360
- package/references/official-docs/docs/persistence-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/persistence-catalog.md +74 -64
- package/references/official-docs/docs/persistence-catalog.zh.md +72 -62
- package/references/official-docs/docs/subsystems/agent-team.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/agent-team.md +4 -3
- package/references/official-docs/docs/subsystems/agent-team.zh.md +4 -3
- package/references/official-docs/docs/subsystems/attachment.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/attachment.md +157 -4
- package/references/official-docs/docs/subsystems/attachment.zh.md +157 -4
- package/references/official-docs/docs/subsystems/code-runtime.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/code-runtime.md +7 -3
- package/references/official-docs/docs/subsystems/code-runtime.zh.md +7 -3
- package/references/official-docs/docs/subsystems/commands.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/commands.md +25 -16
- package/references/official-docs/docs/subsystems/commands.zh.md +25 -16
- package/references/official-docs/docs/subsystems/compaction.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/compaction.md +9 -9
- package/references/official-docs/docs/subsystems/compaction.zh.md +9 -9
- package/references/official-docs/docs/subsystems/conversation.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/conversation.md +4 -4
- package/references/official-docs/docs/subsystems/conversation.zh.md +4 -4
- package/references/official-docs/docs/subsystems/core.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/core.md +66 -4
- package/references/official-docs/docs/subsystems/core.zh.md +66 -4
- package/references/official-docs/docs/subsystems/feedback.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/feedback.md +2 -2
- package/references/official-docs/docs/subsystems/feedback.zh.md +2 -2
- package/references/official-docs/docs/subsystems/llm-streaming.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/llm-streaming.md +23 -2
- package/references/official-docs/docs/subsystems/llm-streaming.zh.md +23 -2
- package/references/official-docs/docs/subsystems/persistence.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/persistence.md +183 -191
- package/references/official-docs/docs/subsystems/persistence.zh.md +183 -191
- package/references/official-docs/docs/subsystems/schedule.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/schedule.md +1 -1
- package/references/official-docs/docs/subsystems/schedule.zh.md +1 -1
- package/references/official-docs/docs/subsystems/session-projection.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-projection.md +40 -17
- package/references/official-docs/docs/subsystems/session-projection.zh.md +40 -17
- package/references/official-docs/docs/subsystems/session-query.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-query.md +19 -13
- package/references/official-docs/docs/subsystems/session-query.zh.md +19 -13
- package/references/official-docs/docs/subsystems/session-reference.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-reference.md +25 -1
- package/references/official-docs/docs/subsystems/session-reference.zh.md +25 -1
- package/references/official-docs/docs/subsystems/session-telemetry.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-telemetry.md +6 -5
- package/references/official-docs/docs/subsystems/session-telemetry.zh.md +6 -5
- package/references/official-docs/docs/subsystems/session-title.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-title.md +5 -5
- package/references/official-docs/docs/subsystems/session-title.zh.md +5 -5
- package/references/official-docs/docs/subsystems/session.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session.md +143 -71
- package/references/official-docs/docs/subsystems/session.zh.md +143 -71
- package/references/official-docs/docs/subsystems/slots.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/slots.md +1 -0
- package/references/official-docs/docs/subsystems/slots.zh.md +1 -0
- package/references/official-docs/docs/subsystems/storage.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/storage.md +28 -5
- package/references/official-docs/docs/subsystems/storage.zh.md +28 -5
- package/references/official-docs/docs/subsystems/subagent.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/subagent.md +32 -88
- package/references/official-docs/docs/subsystems/subagent.zh.md +31 -87
- package/references/official-docs/docs/subsystems/token-meter.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/token-meter.md +2 -2
- package/references/official-docs/docs/subsystems/token-meter.zh.md +2 -2
- package/references/official-docs/docs/subsystems/web-client.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/web-client.md +1 -1
- package/references/official-docs/docs/subsystems/web-client.zh.md +1 -1
- package/references/official-docs/docs/subsystems/workspace.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/workspace.md +8 -8
- package/references/official-docs/docs/subsystems/workspace.zh.md +8 -8
- package/references/official-docs/docs/testing.i18n.yaml +2 -2
- package/references/official-docs/docs/testing.md +2 -2
- package/references/official-docs/docs/testing.zh.md +2 -2
- package/references/official-docs/docs/tool-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/tool-catalog.md +9 -63
- package/references/official-docs/docs/tool-catalog.zh.md +8 -62
- package/references/official-docs/docs/user/guide/network-proxy.i18n.yaml +6 -0
- package/references/official-docs/docs/user/guide/network-proxy.md +85 -0
- package/references/official-docs/docs/user/guide/network-proxy.zh.md +85 -0
- package/references/official-docs/docs/user/guide/providers.i18n.yaml +2 -2
- package/references/official-docs/docs/user/guide/providers.md +70 -17
- package/references/official-docs/docs/user/guide/providers.zh.md +70 -17
- package/references/official-docs/docs/web-styling.i18n.yaml +2 -2
- package/references/official-docs/docs/web-styling.md +4 -0
- package/references/official-docs/docs/web-styling.zh.md +4 -0
- package/references/official-docs/packages/AGENTS.md +2 -2
- package/references/official-docs/website-docs.ts +8 -0
- package/templates/js/README.es.md +1 -1
- package/templates/js/README.hi.md +1 -1
- package/templates/js/README.md +1 -1
- package/templates/js/README.pt.md +1 -1
- package/templates/js/README.zh.md +1 -1
- package/templates/ts/README.es.md +1 -1
- package/templates/ts/README.hi.md +1 -1
- package/templates/ts/README.md +1 -1
- package/templates/ts/README.pt.md +1 -1
- package/templates/ts/README.zh.md +1 -1
|
@@ -44,7 +44,7 @@ interface StorageBackend {
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
一个后端拥有一个介质(一棵文件树的根目录、一个数据库文件),并提供可选的操作组;`kv` 是唯一已交付的操作组。`KvFacet.open(descriptor)` 打开一个具名 unit——`KvUnitDescriptor`
|
|
47
|
+
一个后端拥有一个介质(一棵文件树的根目录、一个数据库文件),并提供可选的操作组;`kv` 是唯一已交付的操作组。`KvFacet.open(descriptor)` 打开一个具名 unit——`KvUnitDescriptor` 携带名称、当前格式版本、可选的兼容记录版本、表名清单,以及是否存在全局单例 slot——并返回提供 `loadAll`、`putRecord`、`deleteRecord`、`setGlobal` 和 `close` 的 `KvUnit`。unit 名与表名必须匹配 `UNIT_NAME_RE`(既可安全用作文件名,也可安全用作 SQL 标识符片段);记录键是任意字符串,绝不进入文件路径。unit 不对并发写入做串行化——顺序由调用方负责——但每次单独调用在介质上都是原子的,且 resolve 后即已持久。`single` 介质上记录的版本不同时拒绝 `version-mismatch`;`per-record` 文档的版本在接受集合之外时读作不存在。无法按该 unit 解析的介质拒绝 `malformed-medium`。[`backend.ts`](../../packages/storage/storage/src/backend.ts) 是逐条款的规范性约定,[`tests/contract.ts`](../../packages/storage/storage/tests/contract.ts) 中的共享一致性套件会针对每个后端检查每项条款。[json 后端](../../packages/storage/storage-json/README.zh.md)以原子方式为每个 unit 整文件重新发布一份人类可读文件;[sqlite 后端](../../packages/storage/storage-sqlite/README.zh.md)在单个数据库中每行存储一份文档,用于频繁更新的数据。
|
|
48
48
|
|
|
49
49
|
## 声明领域
|
|
50
50
|
|
|
@@ -55,16 +55,36 @@ interface StorageBackend {
|
|
|
55
55
|
interface DomainSpec {
|
|
56
56
|
/** Domain name; must match `UNIT_NAME_RE` (doubles as the backend unit name). */
|
|
57
57
|
readonly name: string
|
|
58
|
-
/**
|
|
58
|
+
/** Current domain format version; reads enforce it according to the selected layout. */
|
|
59
59
|
readonly version: number
|
|
60
60
|
/**
|
|
61
61
|
* Medium layout for the backend unit: `single` (the default) stores the
|
|
62
62
|
* whole unit as one document; `per-record` stores each record as its own
|
|
63
63
|
* document, for units whose records are large, sparse, or individually
|
|
64
|
-
* disposable — the projection cache — and scopes version
|
|
65
|
-
* (
|
|
64
|
+
* disposable — the projection cache — and scopes version checks per record
|
|
65
|
+
* (an unaccepted record document is discarded, never migrated).
|
|
66
66
|
*/
|
|
67
67
|
readonly layout?: 'single' | 'per-record'
|
|
68
|
+
/**
|
|
69
|
+
* Older domain versions whose stored records the current record schemas
|
|
70
|
+
* also accept (the declaring owner vouches for that, typically by
|
|
71
|
+
* declaring the fields older records lack as optional). `per-record` backends
|
|
72
|
+
* read documents stamped with a listed version instead of discarding them,
|
|
73
|
+
* and accept a legacy whole-unit file so stamped for the one-time
|
|
74
|
+
* bootstrap; writes always stamp {@link version}.
|
|
75
|
+
*/
|
|
76
|
+
readonly compatibleVersions?: readonly number[]
|
|
77
|
+
/**
|
|
78
|
+
* What `open` does with a stored table record that fails its zod schema.
|
|
79
|
+
* Absent (the default), the whole open rejects with `invalid-record` —
|
|
80
|
+
* right for authoritative data. `'backup-and-skip'` is for domains whose
|
|
81
|
+
* records are disposable derived data: the backend moves the record's
|
|
82
|
+
* document aside (`KvUnit.backupRecord`), the failure is logged with
|
|
83
|
+
* its cause, and the open continues with the record absent. A backend
|
|
84
|
+
* without `backupRecord` (no per-record document to move) falls back
|
|
85
|
+
* to the rejecting default. The global slot always rejects.
|
|
86
|
+
*/
|
|
87
|
+
readonly invalidRecords?: 'backup-and-skip'
|
|
68
88
|
/** Optional global singleton slot. */
|
|
69
89
|
readonly global?: DomainGlobalSpec<unknown>
|
|
70
90
|
/** Table declarations keyed by table name; each name must match `UNIT_NAME_RE`. */
|
|
@@ -180,7 +200,10 @@ The mounted domain facility. Opens declared domains over routed backends; one fa
|
|
|
180
200
|
* (`facet-unsupported`); open the unit projected from the spec (backend
|
|
181
201
|
* `version-mismatch`/`malformed-medium` pass through); load and validate
|
|
182
202
|
* every stored record against the spec's zod schemas (`invalid-record`
|
|
183
|
-
* with the offending table and key
|
|
203
|
+
* with the offending table and key — unless the spec declares
|
|
204
|
+
* `invalidRecords: 'backup-and-skip'` and the unit can move documents aside, in
|
|
205
|
+
* which case the failing record is backed up, logged, and skipped);
|
|
206
|
+
* construct the domain.
|
|
184
207
|
*
|
|
185
208
|
* Lifecycle: the CALLER owns the returned handle and closes it via
|
|
186
209
|
* `Domain.close()` (typically as its own `ctx.effect` disposer) — the
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write docs/subsystems/subagent.md
|
|
5
|
-
subagent.md:
|
|
6
|
-
subagent.zh.md:
|
|
5
|
+
subagent.md: 1d111706ee93328e47b0cf2ed069a8fd9cdb56ec
|
|
6
|
+
subagent.zh.md: 5b7eca88e9b981c2e582a2af70140f4750914632
|
|
@@ -4,7 +4,7 @@ English | [中文](subagent.zh.md)
|
|
|
4
4
|
|
|
5
5
|
The subagent seam lets an agent delegate work to a child agent. Like [bash](shell.md), it is **one optional capability**, not part of the agent loop, so its types live here rather than in [core.md](core.md). It differs from the other capability seams because **multiple provider implementations coexist** in one context, registered by name (`ctx.subagents`), while bash allows only one executor. Its registry follows the [LLM adapter registry](llm-streaming.md), not the single-service bash executor.
|
|
6
6
|
|
|
7
|
-
Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation)
|
|
7
|
+
Service Definition: [dsh-subagent](../../packages/subagent/subagent) (`ctx.subagents` + the vocabulary below). Service Providers are sibling packages (`dsh-subagent-spawn-in-process`, `dsh-subagent-fork-in-process`, `dsh-subagent-acp`, `dsh-subagent-codex`, `dsh-subagent-claude-code`, `dsh-subagent-dsh-sdk`); the model-facing Consumers are [dsh-tool-subagent](../../packages/subagent/tool-subagent) (per-provider delegation) and [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) (the optional global `send_message`, `interrupt_agent`, and `list_agents` controls). The same `ctx.subagents` service owns continuable-child orchestration through an internal activation manager and read-only child and descendant discovery straight from the session store and optional session persistence. Product-provider rationale lives in [the Codex and Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.md); common-seam rationale lives in [the subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.md), [the continuable subagents Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md), [the adjacent-Agent messaging Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md), [the durable catalog Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.md), [the list-identity-projection Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md), and [the merged-service Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.md).
|
|
8
8
|
|
|
9
9
|
Sources: [`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts), [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts), and [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts)
|
|
10
10
|
|
|
@@ -133,21 +133,21 @@ persisted Session
|
|
|
133
133
|
|
|
134
134
|
`SubagentRuntime.startContinuable()` reserves the stable child id, snapshots the versioned `subagent/descriptor` payload, asks the named provider for its detached `ContinuableCreateSpec`, creates the child Agent through a private activation-owner scope, establishes any continuable-parent ownership, and submits the initial prompt. It resolves with `{ childId, messageId }` when inbox acceptance yields the message id — without waiting for the turn to start or for the message to enter the Session log. Every failure before that acceptance rejects with neither id, disposing any created handle and rolling back the Activation and parent ownership.
|
|
135
135
|
|
|
136
|
-
`SubagentRuntime.
|
|
136
|
+
`SubagentRuntime.sendMessage()` is the sole model-authored message operation. It accepts the exact live sender plus a target id, permits only a direct parent or direct continuable child, derives sender attribution itself, and routes a direct-child target by Activation residency:
|
|
137
137
|
|
|
138
|
-
| Activation state | `
|
|
138
|
+
| Target Activation state | `sendMessage` |
|
|
139
139
|
|---|---|
|
|
140
|
-
| `running` |
|
|
141
|
-
| `waiting` | wake the same Activation |
|
|
142
|
-
| no Activation | cold-resume a new Activation |
|
|
140
|
+
| `running` | steer the nearest step in the same Activation |
|
|
141
|
+
| `waiting` | wake and steer the same Activation |
|
|
142
|
+
| no Activation | cold-resume a new Activation, then steer it |
|
|
143
143
|
|
|
144
144
|
`running` means the Agent has an active admission or turn, or waking inbox work; `waiting` means it is quiescent but still owns at least one child Activation that has not completed disposal; `settled` means quiescent with every owned child disposed, at which point the manager disposes the [`AgentHandle`](core.md#creation-and-ownership) and removes the Activation. The manager derives these internal conditions from Agent quiescence and the owned-child set rather than maintaining a second execution state machine.
|
|
145
145
|
|
|
146
|
-
The Agent inbox is the only queue. Every
|
|
146
|
+
The Agent inbox is the only queue. Every Agent message uses `Agent.steer()`: an idle target starts a turn, while a running target claims it at the nearest step boundary. Successful delivery returns the accepted `MessageId`; the existing `agent/inbox/inserted`, `agent/inbox/claimed`, and `agent/inbox/discarded` events remain the message-lifecycle observations, and the continuation layer defines no subagent-specific delivery route.
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
Authority comes from the exact live sender. Parent-to-child delivery requires the target's `SessionHeader.parentSession` to name the sender; child-to-parent delivery requires the sender's resident Activation to name the target. Siblings, ancestors beyond one edge, self-targets, stale Agent objects, and one-shot children are rejected. Each accepted message is framed as `Agent <sender-id> sent a message:` and records `AgentMessageSource`; provenance records the sender but grants no authority.
|
|
149
149
|
|
|
150
|
-
For
|
|
150
|
+
For `startContinuable()` and `sendMessage()`, the caller signal owns lookup, materialization, and admission only until inbox acceptance. Afterwards the manager owns the Activation independently: later caller cancellation neither cancels the accepted turn nor disposes the child. Human browser prompts remain a separate private Queue adapter and therefore still produce distinct FIFO turns.
|
|
151
151
|
|
|
152
152
|
`SubagentRuntime.interrupt(targetSessionId, authority)` is the one public stop: it authorizes synchronously, issues `Agent.cancel(cause, { keepInbox: true })` on the live target, and returns without awaiting quiescence. The Activation, its unclaimed pending inbox work, and published descendants are untouched; work already claimed into the interrupted turn is not requeued. Once the interrupted driver is idle, a waking send resumes the parked FIFO queue. An absent target — unknown, one-shot, or already settled — and a manager-less composition are accepted no-ops. For a live target, a mismatched parent address or caller outside its live ancestry rejects with `UNAUTHORIZED`; stale ancestor objects and self-targeting ancestor requests reject before target lookup.
|
|
153
153
|
|
|
@@ -167,21 +167,19 @@ Every Activation owns its `AgentHandle` and an `ownedChildren: Set<SessionId>`;
|
|
|
167
167
|
Final settlement awaits `ctx.sessions.flush(session)` but ignores its participation boolean because an arbitrary listener cannot prove that a persistence backend stored the state. Rejection is logged without failing the Activation, and the manager still disposes the handle and releases ownership; the persisted child state may then be missing or stale on a later resume. Manager unload invokes an internal manager-wide drain that closes admission and disposes every live forest; `drainContinuableDescendants(parents)` closes admission only below exact live host-owned Agents and disposes their continuable descendants while unrelated forests remain live. Both await already-admitted materializations in their scope, propagate cancellation top-down, release handles child-first, and await every selected branch despite individual failures. Durable child Sessions survive that process-local teardown.
|
|
168
168
|
|
|
169
169
|
```ts type-equiv
|
|
170
|
-
/**
|
|
171
|
-
interface
|
|
172
|
-
readonly kind: '
|
|
170
|
+
/** Durable attribution for one model-authored message between adjacent Agents. */
|
|
171
|
+
interface AgentMessageSource {
|
|
172
|
+
readonly kind: 'agent-message'
|
|
173
173
|
/** A message another agent addressed to this one (`relay` context form). */
|
|
174
174
|
readonly form: 'relay'
|
|
175
|
-
/** Session id of the
|
|
175
|
+
/** Session id of the Agent whose tool call produced the message. */
|
|
176
176
|
readonly senderSessionId: SessionId
|
|
177
177
|
}
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
```ts type-equiv
|
|
181
|
-
/** Options for
|
|
182
|
-
interface
|
|
183
|
-
/** Durable attribution retained on the delivered message; it grants no authority. */
|
|
184
|
-
readonly source: MessageSource
|
|
181
|
+
/** Options for one model-authored message between adjacent Agents. */
|
|
182
|
+
interface SubagentSendMessageOptions {
|
|
185
183
|
/** Caller cancellation, owning the operation only until inbox acceptance. */
|
|
186
184
|
readonly signal: AbortSignal
|
|
187
185
|
}
|
|
@@ -197,33 +195,13 @@ interface ContinuableStart {
|
|
|
197
195
|
}
|
|
198
196
|
```
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
`SubagentRuntime.reportFrom()` uses that extension point without adding a second queue or a result-bearing child wrapper. The exact live child Agent authorizes the call; callers cannot name a recipient. The manager derives the only recipient from the child's durable `parentSession`, requires that parent Agent to be live, frames the selected content as one `subagent-report` user message, and returns the message's stable `MessageId`. Quiet delivery uses `Agent.inject()` and does not wake the parent; next-step delivery uses `Agent.steer()`, waking an idle parent or joining a running parent's nearest step boundary. Neither mode concludes the child's turn, and no final answer reports implicitly.
|
|
203
|
-
|
|
204
|
-
```ts type-equiv
|
|
205
|
-
/** Durable attribution for a continuable child's explicit parent report. */
|
|
206
|
-
interface SubagentReportMessageSource {
|
|
207
|
-
readonly kind: 'subagent-report'
|
|
208
|
-
/** A message another agent addressed to this one (`relay` context form). */
|
|
209
|
-
readonly form: 'relay'
|
|
210
|
-
/** Session id of the reporting child. */
|
|
211
|
-
readonly senderSessionId: SessionId
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
```ts type-equiv
|
|
216
|
-
/** Deployment scheduling policy for accepted child reports. */
|
|
217
|
-
type SubagentReportDelivery = 'quiet' | 'next-step'
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Reporting is the child's own choice, so the manager keeps a separate account of its own: when a resident Activation settles, it delivers one notice to the child's durable direct parent describing how that epoch ended and carrying its final assistant content. That delivery is unconditional for every child whose id a caller received, happens before the ownership release that would let the parent be judged settled, and reaches a resident parent through the same waking-admission accounting as a report. A parent whose own lineage is already tearing down receives it without a wake, because waking a quiescent Agent starts a turn rather than queueing work. Its provenance is a distinct kind so a transcript never presents a runtime account as something the child wrote.
|
|
198
|
+
When a resident Activation settles, the manager delivers one notice to the child's durable direct parent describing how that epoch ended and carrying its final assistant content. That delivery is unconditional for every child whose id a caller received, happens before the ownership release that would let the parent be judged settled, and reaches a resident parent through the same waking-admission accounting as an Agent message. A parent whose own lineage is already tearing down receives it without a wake, because waking a quiescent Agent starts a turn rather than queueing work. Its provenance is a distinct kind so a transcript never presents a runtime account as something the child wrote.
|
|
221
199
|
|
|
222
200
|
```ts type-equiv
|
|
223
201
|
/**
|
|
224
202
|
* Durable attribution for the runtime's own account of a continuable child
|
|
225
203
|
* settling. Deliberately a different kind from
|
|
226
|
-
* {@link
|
|
204
|
+
* {@link AgentMessageSource}: an Agent message is content the sender chose,
|
|
227
205
|
* while this message is the manager stating what became of the child, and a
|
|
228
206
|
* transcript that merged them would credit the child with words it never wrote.
|
|
229
207
|
*/
|
|
@@ -238,17 +216,7 @@ interface SubagentSettledMessageSource {
|
|
|
238
216
|
}
|
|
239
217
|
```
|
|
240
218
|
|
|
241
|
-
|
|
242
|
-
/** Options for one continuable child's report to its direct parent. */
|
|
243
|
-
interface SubagentReportOptions {
|
|
244
|
-
/** Already-resolved parent scheduling policy. */
|
|
245
|
-
readonly delivery: SubagentReportDelivery
|
|
246
|
-
/** Caller cancellation, owning authorization and admission until acceptance. */
|
|
247
|
-
readonly signal: AbortSignal
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
The provider participates only in preparing the initial creation spec, where `spawn` and `fork` differ. Its returned spec carries only detached provider-specific creation inputs — today the optional parent-history seed — and no Agent, `AgentHandle`, prompt delivery, result, disposal, or resume operation. Cold resume does not dispatch through a provider at all: the manager folds the generic descriptor, calls `ctx.agents.resume()` through the same activation-owner scope, and submits the waiting turn.
|
|
219
|
+
The provider participates only in preparing the initial creation spec, where `spawn` and `fork` differ. Its returned spec carries only detached provider-specific creation inputs — the optional parent-history seed — and no Agent, `AgentHandle`, prompt delivery, result, disposal, or resume operation. Cold resume does not dispatch through a provider at all: the manager folds the generic descriptor, calls `ctx.agents.resume()` through the same activation-owner scope, and submits the waiting turn.
|
|
252
220
|
|
|
253
221
|
```ts type-equiv
|
|
254
222
|
/**
|
|
@@ -290,11 +258,11 @@ interface ContinuableCreateSpec {
|
|
|
290
258
|
|
|
291
259
|
The descriptor (`SubagentDescriptorData` in [descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts)) is a mode-discriminated durable identity for every session-backed subagent. Both modes carry the provider name. A `one-shot` descriptor optionally carries a caller-owned display `label`; a `continuable` descriptor requires the delegation `description` as its durable creation label and additionally snapshots resolved child `agentOptions.provider`/`model`/`reasoningEffort` and optional `persona`/`toolFilter` for cold resume. It never snapshots the merge-extensible `AgentOptions` object, so an unrelated extension value cannot break continuation and a later composition input is a deliberate version change. It omits `subagentDepth` (cold resume trusts the persisted header's `delegationDepth` as the monotone floor) and `outputSchema` (one run or Activation's result contract, not durable identity).
|
|
292
260
|
|
|
293
|
-
A local one-shot provider appends the descriptor inside the child's initial turn before its first request. The continuation manager appends the descriptor after any provider-supplied lineage and before the initial prompt is admitted; `
|
|
261
|
+
A local one-shot provider appends the descriptor inside the child's initial turn before its first request. The continuation manager appends the descriptor after any provider-supplied lineage and before the initial prompt is admitted; `Session.inheritedEventCount` remains the fork-lineage boundary: resume-time descriptor authority reads the child's own suffix, while the list-serving identity projection folds `subagent/descriptor` last-wins so the child's own descriptor overrides a fork-seeded ancestor's. A seeded cold list skips a cache hint until an authoritative observation supplies that exact cut. The event is log-only: no `surfaceOp`, never in model history, and retained across compaction by the append-only log. Malformed current-version descriptors are corrupt; unsupported versions cannot be classified by this runtime.
|
|
294
262
|
|
|
295
263
|
## Durable enumeration: `listChildren()`, `listDescendants()`, and their entries
|
|
296
264
|
|
|
297
|
-
`SubagentRuntime.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from the live-preferred merge of `ctx.sessions
|
|
265
|
+
`SubagentRuntime.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from the live-preferred merge of `ctx.sessions` and the session-query engine's `listSessions()` — no Agent is loaded or resumed. Candidates are the direct children whose durable header carries `origin: 'subagent'`; the marker classifies enumeration and coarse generic-route denial but cannot establish a valid descriptor, resumability, or authorization — the projection fold owns identity, and the Activation contract owns resume. Each row's `mode`/`label` is the registered `subagent` projection unit's value, served through a three-rung ladder: the registry's watermark cache for a live child (zero log reads); the optional projection checkpoint cache for a cold one (`cachedSnapshot` — an identity passing the own-suffix seq gate is final, because an own descriptor is immutable once appended); otherwise one `query.observeSession()` cold observation folded through the registry (bounded concurrency, recomputed per listing). The cache is a pure optional accelerator: absent, serving the `null` sentinel or missing the key, failing the seq gate, or faulting, it falls silently through to the authoritative refold. The fold is `subagent/descriptor` last-wins with no failure channel: the child's own descriptor overrides a fork-seeded ancestor's, and a malformed or unknown-version payload folds to a serializable `null` sentinel, treated as no value. The result is one `SubagentListEntry[]` in `createdAt`-then-id order: a served identity yields a `child` entry with `mode: 'one-shot' | 'continuable'` and `activity: 'running' | 'inactive'`; continuable entries always carry `label`, while one-shot entries carry it only when the start caller supplied presentation metadata. A settled candidate whose fold served no identity yields a `corrupt` diagnostic — missing, malformed, and unknown-version descriptors deliberately undistinguished (`unsupported` remains in the type but is never produced); a running candidate without an identity is omitted (the creation window before its descriptor lands); a failed cold inspection yields one `unavailable` diagnostic retried on the next listing, so one damaged sibling cannot hide healthy children. `hasChildren` marks a direct descendant with durable subagent origin, read from the same merged material. Activity snapshots only whether the logical record is live in `ctx.sessions`, not outcome or resumability. Absent persistence, enumeration is live-only rather than an error — a cold child cannot be resumed then either. `listChildren()` throws `SubagentError` with code `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` when the `ctx.sessionProjections` registry is absent and `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE` when the session store is, both checked before any read so a deployment with zero children still fails deterministically; the list tool requires `ctx.subagents` and `ctx.agents` at plugin load. A service consumer such as a UI can display both modes and choose an unlabeled one-shot fallback, while the model-facing `list_agents` adapter (the separately loadable `/list-agents` plugin of [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)) keeps only continuable entries and refines status through the live Agent registry into its own `running`/`idle`/`ready` vocabulary, whose `ready` names a storage-only child as resumable rather than terminal. Listing does not consult the continuation manager's Activation map, Agent registry, or provider availability; `send_message` remains the authoritative delivery-time operation, and a listed running continuable child may still reject delivery as an ownership conflict. The read-path rationale lives in [the list-identity-projection Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.md).
|
|
298
266
|
|
|
299
267
|
`SubagentRuntime.listDescendants(rootSessionId)` applies the same live-preferred corpus and projection-backed interpretation to the root's complete descendant tree in stable pre-order. Ordinary sessions and one-shot children remain traversal nodes, so continuable descendants below them are discovered; only `origin: 'subagent'` candidates produce rows. Each returned child or diagnostic adds its position from the enumerated durable header, while a cold inspection revalidates that complete lifecycle before serving identity:
|
|
300
268
|
|
|
@@ -532,21 +500,20 @@ Named provider registry with one-shot runs, durable discovery, and continuable-c
|
|
|
532
500
|
async startContinuable(spec: ContinuableStartSpec): Promise<ContinuableStart>
|
|
533
501
|
|
|
534
502
|
/**
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
* @param
|
|
541
|
-
* @param
|
|
542
|
-
* @param content -
|
|
543
|
-
* @param options -
|
|
544
|
-
* operation only before inbox acceptance.
|
|
503
|
+
* Steer one model-authored message to the sender's direct parent or direct
|
|
504
|
+
* continuable child. A running target admits it at the nearest step boundary;
|
|
505
|
+
* an idle target starts a turn, and an absent direct child cold-resumes from
|
|
506
|
+
* persistence. The service derives durable sender attribution from the exact
|
|
507
|
+
* live sender. Caller cancellation stops only pre-acceptance work.
|
|
508
|
+
* @param sender - exact live Agent authorizing and originating the message.
|
|
509
|
+
* @param targetId - durable direct-parent or direct-child session id.
|
|
510
|
+
* @param content - model-authored content to deliver.
|
|
511
|
+
* @param options - caller cancellation before inbox acceptance.
|
|
545
512
|
* @returns the accepted message's inbox id.
|
|
546
|
-
* @throws when continuation services are unavailable,
|
|
547
|
-
*
|
|
513
|
+
* @throws when continuation services are unavailable, adjacency is rejected,
|
|
514
|
+
* or the message was not admitted.
|
|
548
515
|
*/
|
|
549
|
-
async
|
|
516
|
+
async sendMessage( sender: Agent, targetId: SessionId, content: ContentBlock[], options: SubagentSendMessageOptions, ): Promise<MessageId>
|
|
550
517
|
|
|
551
518
|
/**
|
|
552
519
|
* Interrupt one live continuable child's current turn under a human parent
|
|
@@ -565,29 +532,6 @@ async followup( parent: Agent, childId: SessionId, content: ContentBlock[], opti
|
|
|
565
532
|
*/
|
|
566
533
|
interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void
|
|
567
534
|
|
|
568
|
-
/**
|
|
569
|
-
* Deliver selected content from one live continuable child to its durable
|
|
570
|
-
* direct parent. The child is the authority credential; callers cannot name a
|
|
571
|
-
* recipient. Reporting does not conclude the child's turn or Activation.
|
|
572
|
-
* @param child - exact live reporting child.
|
|
573
|
-
* @param content - selected model-facing content.
|
|
574
|
-
* @param options - parent scheduling and pre-acceptance cancellation.
|
|
575
|
-
* @returns the stable identity of the parent-accepted message.
|
|
576
|
-
* @throws when continuation services are unavailable, sender authorization
|
|
577
|
-
* fails, or the direct parent is not live.
|
|
578
|
-
*/
|
|
579
|
-
async reportFrom( child: Agent, content: ContentBlock[], options: SubagentReportOptions, ): Promise<MessageId>
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* Compose one deployment capability into every continuable child's
|
|
583
|
-
* unpublished creation context on fresh creation and cold resume. Grants wait
|
|
584
|
-
* for the next Activation; removing the contribution revokes every resident
|
|
585
|
-
* installation immediately.
|
|
586
|
-
* @param contribution - synchronous child-scope installer.
|
|
587
|
-
* @returns the exact Cordis effect disposer.
|
|
588
|
-
*/
|
|
589
|
-
registerContinuableSetup(contribution: ContinuableSetupContribution): () => void
|
|
590
|
-
|
|
591
535
|
/**
|
|
592
536
|
* Close continuable admission below exact live parent Agents, stop only their
|
|
593
537
|
* visible descendant Activations synchronously, then await admitted scoped
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
subagent seam 让一个 agent(智能体)将工作委派给子 agent。与 [bash](shell.zh.md) 一样,它是**一项可选能力**,不属于 agent loop(智能体循环),因此其类型定义在此而非 [core.md](core.zh.md) 中。它不同于其他能力 seam,因为**同一上下文中可共存多个提供方实现**,并按名称注册(`ctx.subagents`),而 bash 只允许一个执行器。该注册表遵循 [LLM(大语言模型)适配器注册表](llm-streaming.zh.md),而非单服务的 bash 执行器。
|
|
6
6
|
|
|
7
|
-
Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service Provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`dsh-subagent-fork-in-process`、`dsh-subagent-acp`、`dsh-subagent-codex`、`dsh-subagent-claude-code`、`dsh-subagent-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)
|
|
7
|
+
Service Definition:[dsh-subagent](../../packages/subagent/subagent)(`ctx.subagents` + 下文词汇)。Service Provider 是六个兄弟包:`dsh-subagent-spawn-in-process`、`dsh-subagent-fork-in-process`、`dsh-subagent-acp`、`dsh-subagent-codex`、`dsh-subagent-claude-code`、`dsh-subagent-dsh-sdk`;面向模型的 Consumer 包括 [dsh-tool-subagent](../../packages/subagent/tool-subagent)(按提供方委派)和 [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)(可选的全局 `send_message`、`interrupt_agent` 与 `list_agents` 控制工具)。同一个 `ctx.subagents` 服务通过内部激活管理器负责可继续子 agent 编排,并直接基于会话存储和可选的会话持久化提供只读的 child 与后代发现。产品提供方设计理由见 [Codex 与 Claude Code Agent Note](../../.agents/notes/implemented/feature/2026-08-04-claude-code-and-codex-subagent-backends.zh.md);通用 seam 的设计理由见 [subagent Agent Note](../../.agents/notes/implemented/feature/2026-06-21-subagent-capability-seam.zh.md)、[可继续 subagent Agent Note](../../.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.zh.md)、[相邻 Agent 消息 Agent Note](../../.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md)、[持久化目录 Agent Note](../../.agents/notes/implemented/feature/2026-07-22-durable-subagent-catalog-and-list-agents.zh.md)、[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.zh.md)和[服务合并 Agent Note](../../.agents/notes/implemented/simplification/2026-07-26-merge-subagent-control-service.zh.md)。
|
|
8
8
|
|
|
9
9
|
源码:[`packages/subagent/subagent/src/types.ts`](../../packages/subagent/subagent/src/types.ts)、[`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts)和 [`packages/subagent/subagent/src/continuation.ts`](../../packages/subagent/subagent/src/continuation.ts)
|
|
10
10
|
|
|
@@ -133,21 +133,21 @@ persisted Session
|
|
|
133
133
|
|
|
134
134
|
`SubagentRuntime.startContinuable()` 会预留稳定的子 agent id,对版本化的 `subagent/descriptor` payload 建立快照,向指定提供方索取其分离的 `ContinuableCreateSpec`,通过私有的 activation-owner 作用域创建子 Agent,建立任何可继续父级的所有权,并提交初始提示词。当收件箱(inbox)准入产出消息 id 时,它以 `{ childId, messageId }` resolve——无需等待轮次开始,也无需等待消息进入会话日志。在该准入之前的任何失败都会以两个 id 都不返回的方式 reject,并 dispose(资源释放)任何已创建的 handle,回滚 Activation 与父级所有权。
|
|
135
135
|
|
|
136
|
-
`SubagentRuntime.
|
|
136
|
+
`SubagentRuntime.sendMessage()` 是唯一由模型编写消息的操作。它接收确切在线 sender 与目标 id,只允许直接 parent 或直接可继续 child,自行推导 sender 来源信息,并根据目标 child 的 Activation 驻留状态路由:
|
|
137
137
|
|
|
138
|
-
| Activation 状态 | `
|
|
138
|
+
| 目标 Activation 状态 | `sendMessage` |
|
|
139
139
|
|---|---|
|
|
140
|
-
| `running` | 在同一 Activation
|
|
141
|
-
| `waiting` |
|
|
142
|
-
| 无 Activation |
|
|
140
|
+
| `running` | 在同一 Activation 中 steer 最近的 step |
|
|
141
|
+
| `waiting` | 唤醒并 steer 同一 Activation |
|
|
142
|
+
| 无 Activation | 冷恢复新的 Activation,然后 steer |
|
|
143
143
|
|
|
144
144
|
`running` 表示 Agent 拥有活跃的准入或轮次,或正在唤醒收件箱工作;`waiting` 表示它已完全停稳,但仍拥有至少一个尚未完成 dispose 的子 Activation;`settled` 表示已完全停稳且其拥有的每个子级都已 dispose,此时管理器会 dispose [`AgentHandle`](core.zh.md#creation-and-ownership) 并移除该 Activation。管理器根据 Agent 的完全停稳状态与其拥有的子级集合推导这些内部条件,而非维护第二套执行状态机。
|
|
145
145
|
|
|
146
|
-
Agent
|
|
146
|
+
Agent 收件箱是唯一队列。每条 Agent 消息都使用 `Agent.steer()`:空闲目标会启动一个轮次,运行中目标则在最近的 step 边界领取消息。投递成功会返回被接受的 `MessageId`;既有的 `agent/inbox/inserted`、`agent/inbox/claimed` 与 `agent/inbox/discarded` 事件仍是消息生命周期的观测点,继续执行层不定义任何 subagent 专属的投递路由。
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
权限来自确切在线 sender。parent 到 child 的投递要求目标的 `SessionHeader.parentSession` 指向 sender;child 到 parent 的投递要求 sender 的驻留 Activation 指向目标。sibling、相隔多于一条边的 ancestor、self-target、陈旧 Agent 对象与一次性 child 都会被拒绝。每条已接受消息都以 `Agent <sender-id> sent a message:` 作为前缀,并记录 `AgentMessageSource`;来源信息记录 sender,但不授予权限。
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
对于 `startContinuable()` 与 `sendMessage()`,调用方 signal 仅在收件箱接受之前掌管查找、物化与准入。此后管理器独立掌管该 Activation:之后的调用方取消既不会取消已接受的轮次,也不会 dispose 子 agent。浏览器中的人类提示仍由私有 Queue 适配器处理,因此继续产生独立 FIFO 轮次。
|
|
151
151
|
|
|
152
152
|
`SubagentRuntime.interrupt(targetSessionId, authority)` 是唯一的公开停止操作:它同步完成鉴权,对在线目标发出 `Agent.cancel(cause, { keepInbox: true })`,然后不等待完全停稳即返回。Activation、其尚未领取的待处理 inbox 工作与已发布的后代均不受影响;已被领取进入中断轮次的工作不会重新入队。被中断的 driver 进入 idle 后,一次唤醒发送会恢复被暂停的 FIFO 队列。不存在的目标——未知、一次性或已结算——以及未绑定管理器的组合是被接受的 no-op。对在线目标,错误的 parent 地址或不在其在线祖先链中的调用方会以 `UNAUTHORIZED` 拒绝;陈旧的 ancestor 对象和指向自身的 ancestor 请求会在查找目标前拒绝。
|
|
153
153
|
|
|
@@ -167,21 +167,19 @@ type SubagentInterruptAuthority =
|
|
|
167
167
|
最终结算会等待 `ctx.sessions.flush(session)`,但会忽略其参与布尔值,因为任意 listener 都无法证明某个持久化后端已存储该状态。rejection 会被记录,但不会使 Activation 失败;管理器仍会 dispose 该 handle 并释放所有权,此后持久化的子 agent 状态在后续恢复时可能缺失或陈旧。管理器卸载会调用内部的管理器全局 drain,关闭准入并 dispose 每片在线森林;`drainContinuableDescendants(parents)` 只关闭由 host 确切拥有的在线 Agent 之下的准入,并 dispose 其可继续后代,而无关森林保持在线。两者都会等待各自作用域内已获准的物化过程,自顶向下传播取消,按 child-first 顺序释放 handle,并且即使个别分支失败也会等待所有选中分支。持久化子会话不受该进程内拆卸的影响。
|
|
168
168
|
|
|
169
169
|
```ts type-equiv
|
|
170
|
-
/**
|
|
171
|
-
interface
|
|
172
|
-
readonly kind: '
|
|
170
|
+
/** Durable attribution for one model-authored message between adjacent Agents. */
|
|
171
|
+
interface AgentMessageSource {
|
|
172
|
+
readonly kind: 'agent-message'
|
|
173
173
|
/** A message another agent addressed to this one (`relay` context form). */
|
|
174
174
|
readonly form: 'relay'
|
|
175
|
-
/** Session id of the
|
|
175
|
+
/** Session id of the Agent whose tool call produced the message. */
|
|
176
176
|
readonly senderSessionId: SessionId
|
|
177
177
|
}
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
```ts type-equiv
|
|
181
|
-
/** Options for
|
|
182
|
-
interface
|
|
183
|
-
/** Durable attribution retained on the delivered message; it grants no authority. */
|
|
184
|
-
readonly source: MessageSource
|
|
181
|
+
/** Options for one model-authored message between adjacent Agents. */
|
|
182
|
+
interface SubagentSendMessageOptions {
|
|
185
183
|
/** Caller cancellation, owning the operation only until inbox acceptance. */
|
|
186
184
|
readonly signal: AbortSignal
|
|
187
185
|
}
|
|
@@ -197,33 +195,13 @@ interface ContinuableStart {
|
|
|
197
195
|
}
|
|
198
196
|
```
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
`SubagentRuntime.reportFrom()` 通过该扩展点实现报告,无需新增第二条队列或承载结果的 child 包装层。调用由确切的在线 child Agent 授权,调用方不能指定接收方。管理器从 child 的持久化 `parentSession` 中推导唯一接收方,要求该 parent Agent 必须在线,将选中内容封装为一条 `subagent-report` 用户消息,并返回该消息的稳定 `MessageId`。静默投递使用 `Agent.inject()`,不会唤醒 parent;next-step 投递使用 `Agent.steer()`,会唤醒空闲 parent,或加入运行中 parent 最近的 step 边界。两种模式都不会结束 child 轮次,最终回答也不会隐式报告。
|
|
203
|
-
|
|
204
|
-
```ts type-equiv
|
|
205
|
-
/** Durable attribution for a continuable child's explicit parent report. */
|
|
206
|
-
interface SubagentReportMessageSource {
|
|
207
|
-
readonly kind: 'subagent-report'
|
|
208
|
-
/** A message another agent addressed to this one (`relay` context form). */
|
|
209
|
-
readonly form: 'relay'
|
|
210
|
-
/** Session id of the reporting child. */
|
|
211
|
-
readonly senderSessionId: SessionId
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
```ts type-equiv
|
|
216
|
-
/** Deployment scheduling policy for accepted child reports. */
|
|
217
|
-
type SubagentReportDelivery = 'quiet' | 'next-step'
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
上报是 child 自己的选择,因此管理器还保有一份属于自己的记账:当驻留 Activation 结算时,它会向该 child 持久化的直接 parent 投递一条通知,说明该 epoch 如何结束,并携带其最终 assistant 内容。对每个调用方拿到过 id 的 child,这条投递都是无条件的;它发生在会让 parent 被判定为已结算的所有权释放之前,并通过与上报相同的唤醒准入记账到达驻留 parent。若 parent 自身所在的谱系已在拆卸中,这条通知会以不唤醒的方式送达,因为唤醒一个静息 Agent 是开启一个轮次,而不是排队等待工作。其来源信息使用一个独立的 kind,因此 transcript(文本记录)绝不会把运行时的记账呈现为 child 自己写下的内容。
|
|
198
|
+
当驻留 Activation 结算时,管理器会向该 child 持久化的直接 parent 投递一条通知,说明该 epoch 如何结束,并携带其最终 assistant 内容。对每个调用方拿到过 id 的 child,这条投递都是无条件的;它发生在会让 parent 被判定为已结算的所有权释放之前,并通过与 Agent 消息相同的唤醒准入记账到达驻留 parent。若 parent 自身所在的谱系已在拆卸中,这条通知会以不唤醒的方式送达,因为唤醒一个静息 Agent 是开启一个轮次,而不是排队等待工作。其来源信息使用一个独立的 kind,因此 transcript(文本记录)绝不会把运行时的记账呈现为 child 自己写下的内容。
|
|
221
199
|
|
|
222
200
|
```ts type-equiv
|
|
223
201
|
/**
|
|
224
202
|
* Durable attribution for the runtime's own account of a continuable child
|
|
225
203
|
* settling. Deliberately a different kind from
|
|
226
|
-
* {@link
|
|
204
|
+
* {@link AgentMessageSource}: an Agent message is content the sender chose,
|
|
227
205
|
* while this message is the manager stating what became of the child, and a
|
|
228
206
|
* transcript that merged them would credit the child with words it never wrote.
|
|
229
207
|
*/
|
|
@@ -238,16 +216,6 @@ interface SubagentSettledMessageSource {
|
|
|
238
216
|
}
|
|
239
217
|
```
|
|
240
218
|
|
|
241
|
-
```ts type-equiv
|
|
242
|
-
/** Options for one continuable child's report to its direct parent. */
|
|
243
|
-
interface SubagentReportOptions {
|
|
244
|
-
/** Already-resolved parent scheduling policy. */
|
|
245
|
-
readonly delivery: SubagentReportDelivery
|
|
246
|
-
/** Caller cancellation, owning authorization and admission until acceptance. */
|
|
247
|
-
readonly signal: AbortSignal
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
219
|
提供方只参与准备初始创建 spec,`spawn` 与 `fork` 在此有所不同。其返回的 spec 只携带分离的、提供方专属的创建输入——即可选的父级历史种子——不含 Agent、`AgentHandle`、提示词投递、结果、dispose 或恢复操作。冷恢复根本不经由提供方分发:管理器折叠通用描述符,通过同一个 activation-owner 作用域调用 `ctx.agents.resume()`,并提交等待中的轮次。
|
|
252
220
|
|
|
253
221
|
```ts type-equiv
|
|
@@ -290,11 +258,11 @@ interface ContinuableCreateSpec {
|
|
|
290
258
|
|
|
291
259
|
描述符([descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts) 中的 `SubagentDescriptorData`)是每个由会话支撑的 subagent 所使用、按模式判别的持久化身份。两种模式都携带提供方名称。`one-shot` 描述符可以携带调用方拥有的可选显示 `label`;`continuable` 描述符要求以委派 `description` 作为持久化创建标签,并另外对已解析的子 agent `agentOptions.provider`/`model`/`reasoningEffort` 与可选的 `persona`/`toolFilter` 建立快照,用于冷恢复。它绝不会对可合并扩展的 `AgentOptions` 对象建立快照,因此无关的扩展值不会破坏继续执行,后续新增组合配置输入则是一次有意的版本更改。描述符省略 `subagentDepth`(冷恢复以持久化 header 中的 `delegationDepth` 作为单调下界)和 `outputSchema`(单次运行或 Activation 的结果约定,而非持久化身份)。
|
|
292
260
|
|
|
293
|
-
本地一次性提供方会在子 agent 的初始轮次内、首次请求前追加描述符。继续执行管理器会在任何提供方提供的谱系之后、初始提示词获准之前追加描述符;`
|
|
261
|
+
本地一次性提供方会在子 agent 的初始轮次内、首次请求前追加描述符。继续执行管理器会在任何提供方提供的谱系之后、初始提示词获准之前追加描述符;`Session.inheritedEventCount` 仍是 fork 谱系边界:恢复时的描述符权威读取子 agent 自身的后缀,而供列表使用的身份投影以 last-wins 折叠 `subagent/descriptor`,子 agent 自己的描述符会覆盖 fork seed 中祖先的描述符。seeded cold list 会跳过 cache hint,直到权威 observation 提供该精确 cut。该事件只进入日志:不含 `surfaceOp`,绝不进入模型历史,并由仅追加日志跨压缩保留。格式错误的当前版本描述符属于损坏;本运行时无法对不受支持的版本进行分类。
|
|
294
262
|
|
|
295
263
|
## 持久化枚举:`listChildren()`、`listDescendants()` 与其条目
|
|
296
264
|
|
|
297
|
-
`SubagentRuntime.listChildren(parentSessionId)` 从 `ctx.sessions
|
|
265
|
+
`SubagentRuntime.listChildren(parentSessionId)` 从 `ctx.sessions` 与会话查询引擎 `listSessions()` 的实时优先合并中枚举 parent 直接且由会话支撑的 subagent——不会加载或恢复任何 Agent。候选是持久 header 携带 `origin: 'subagent'` 的直接 child;该标记只负责枚举分类与粗粒度的通用路由拒绝,不能证明描述符有效、child 可恢复或操作已获授权——身份由投影折叠负责,恢复由 Activation 约定负责。每行的 `mode`/`label` 是已注册 `subagent` projection unit 的值,经三级阶梯供值:存活 child 由注册表水位缓存供值(零日志读取);冷 child 先读可选的投影 checkpoint 缓存(`cachedSnapshot`——过 own-suffix seq 门的身份即定值,own descriptor 一经追加不可变);否则在一次 `query.observeSession()` 冷观察上经注册表折叠(有界并发,每次列表重新计算)。该缓存是纯可选加速层:服务缺席、行里是 `null` 哨兵或 key 缺席、seq 门不过、读取出错,都静默落到权威重折。折叠规则是 `subagent/descriptor` last-wins 且没有失败通道:子 agent 自己的描述符覆盖 fork seed 中祖先的描述符,格式错误或版本不认识的载荷折叠为可序列化的 `null` 哨兵,视同无值。结果是按 `createdAt`、再按 id 排序的 `SubagentListEntry[]`:取到身份即生成带有 `mode: 'one-shot' | 'continuable'` 和 `activity: 'running' | 'inactive'` 的 `child` 条目;可继续条目始终携带 `label`,一次性条目则只在启动调用方提供展示元数据时携带该字段。已定局而折叠无身份的候选生成 `corrupt` diagnostic——缺失、格式错误与版本不认识的描述符有意不再细分(`unsupported` 仍保留在类型中但从不产出);运行中而无身份的候选被省略(描述符落盘前的创建窗口);冷检查失败生成一条 `unavailable` diagnostic 并在下次列表自然重试,因此一个损坏的 sibling 不会隐藏健康 child。`hasChildren` 标记存在持久 subagent origin 的直接后代,读取自同一份合并材料。活动状态只表示逻辑记录是否在 `ctx.sessions` 中存活,而不表示结果或可恢复性。缺少持久化时,枚举退化为仅存活枚举而不是报错——此时冷 child 本就无法恢复。缺少 `ctx.sessionProjections` 注册表时,`listChildren()` 抛出携带错误码 `SUBAGENT_CONTROL_PROJECTIONS_UNAVAILABLE` 的 `SubagentError`,缺少会话存储时则抛出 `SUBAGENT_CONTROL_SESSION_STORE_UNAVAILABLE`,两者都在任何读取之前检查,因此零 child 的部署同样确定失败;列表工具在插件加载时要求 `ctx.subagents` 与 `ctx.agents`。UI 等服务消费方可以展示两种模式,并为无标签的一次性 child 选择回退展示;面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)则只保留可继续条目,并通过在线 Agent 注册表将状态细化为自己的 `running`/`idle`/`ready` 词汇,其中 `ready` 把仅存于存储的 child 命名为可恢复而非终态。枚举不会查询继续执行管理器的 Activation map、Agent 注册表或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的运行中可继续 child 仍可能因所有权冲突而拒绝投递。读路径的设计理由见[列表身份投影 Agent Note](../../.agents/notes/implemented/architecture/2026-08-06-subagent-list-identity-projection.zh.md)。
|
|
298
266
|
|
|
299
267
|
`SubagentRuntime.listDescendants(rootSessionId)` 将同一份实时优先语料与基于投影的解释应用到根的完整后代树,并按稳定 pre-order 输出。普通会话和一次性 child 仍作为遍历节点,因此其下的可继续后代仍可发现;只有 `origin: 'subagent'` 的候选会生成条目。每个返回的 child 或 diagnostic 都从枚举所得的持久 header 附加树位置;冷检查在提供身份前还会重新校验完整生命周期:
|
|
300
268
|
|
|
@@ -536,21 +504,20 @@ Named provider registry with one-shot runs, durable discovery, and continuable-c
|
|
|
536
504
|
async startContinuable(spec: ContinuableStartSpec): Promise<ContinuableStart>
|
|
537
505
|
|
|
538
506
|
/**
|
|
539
|
-
*
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* @param
|
|
545
|
-
* @param
|
|
546
|
-
* @param content -
|
|
547
|
-
* @param options -
|
|
548
|
-
* operation only before inbox acceptance.
|
|
507
|
+
* Steer one model-authored message to the sender's direct parent or direct
|
|
508
|
+
* continuable child. A running target admits it at the nearest step boundary;
|
|
509
|
+
* an idle target starts a turn, and an absent direct child cold-resumes from
|
|
510
|
+
* persistence. The service derives durable sender attribution from the exact
|
|
511
|
+
* live sender. Caller cancellation stops only pre-acceptance work.
|
|
512
|
+
* @param sender - exact live Agent authorizing and originating the message.
|
|
513
|
+
* @param targetId - durable direct-parent or direct-child session id.
|
|
514
|
+
* @param content - model-authored content to deliver.
|
|
515
|
+
* @param options - caller cancellation before inbox acceptance.
|
|
549
516
|
* @returns the accepted message's inbox id.
|
|
550
|
-
* @throws when continuation services are unavailable,
|
|
551
|
-
*
|
|
517
|
+
* @throws when continuation services are unavailable, adjacency is rejected,
|
|
518
|
+
* or the message was not admitted.
|
|
552
519
|
*/
|
|
553
|
-
async
|
|
520
|
+
async sendMessage( sender: Agent, targetId: SessionId, content: ContentBlock[], options: SubagentSendMessageOptions, ): Promise<MessageId>
|
|
554
521
|
|
|
555
522
|
/**
|
|
556
523
|
* Interrupt one live continuable child's current turn under a human parent
|
|
@@ -569,29 +536,6 @@ async followup( parent: Agent, childId: SessionId, content: ContentBlock[], opti
|
|
|
569
536
|
*/
|
|
570
537
|
interrupt(targetSessionId: SessionId, authority: SubagentInterruptAuthority): void
|
|
571
538
|
|
|
572
|
-
/**
|
|
573
|
-
* Deliver selected content from one live continuable child to its durable
|
|
574
|
-
* direct parent. The child is the authority credential; callers cannot name a
|
|
575
|
-
* recipient. Reporting does not conclude the child's turn or Activation.
|
|
576
|
-
* @param child - exact live reporting child.
|
|
577
|
-
* @param content - selected model-facing content.
|
|
578
|
-
* @param options - parent scheduling and pre-acceptance cancellation.
|
|
579
|
-
* @returns the stable identity of the parent-accepted message.
|
|
580
|
-
* @throws when continuation services are unavailable, sender authorization
|
|
581
|
-
* fails, or the direct parent is not live.
|
|
582
|
-
*/
|
|
583
|
-
async reportFrom( child: Agent, content: ContentBlock[], options: SubagentReportOptions, ): Promise<MessageId>
|
|
584
|
-
|
|
585
|
-
/**
|
|
586
|
-
* Compose one deployment capability into every continuable child's
|
|
587
|
-
* unpublished creation context on fresh creation and cold resume. Grants wait
|
|
588
|
-
* for the next Activation; removing the contribution revokes every resident
|
|
589
|
-
* installation immediately.
|
|
590
|
-
* @param contribution - synchronous child-scope installer.
|
|
591
|
-
* @returns the exact Cordis effect disposer.
|
|
592
|
-
*/
|
|
593
|
-
registerContinuableSetup(contribution: ContinuableSetupContribution): () => void
|
|
594
|
-
|
|
595
539
|
/**
|
|
596
540
|
* Close continuable admission below exact live parent Agents, stop only their
|
|
597
541
|
* visible descendant Activations synchronously, then await admitted scoped
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write docs/subsystems/token-meter.md
|
|
5
|
-
token-meter.md:
|
|
6
|
-
token-meter.zh.md:
|
|
5
|
+
token-meter.md: 2265f5073efbd2953e4f399ad58a026772b60006
|
|
6
|
+
token-meter.zh.md: b1d9d66dc804fecace15489e61c1d080c096932d
|
|
@@ -12,7 +12,7 @@ Source: [`packages/llm/token-meter/src/types.ts`](../../packages/llm/token-meter
|
|
|
12
12
|
/** Detached immutable request-pressure and surface snapshot at one consumed log revision. */
|
|
13
13
|
interface TokenMeasurement {
|
|
14
14
|
/** Number of durable events consumed; equal to the next unread event seq. */
|
|
15
|
-
readonly logRevision:
|
|
15
|
+
readonly logRevision: SessionLogOffset
|
|
16
16
|
/** Provider or heuristic anchor used for this measurement. */
|
|
17
17
|
readonly baseline: TokenMeasurementBaseline
|
|
18
18
|
/** Signed repricing of current surface content relative to the baseline anchor. */
|
|
@@ -34,7 +34,7 @@ Every measurement resolves the effective envelope's routed provider/model to tha
|
|
|
34
34
|
/** One token-priced node in the current ordered session surface. */
|
|
35
35
|
interface TokenSurfaceNode {
|
|
36
36
|
/** Durable sequence number of the surface event. */
|
|
37
|
-
readonly seq:
|
|
37
|
+
readonly seq: SessionSeq
|
|
38
38
|
/**
|
|
39
39
|
* Request-pressure tokens for the exact message projected by this node under
|
|
40
40
|
* the measured route: image occurrences carry the route's declared visual
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** Detached immutable request-pressure and surface snapshot at one consumed log revision. */
|
|
13
13
|
interface TokenMeasurement {
|
|
14
14
|
/** Number of durable events consumed; equal to the next unread event seq. */
|
|
15
|
-
readonly logRevision:
|
|
15
|
+
readonly logRevision: SessionLogOffset
|
|
16
16
|
/** Provider or heuristic anchor used for this measurement. */
|
|
17
17
|
readonly baseline: TokenMeasurementBaseline
|
|
18
18
|
/** Signed repricing of current surface content relative to the baseline anchor. */
|
|
@@ -34,7 +34,7 @@ interface TokenMeasurement {
|
|
|
34
34
|
/** One token-priced node in the current ordered session surface. */
|
|
35
35
|
interface TokenSurfaceNode {
|
|
36
36
|
/** Durable sequence number of the surface event. */
|
|
37
|
-
readonly seq:
|
|
37
|
+
readonly seq: SessionSeq
|
|
38
38
|
/**
|
|
39
39
|
* Request-pressure tokens for the exact message projected by this node under
|
|
40
40
|
* the measured route: image occurrences carry the route's declared visual
|