feat(subagent): catalog one-shot child sessions

This commit is contained in:
Dudu-0223
2026-07-27 16:58:37 +08:00
committed by Tianyi Cui
parent de6e572e51
commit 774ee34b9a
85 changed files with 1034 additions and 539 deletions

View File

@@ -1517,7 +1517,7 @@ export interface Config {
export type PermissionPolicy = 'allow' | 'reject'
```
Source: [`packages/subagent/subagent-acp/src/index.ts:21`](../packages/subagent/subagent-acp/src/index.ts)
Source: [`packages/subagent/subagent-acp/src/index.ts:26`](../packages/subagent/subagent-acp/src/index.ts)
## `@deepseek-ai/dsh-subagent-dsh-sdk`

View File

@@ -794,7 +794,7 @@ A ready child settled. Scope-filtered dispatch uses the same delegating parent c
Types: [Scoped](../core-data-structures/scope.md) · [SubagentService](../core-data-structures/subagent.md)
Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:151`](../../packages/subagent/subagent/src/index.ts)
### `subagent/provider-added` — emit
@@ -811,7 +811,7 @@ A provider became resolvable in the registry.
Types: [SubagentProvider](../core-data-structures/subagent.md)
Source: [`packages/subagent/subagent/src/index.ts:116`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:125`](../../packages/subagent/subagent/src/index.ts)
### `subagent/provider-removed` — emit
@@ -826,7 +826,7 @@ A provider left the registry. Accepted runs remain holder-owned.
'subagent/provider-removed'(name: string): void
```
Source: [`packages/subagent/subagent/src/index.ts:122`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:131`](../../packages/subagent/subagent/src/index.ts)
### `subagent/start` — emit
@@ -848,7 +848,7 @@ A provider established a ready child. For in-process providers, `ctx.agents.get(
Types: [Scoped](../core-data-structures/scope.md) · [SubagentService](../core-data-structures/subagent.md)
Source: [`packages/subagent/subagent/src/index.ts:133`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts)
## `system-prompt/*`

View File

@@ -1993,11 +1993,11 @@ async followup( parent: Agent, childId: SessionId, content: ContentBlock[], opti
async drainContinuableDescendants(parents: readonly Agent[]): Promise<void>
/**
* Enumerate the parent's direct continuable children from the live-preferred
* session corpus without loading or resuming an Agent. Session query supplies
* lineage, candidate order, event reads, and live state; this service
* interprets descriptors, status, and per-child diagnostics without consulting
* Agent registrations, Activations, or providers.
* Enumerate the parent's direct session-backed subagents from the
* live-preferred session corpus without loading or resuming an Agent. Session
* query supplies lineage, candidate order, event reads, and live state; this
* service interprets descriptor mode, activity, and per-child diagnostics
* without consulting Agent registrations, Activations, or providers.
*
* The trace and exact descriptor read receive `signal`; the full event-list
* read has no signal parameter, so the scan rechecks cancellation around
@@ -2040,7 +2040,7 @@ list(): string[]
* fulfills; a rejection therefore has no run for the caller to dispose and
* emits no run lifecycle events.
* @param name - the provider to use.
* @param request - child prompt, parent, signal, and optional capabilities.
* @param request - child label, prompt, parent, signal, and optional capabilities.
* @returns the ready holder-owned run.
*/
async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
@@ -2048,7 +2048,7 @@ async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [ContinuableStart](../core-data-structures/subagent.md) · [ContinuableStartSpec](../core-data-structures/subagent.md) · [MessageId](../core-data-structures/core.md) · [SessionId](../core-data-structures/core.md) · [SubagentFollowupOptions](../core-data-structures/subagent.md) · [SubagentListEntry](../core-data-structures/subagent.md) · [SubagentProvider](../core-data-structures/subagent.md) · [SubagentRun](../core-data-structures/subagent.md) · [SubagentStartRequest](../core-data-structures/subagent.md)
Source: [`packages/subagent/subagent/src/index.ts:147`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:156`](../../packages/subagent/subagent/src/index.ts)
## `ctx.subprocess` — `SubprocessService` (abstract seam)

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/core-data-structures/subagent.md
subagent.md: ae0d84af09e65bf284780722bab02282fd6c3f37
subagent.zh.md: 9d2ba038885110a52cc3c7153cc908b05ea8b15f
subagent.md: 7af4e119fa07d360f03242b2db85c60a5301cd6b
subagent.zh.md: 046135ea378e07d5e5d96b8e7fc9663c4a9329c6

View File

@@ -41,9 +41,12 @@ The tool layer builds this request from the model input and its own config; the
* What a caller asks for when starting a ONE-SHOT subagent. The tool layer
* builds this from the model's `{ description, prompt }` plus its own config;
* the service validates {@link SubagentCapabilities} against the named provider
* before dispatching to {@link SubagentProvider.start}.
* and resolves the durable descriptor before dispatching to
* {@link SubagentProvider.start}.
*/
interface SubagentStartRequest {
/** Short display label persisted with a session-backed child. */
readonly label: string
/** Content delivered as the child's user message. */
readonly prompt: ContentBlock[]
/**
@@ -95,7 +98,18 @@ interface SubagentStartRequest {
`signal` is the single cancellation channel before and after readiness. The [subagent composition-controls Agent Note](../../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md) owns the persona, live global-tool filter, absolute-depth, and visibility-not-authority rationale.
Providers receive exactly this request: one-shot delegation has no service-resolved continuation state, because a continuable child never reaches `SubagentProvider.start()`.
The caller-facing request does not carry catalog format details or continuation state. `SubagentService.start()` resolves the detached one-shot descriptor after capability checks, then passes this provider-facing request to the selected transport; a continuable child never reaches `SubagentProvider.start()`:
```ts type-equiv
/**
* Provider-facing one-shot request after {@link SubagentService.start} resolves
* the durable child descriptor.
*/
interface ResolvedSubagentStartRequest extends SubagentStartRequest {
/** Detached descriptor a session-backed provider persists in the child log. */
readonly descriptor: SubagentDescriptorData
}
```
## Continuable children and activations
@@ -200,11 +214,13 @@ interface ContinuableCreateSpec {
}
```
The descriptor (`SubagentDescriptorData` in [descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts)) snapshots explicit fields — provider name, the delegation `description` as the durable creation `label`, resolved child `agentOptions.provider`/`model`, optional `persona`/`toolFilter` — never 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` (a one-shot result contract, not durable composition). The continuation manager appends the model-hidden `subagent/descriptor` event after any provider-supplied lineage and before the initial prompt is admitted; `header.seedLength` remains the fork-lineage boundary, so descriptor lookup reads the child's own suffix. The event is log-only: no `surfaceOp`, never in model history, and retained across compaction by the append-only log.
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 and delegation `description` as the durable creation `label`. `one-shot` stops there; `continuable` additionally snapshots resolved child `agentOptions.provider`/`model` 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).
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; `header.seedLength` remains the fork-lineage boundary, so descriptor lookup reads the child's own suffix. 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.
## Durable enumeration: `listChildren()` and `SubagentListEntry`
`SubagentService.listChildren(parentSessionId)` enumerates the parent's direct continuable children from one `ctx.sessionQuery.traceSession()` observation, without loading or resuming any Agent. Session lineage is broader than subagent identity — ordinary forks and one-shot children share `parentSession` — so exactly one supported `subagent/descriptor` event in the child's own suffix (after `seedLength`, so a fork seed cannot leak an ancestor's descriptor) is the sole subagent discriminator. The result is one `SubagentListEntry[]` in the trace's `createdAt`-then-id candidate order: a valid descriptor yields a `child` entry whose `status` snapshots the logical record (`running` = live in `ctx.sessions`, `complete` = persisted only, resumable by `send_message`); a per-child inspection failure yields a `diagnostic` entry (`corrupt`, `unsupported`, or `unavailable`) so one damaged sibling cannot hide healthy children; a missing descriptor yields no entry. A failure while building the initial trace fails the whole call — per-child isolation begins only after a trustworthy candidate set exists. The service keeps `sessionQuery` optional for by-id continuation: `listChildren()` throws `SUBAGENT_CONTROL_SESSION_QUERY_UNAVAILABLE` when it is absent, while the model-facing `list_agents` adapter (the separately loadable `/list-agents` plugin of [dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control)) requires the service at plugin load. Listing does not consult the continuation manager's Activation map or provider availability; `send_message` remains the authoritative delivery-time operation, and a listed `running` child may still reject delivery as an ownership conflict.
`SubagentService.listChildren(parentSessionId)` enumerates the parent's direct session-backed subagents from one `ctx.sessionQuery.traceSession()` observation, without loading or resuming any Agent. Session lineage is broader than subagent identity — ordinary forks share `parentSession` — so exactly one supported `subagent/descriptor` event in the child's own suffix (after `seedLength`, so a fork seed cannot leak an ancestor's descriptor) is the sole subagent discriminator. The result is one `SubagentListEntry[]` in the trace's `createdAt`-then-id candidate order: a valid descriptor yields a `child` entry with `mode: 'one-shot' | 'continuable'` and `activity: 'running' | 'inactive'`; a per-child inspection failure yields a `diagnostic` entry (`corrupt`, `unsupported`, or `unavailable`) so one damaged sibling cannot hide healthy children; a missing descriptor yields no entry. Activity snapshots only whether the logical record is live in `ctx.sessions`, not outcome or resumability. A service consumer such as a UI can display both modes, 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 maps activity to its existing `running`/`complete` vocabulary. A failure while building the initial trace fails the whole call — per-child isolation begins only after a trustworthy candidate set exists. The service keeps `sessionQuery` optional for by-id continuation: `listChildren()` throws `SubagentError` with code `SUBAGENT_CONTROL_SESSION_QUERY_UNAVAILABLE` when it is absent, while the list tool requires `ctx.subagents` and `ctx.sessionQuery` at plugin load. 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 terminal result: `SubagentResult`
@@ -295,7 +311,7 @@ interface SubagentRun {
}
```
A local one-shot run MUST publish an ordinary child agent/session before `start()` fulfills, return that child session id as `SubagentRun.id`, expose the exact child as `localAgent`, and record `request.parent.session.id` in the child's `parentSession` header. Runtime ownership may place the child under the parent, provider, or root scope. A remote provider instead returns a parent-scoped lifecycle id and `localAgent: undefined`.
A local one-shot run MUST publish an ordinary child agent/session before `start()` fulfills, return that child session id as `SubagentRun.id`, expose the exact child as `localAgent`, record `request.parent.session.id` in the child's `parentSession` header, and append the resolved descriptor inside the child's initial turn before its first request. Runtime ownership may place the child under the parent, provider, or root scope. A remote provider instead returns a parent-scoped lifecycle id and `localAgent: undefined`; without a local child Session, it is absent from trace-backed enumeration.
## The provider seam: `SubagentProvider`
@@ -321,13 +337,13 @@ interface SubagentProvider {
/**
* Establish a ONE-SHOT child and return its handle only after publication.
* The service has already validated that every requested start-time
* capability is supported, so an implementation may assume e.g.
* `request.maxDepth` is honorable when present. If setup fails or
* `request.signal` aborts before fulfillment, the provider owns and cleans
* all partial resources before this promise rejects. Ownership transfers to
* the caller only on fulfillment.
* capability is supported and resolved `request.descriptor`, so a
* session-backed implementation appends that descriptor inside the child's
* initial turn. If setup fails or `request.signal` aborts before fulfillment,
* the provider owns and cleans all partial resources before this promise
* rejects. Ownership transfers to the caller only on fulfillment.
*/
start(request: SubagentStartRequest): Promise<SubagentRun>
start(request: ResolvedSubagentStartRequest): Promise<SubagentRun>
/**
* OPTIONAL (continuable-creation capability): contribute the detached
* creation inputs that distinguish this provider's continuable children —

View File

@@ -41,9 +41,12 @@ interface SubagentCapabilities {
* What a caller asks for when starting a ONE-SHOT subagent. The tool layer
* builds this from the model's `{ description, prompt }` plus its own config;
* the service validates {@link SubagentCapabilities} against the named provider
* before dispatching to {@link SubagentProvider.start}.
* and resolves the durable descriptor before dispatching to
* {@link SubagentProvider.start}.
*/
interface SubagentStartRequest {
/** Short display label persisted with a session-backed child. */
readonly label: string
/** Content delivered as the child's user message. */
readonly prompt: ContentBlock[]
/**
@@ -95,7 +98,18 @@ interface SubagentStartRequest {
`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 Agent Note](../../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)规定 persona、live 全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。
提供方接收的正是此请求:单次委派不含由服务解析的继续执行状态,因为可继续子 agent 绝不会到达 `SubagentProvider.start()`
面向调用方的请求不携带目录格式细节或继续执行状态。`SubagentService.start()` 会在功能检查后解析分离的一次性描述符,再将以下面向提供方的请求传给所选传输;可继续子 agent 绝不会到达 `SubagentProvider.start()`
```ts type-equiv
/**
* Provider-facing one-shot request after {@link SubagentService.start} resolves
* the durable child descriptor.
*/
interface ResolvedSubagentStartRequest extends SubagentStartRequest {
/** Detached descriptor a session-backed provider persists in the child log. */
readonly descriptor: SubagentDescriptorData
}
```
## 可继续子 agent 与激活
@@ -200,11 +214,13 @@ interface ContinuableCreateSpec {
}
```
描述符([descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts) 中的 `SubagentDescriptorData`会对显式字段建立快照——提供方名称作为持久化创建 `label` 的委派 `description`已解析的子 agent `agentOptions.provider`/`model`可选的 `persona`/`toolFilter`——绝不会对可合并扩展的 `AgentOptions` 对象建立快照,因此无关的扩展值不会破坏继续执行,后续新增组合配置输入则是一次有意的版本更改。省略 `subagentDepth`(冷恢复以持久化 header 中的 `delegationDepth` 作为单调下界)和 `outputSchema`(单次结果契约,而非持久化组合配置)。继续执行管理器会在任何提供方提供的谱系之后、初始 prompt 获准之前,追加对模型隐藏的 `subagent/descriptor` 事件;`header.seedLength` 仍是 fork 谱系边界,因此描述符查找会读取子 agent 自身的后缀。该事件只进入日志:不含 `surfaceOp`,绝不进入模型历史,并由仅追加日志跨压缩保留
描述符([descriptor.ts](../../packages/subagent/subagent/src/descriptor.ts) 中的 `SubagentDescriptorData`是每个由会话支撑的 subagent 所使用、按模式判别的持久化身份。两种模式都携带提供方名称作为持久化创建 `label` 的委派 `description`。`one-shot` 到此为止;`continuable` 还会对已解析的子 agent `agentOptions.provider``model`可选的 `persona``toolFilter` 建立快照,用于冷恢复。它绝不会对可合并扩展的 `AgentOptions` 对象建立快照,因此无关的扩展值不会破坏继续执行,后续新增组合配置输入则是一次有意的版本更改。描述符省略 `subagentDepth`(冷恢复以持久化 header 中的 `delegationDepth` 作为单调下界)和 `outputSchema`(单次运行或 Activation 的结果契约,而非持久化身份)
本地一次性提供方会在子 agent 的初始轮次内、首次请求前追加描述符。继续执行管理器会在任何提供方提供的谱系之后、初始 prompt 获准之前追加描述符;`header.seedLength` 仍是 fork 谱系边界,因此描述符查找会读取子 agent 自身的后缀。该事件只进入日志:不含 `surfaceOp`,绝不进入模型历史,并由仅追加日志跨压缩保留。格式错误的当前版本描述符属于损坏;本运行时无法对不受支持的版本进行分类。
## 持久化枚举:`listChildren()` 与 `SubagentListEntry`
`SubagentService.listChildren(parentSessionId)` 从一次 `ctx.sessionQuery.traceSession()` 观测中枚举 parent 直接可继续 child,而不会加载或恢复任何 Agent。会话谱系的范围比 subagent 身份更广——普通 fork 和一次性 child 都会共享 `parentSession`——因此child 自身后缀中恰好一个受支持的 `subagent/descriptor` 事件(位于 `seedLength` 之后,避免 fork seed 泄漏祖先描述符)是唯一的 subagent 判别信息。结果是一个按追踪结果中 `createdAt`、再按 id 排列候选顺序的 `SubagentListEntry[]`:有效描述符生成 `child` 条目,其 `status` 是逻辑记录的快照(`running` 表示在 `ctx.sessions` 中存活,`complete` 表示只存在于持久化存储中并可由 `send_message` 恢复);逐 child 检查失败生成 `diagnostic` 条目(`corrupt`、`unsupported` 或 `unavailable`),因此一个损坏的 sibling 不会隐藏健康 child缺少描述符则不生成条目。构建初始追踪时的失败会让整个调用失败——只有得到可信候选集后才开始逐 child 隔离。服务将 `sessionQuery` 保持为按 id 继续执行时的可选依赖:缺少该服务时,`listChildren()` 抛出 `SUBAGENT_CONTROL_SESSION_QUERY_UNAVAILABLE`,而面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)会在插件加载时要求该服务。枚举不会查询继续执行管理器的 Activation map 或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的 `running` child 仍可能因所有权冲突而拒绝投递。
`SubagentService.listChildren(parentSessionId)` 从一次 `ctx.sessionQuery.traceSession()` 观测中枚举 parent 直接且由会话支撑的 subagent,而不会加载或恢复任何 Agent。会话谱系的范围比 subagent 身份更广——普通 fork 会共享 `parentSession`——因此child 自身后缀中恰好一个受支持的 `subagent/descriptor` 事件(位于 `seedLength` 之后,避免 fork seed 泄漏祖先描述符)是唯一的 subagent 判别信息。结果是一个按追踪结果中 `createdAt`、再按 id 排列候选顺序的 `SubagentListEntry[]`:有效描述符生成带有 `mode: 'one-shot' | 'continuable'` 和 `activity: 'running' | 'inactive'` 的 `child` 条目;逐 child 检查失败生成 `diagnostic` 条目(`corrupt`、`unsupported` 或 `unavailable`),因此一个损坏的 sibling 不会隐藏健康 child缺少描述符则不生成条目。活动状态只表示逻辑记录是否在 `ctx.sessions` 中存活而不表示结果或可恢复性。UI 等服务消费方可以展示两种模式;面向模型的 `list_agents` 适配器([dsh-tool-subagent-control](../../packages/subagent/tool-subagent-control) 中可单独加载的 `/list-agents` 插件)则只保留可继续条目,并将活动状态映射到现有的 `running``complete` 词汇。构建初始追踪时的失败会让整个调用失败——只有得到可信候选集后才开始逐 child 隔离。服务将 `sessionQuery` 保持为按 id 继续执行时的可选依赖:缺少该服务时,`listChildren()` 抛出 `SubagentError`,并携带错误码 `SUBAGENT_CONTROL_SESSION_QUERY_UNAVAILABLE`;列表工具则在插件加载时要求 `ctx.subagents` 与 `ctx.sessionQuery`。枚举不会查询继续执行管理器的 Activation map、Agent 注册表或提供方可用性;`send_message` 仍是消息送达时的权威操作,列表中的运行中可继续 child 仍可能因所有权冲突而拒绝投递。
## 终态结果:`SubagentResult`
@@ -295,7 +311,7 @@ interface SubagentRun {
}
```
本地单次 run 必须在 `start()` fulfill 之前发布一个普通子 agent/会话,将该子会话 id 作为 `SubagentRun.id` 返回,以 `localAgent` 暴露确切的子 agent在子 agent 的 `parentSession` header 中记录 `request.parent.session.id`。运行时所有权可以把子 agent 放在 parent、提供方或 root 作用域下。远程提供方则返回 parent 作用域的生命周期 id 与 `localAgent: undefined`。
本地单次 run 必须在 `start()` fulfill 之前发布一个普通子 agent会话,将该子会话 id 作为 `SubagentRun.id` 返回,以 `localAgent` 暴露确切的子 agent在子 agent 的 `parentSession` header 中记录 `request.parent.session.id`,并在子 agent 的初始轮次内、首次请求前追加已解析的描述符。运行时所有权可以把子 agent 放在 parent、提供方或 root 作用域下。远程提供方则返回 parent 作用域的生命周期 id 与 `localAgent: undefined`;由于没有本地 child Session它不会出现在基于追踪的枚举结果中
<a id="the-provider-seam-subagentprovider"></a>
@@ -323,13 +339,13 @@ interface SubagentProvider {
/**
* Establish a ONE-SHOT child and return its handle only after publication.
* The service has already validated that every requested start-time
* capability is supported, so an implementation may assume e.g.
* `request.maxDepth` is honorable when present. If setup fails or
* `request.signal` aborts before fulfillment, the provider owns and cleans
* all partial resources before this promise rejects. Ownership transfers to
* the caller only on fulfillment.
* capability is supported and resolved `request.descriptor`, so a
* session-backed implementation appends that descriptor inside the child's
* initial turn. If setup fails or `request.signal` aborts before fulfillment,
* the provider owns and cleans all partial resources before this promise
* rejects. Ownership transfers to the caller only on fulfillment.
*/
start(request: SubagentStartRequest): Promise<SubagentRun>
start(request: ResolvedSubagentStartRequest): Promise<SubagentRun>
/**
* OPTIONAL (continuable-creation capability): contribute the detached
* creation inputs that distinguish this provider's continuable children —

View File

@@ -22,7 +22,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `agent/session-start` | `emit` | [`packages/core/agent/src/types.ts:362`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`workspace-context`](../packages/context/workspace-context) |
| `agent/settled` | `emit` | [`packages/core/agent/src/types.ts:450`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`compact-basic`](../packages/compact/compact-basic) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:298`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`agent`](../packages/core/agent), `apiproxy`, [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/step` | `serial` | [`packages/core/agent/src/types.ts:389`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`compact-basic`](../packages/compact/compact-basic), [`plan-mode`](../packages/plan/plan-mode), [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-skill`](../packages/skill/tool-skill), [`workspace-context`](../packages/context/workspace-context) |
| `agent/step` | `serial` | [`packages/core/agent/src/types.ts:389`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`compact-basic`](../packages/compact/compact-basic), [`plan-mode`](../packages/plan/plan-mode), [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-skill`](../packages/skill/tool-skill), [`workspace-context`](../packages/context/workspace-context) |
| `agent/turn-stopping` | `serial` | [`packages/core/agent/src/types.ts:436`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:30`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `apiproxy` |
| `commands/change` | `emit` | [`packages/ui/commands/src/index.ts:154`](../packages/ui/commands/src/index.ts) | [`commands`](../packages/ui/commands) (`events.dispatch`) | `apiproxy`, [`tui`](../packages/ui/tui) |
@@ -41,10 +41,10 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `settings/document-updated` | `emit` | [`packages/settings/settings/src/index.ts:150`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | `apiproxy` |
| `settings/updated` | `emit` | [`packages/settings/settings/src/index.ts:137`](../packages/settings/settings/src/index.ts) | [`settings`](../packages/settings/settings) (`events.dispatch`) | [`settings`](../packages/settings/settings) |
| `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:188`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | [`tui`](../packages/ui/tui) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:142`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`jsonrpc`](../packages/ui/jsonrpc), [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:116`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:122`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:133`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:151`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`jsonrpc`](../packages/ui/jsonrpc), [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:125`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/provider-removed` | `emit` | [`packages/subagent/subagent/src/index.ts:131`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:142`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`subagent`](../packages/subagent/subagent) |
| `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:29`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`waterfall`) | [`agent`](../packages/core/agent), [`system-prompt`](../packages/core/system-prompt) |
| `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - |
| `telemetry/record` | `waterfall` | [`packages/telemetry/session-telemetry/src/index.ts:41`](../packages/telemetry/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/telemetry/session-telemetry) (`waterfall`) | - |

View File

@@ -522,11 +522,11 @@ Source: [`packages/core/session/src/types.ts:216`](../packages/core/session/src/
```ts persistence-catalog
/**
* Durable declared composition of a continuable subagent child, appended
* once by the establishing provider inside the child's initial turn,
* before its first request. Log-only: it carries no `surfaceOp`, never
* enters model history, and the append-only log retains it when
* compaction replaces surface history.
* Durable identity and lifecycle mode of a session-backed subagent child,
* appended once by the establishing provider inside the child's initial
* turn, before its first request. Continuable records also carry their
* resumable composition. Log-only: it carries no `surfaceOp`, never enters
* model history, and survives compaction.
*/
'subagent/descriptor': SubagentDescriptorData
```

View File

@@ -1151,7 +1151,7 @@ The registered tool name is the load-time `toolName` config (default `subagent`)
### `list_agents`
List your background subagents by durable id and label. Status is a snapshot of the stored record: running means the subagent session is currently live in this process, complete means it exists only in storage and a `send_message` starts a new turn on the same conversation. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped.
List your continuable background subagents by durable id and label. Status is a snapshot of the stored record: running means the subagent session is currently live in this process, complete means it exists only in storage and a `send_message` starts a new turn on the same conversation. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped.
```json
{