refactor(subagent): narrow continuation interface

This commit is contained in:
Tianyi Cui
2026-07-28 00:10:24 +08:00
committed by imccyu
parent 644bf00b86
commit f14121a4c2
55 changed files with 669 additions and 441 deletions

View File

@@ -1582,7 +1582,7 @@ export interface Config {
}
```
Source: [`packages/subagent/subagent-fork/src/index.ts:25`](../packages/subagent/subagent-fork/src/index.ts)
Source: [`packages/subagent/subagent-fork/src/index.ts:30`](../packages/subagent/subagent-fork/src/index.ts)
## `@deepseek-ai/dsh-subagent-spawn`
@@ -1596,7 +1596,7 @@ export interface Config {
}
```
Source: [`packages/subagent/subagent-spawn/src/index.ts:20`](../packages/subagent/subagent-spawn/src/index.ts)
Source: [`packages/subagent/subagent-spawn/src/index.ts:25`](../packages/subagent/subagent-spawn/src/index.ts)
## `@deepseek-ai/dsh-system-prompt`

View File

@@ -685,14 +685,12 @@ Source: [`packages/core/session/src/index.ts:93`](../../packages/core/session/sr
### `session/flush` — parallel
Awaited parallel durability checkpoint: every listener runs and the caller awaits all of them, with no waterfall veto. An empty listener snapshot is accepted by SessionStore.flush and rejected by SessionStore.flushRequired. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
Awaited parallel durability checkpoint: every listener runs and the caller awaits all of them, with no waterfall veto. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
```ts cordis-catalog
/**
* Awaited parallel durability checkpoint: every listener runs and the
* caller awaits all of them, with no waterfall veto. An empty listener
* snapshot is accepted by {@link SessionStore.flush} and rejected by
* {@link SessionStore.flushRequired}. Scope-filtered dispatch
* caller awaits all of them, with no waterfall veto. Scope-filtered dispatch
* (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
* @param session - the session whose buffered events must reach durable storage.
* @dshScopeScan unsupported
@@ -703,7 +701,7 @@ Awaited parallel durability checkpoint: every listener runs and the caller await
Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
Source: [`packages/core/session/src/index.ts:104`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:102`](../../packages/core/session/src/index.ts)
## `settings/*`
@@ -796,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:165`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:166`](../../packages/subagent/subagent/src/index.ts)
### `subagent/provider-added` — emit
@@ -813,7 +811,7 @@ A provider became resolvable in the registry.
Types: [SubagentProvider](../core-data-structures/subagent.md)
Source: [`packages/subagent/subagent/src/index.ts:139`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:140`](../../packages/subagent/subagent/src/index.ts)
### `subagent/provider-removed` — emit
@@ -828,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:145`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:146`](../../packages/subagent/subagent/src/index.ts)
### `subagent/start` — emit
@@ -850,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:156`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:157`](../../packages/subagent/subagent/src/index.ts)
## `system-prompt/*`

View File

@@ -1635,22 +1635,11 @@ announce(session: Session): void
* raw `ctx.parallel('session/flush', …)` — one owner, one spelling, and the
* scoped-dispatch invariant can pin it.
* @param session - the session whose buffered events must reach durable storage.
* @returns resolves when every flush listener has settled; after all settle,
* rejects with the first registered listener failure if any listener failed.
* @returns whether at least one durability listener participated, after every
* listener has settled successfully.
* @throws the first registered listener failure after every listener settles.
*/
async flush(session: Session): Promise<void>
/**
* Dispatch the same awaited checkpoint as {@link flush}, but reject when its
* scoped listener snapshot is empty. Callers use this operation when success
* requires an installed durability participant rather than optional
* best-effort persistence.
* @param session - the session whose buffered events must reach durable storage.
* @returns resolves when at least one listener participated and every
* listener settled successfully.
* @throws when no listener is registered or any registered listener fails.
*/
async flushRequired(session: Session): Promise<void>
async flush(session: Session): Promise<boolean>
/**
* Look up a live session.
@@ -1684,7 +1673,7 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId):
Types: [CreateSessionOptions](../core-data-structures/persistence.md) · [Session](../core-data-structures/session.md) · [SessionId](../core-data-structures/core.md)
Source: [`packages/core/session/src/index.ts:766`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:764`](../../packages/core/session/src/index.ts)
## `ctx.sessionTitle` — `SessionTitleService`
@@ -1972,17 +1961,18 @@ Named provider registry with raw and Task-backed continuation operations.
startContinuable(spec: ContinuableStartSpec): ContinuableStart
/**
* Deliver a message to a continuable child by steering its live activation
* or cold-resuming a fresh Task-backed activation.
* Follow up with a continuable child. A live child is steered and fulfillment
* confirms request admission; an idle child immediately returns a fresh Task
* whose descriptor lookup, authorization, and cold resume may later fail.
* @param parent - live direct parent authorizing the operation.
* @param childId - durable child session id.
* @param message - user-role content to deliver.
* @param source - durable caller attribution.
* @param signal - caller cancellation; while live delivery awaits admission,
* abort cancels the shared activation so the wait reaches quiescence.
* @param content - user-role content to deliver.
* @param options - durable attribution and caller cancellation; aborting a
* live-delivery wait cancels the shared activation and awaits quiescence.
* @returns the existing steered Task or newly started Task.
* @throws when continuation services are unavailable or live delivery is not admitted.
*/
sendMessage( parent: Agent, childId: SessionId, message: ContentBlock[], source: MessageSource, signal: AbortSignal, ): Promise<SendMessageResult>
followup( parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions, ): Promise<SubagentFollowupResult>
/**
* Register a provider under its name. Registration is effect-scoped and HMR
@@ -2016,23 +2006,11 @@ list(): string[]
* @returns the ready holder-owned run.
*/
async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
/**
* Resume a persisted continuable child through the named provider's
* `resume` capability, with the same run lifecycle observation as
* {@link start}. The internal continuation manager has already loaded the
* child, folded its descriptor, and authorized the parent; this method owns
* only capability-checked dispatch.
* @param name - the provider recorded in the child's descriptor.
* @param request - the fully resolved resume request.
* @returns the fresh holder-owned run for the resumed activation.
*/
async resume(name: string, request: SubagentResumeRequest): 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) · [MessageSource](../core-data-structures/core.md) · [SendMessageResult](../core-data-structures/subagent.md) · [SessionId](../core-data-structures/core.md) · [SubagentProvider](../core-data-structures/subagent.md) · [SubagentResumeRequest](../core-data-structures/subagent.md) · [SubagentRun](../core-data-structures/subagent.md) · [SubagentStartRequest](../core-data-structures/subagent.md)
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) · [SessionId](../core-data-structures/core.md) · [SubagentFollowupOptions](../core-data-structures/subagent.md) · [SubagentFollowupResult](../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:198`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:199`](../../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: 1321429ac9e6280878016601646dd08981ab2b40
subagent.zh.md: 072b2d2c1635d7c2c59b5a24d2bafc6ee32f8422
subagent.md: 2dc25dfb14b1506edf7f53f6ce0d8681fefa98c6
subagent.zh.md: 00f2748ad92ae37b0a2fe2616d9e052f9c4b916f

View File

@@ -39,8 +39,8 @@ The tool layer builds this request from the model input and its own config; the
/**
* What a caller asks for when starting a 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, then
* passes it to {@link SubagentProvider.start}.
* validates {@link SubagentCapabilities} against the named provider and
* resolves a {@link SubagentProviderStartRequest} for dispatch.
*/
interface SubagentStartRequest {
/** Content delivered as the child's user message. */
@@ -89,23 +89,36 @@ interface SubagentStartRequest {
* persona (strict `{{…}}` interpolation against the registered variables).
*/
readonly persona?: string
/**
* Continuable-child intent, resolved by `ctx.subagents` before start.
* The provider MUST publish exactly `sessionId` as the child identity
* instead of allocating one internally, and MUST append the snapshotted
* `descriptor` as the child's turn-enclosed `subagent/descriptor` event
* before its first request. Requires {@link SubagentProvider.resume} (the
* continuation capability); the service rejects the request otherwise.
*/
readonly continuation?: SubagentContinuation
}
```
`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.
## Continuable children: `SubagentContinuation` and `SubagentResumeRequest`
Providers receive a separate resolved shape. Raw `SubagentService.start()` clears continuation state, while `startContinuable()` alone supplies the service-allocated identity and descriptor.
A **continuable background subagent** is a durable child session with a series of Task-backed activations. `SubagentService.startContinuable()` allocates the stable child id, snapshots the versioned `subagent/descriptor` payload, and passes both through the resolved start request; the provider publishes exactly that id and appends the descriptor before the initial prompt is admitted. `SubagentService.sendMessage()` loads and authorizes a stopped child before dispatching a fully resolved resume request through the raw `resume()` operation, or steers its live activation. An internal manager owns descriptor lookup and Task association only while `ctx.tasks` and `ctx.agents` exist; persistence is required per continuation operation, not to load the provider registry. `startContinuable()` returns both identities, while `sendMessage()` reports whether the message `steered` the existing Task or `started` a fresh one. Every sender supplies a `MessageSource` and cancellation signal; abort while live delivery awaits admission cancels the shared activation and rejects after quiescence. The optional model-facing tool uses `CoordinatorMessageSource` and its tool-execution signal, while a human adapter uses `{ kind: 'user' }` and its interaction signal.
```ts type-equiv
/**
* Provider-facing start request after the service resolves optional
* continuation state. Ordinary callers use {@link SubagentStartRequest}; only
* the Task-backed continuation path can attach a stable child identity and
* durable descriptor.
*/
interface SubagentProviderStartRequest extends SubagentStartRequest {
/**
* Continuable-child state resolved by `ctx.subagents` before provider dispatch.
* The provider MUST publish exactly `sessionId` as the child identity
* instead of allocating one internally, and MUST append the snapshotted,
* model-hidden `subagent/descriptor` before the initial prompt is admitted.
* Requires {@link SubagentProvider.resume} (the
* continuation capability); the service rejects the request otherwise.
*/
readonly continuation?: SubagentContinuation | undefined
}
```
## Continuable children and provider resume
A **continuable background subagent** is a durable child session with a series of Task-backed activations. `SubagentService.startContinuable()` allocates the stable child id, snapshots the versioned `subagent/descriptor` payload, and passes both through the provider-facing start request; the provider publishes exactly that id and appends the descriptor before the initial prompt is admitted. `SubagentService.followup()` mirrors the intent verb on `Agent`: it steers a live activation or privately dispatches a resolved provider resume after loading and authorizing a stopped child. An internal manager owns descriptor lookup and Task association only while `ctx.tasks` and `ctx.agents` exist; persistence is required per continuation operation, not to load the provider registry. `startContinuable()` returns both identities, while `followup()` reports whether the content `steered` the existing Task or `started` a fresh one. Every sender supplies a `MessageSource` and cancellation signal through one options object; abort while live delivery awaits admission cancels the shared activation and rejects after quiescence. The optional model-facing tool uses `CoordinatorMessageSource` and its tool-execution signal, while a human adapter uses `{ kind: 'user' }` and its interaction signal.
```ts type-equiv
/** Attribution for a model coordinator's follow-up to one of its children. */
@@ -118,8 +131,33 @@ interface CoordinatorMessageSource {
```ts type-equiv
/**
* The resolved continuable-child identity and durable composition record a
* continuation caller attaches to a start request.
* Options for following up with one continuable child.
*/
interface SubagentFollowupOptions {
/** Durable attribution retained on either live or resumed delivery. */
readonly source: MessageSource
/** Caller cancellation for a live-delivery admission wait. */
readonly signal: AbortSignal
}
```
```ts type-equiv
/**
* How a continuable follow-up was routed:
* `steered` joined the running activation's existing Task without creating a
* Task of its own; `started` created a fresh Task that cold-resumes the
* durable child with the content. Failure is an exception, never a result —
* undelivered content throws.
*/
type SubagentFollowupResult =
| { readonly route: 'steered'; readonly taskId: TaskId }
| { readonly route: 'started'; readonly taskId: TaskId }
```
```ts type-equiv
/**
* The resolved continuable-child identity and durable composition record the
* service attaches before provider dispatch.
*/
interface SubagentContinuation {
/** Service-allocated stable child session id, published verbatim. */
@@ -131,14 +169,13 @@ interface SubagentContinuation {
```ts type-equiv
/**
* What a caller asks for when resuming a persisted continuable child. The
* continuation manager loads the child log, folds and authorizes its descriptor,
* and passes this fully resolved request to
* {@link SubagentService.resume}, which dispatches to
* Provider-facing request for reconstructing a persisted continuable child.
* The continuation manager loads the child log, folds and authorizes its
* descriptor, then privately dispatches this resolved request to
* {@link SubagentProvider.resume}. The provider reconstructs the declared
* composition under the live parent's scope and drives one turn with `prompt`.
*/
interface SubagentResumeRequest {
interface SubagentProviderResumeRequest {
/** The persisted child session id to resume. */
readonly sessionId: SessionId
/** The follow-up message that starts the resumed activation's turn. */
@@ -295,22 +332,22 @@ interface SubagentProvider {
* 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: SubagentProviderStartRequest): Promise<SubagentRun>
/**
* OPTIONAL (continuation capability): reconstruct a persisted continuable
* child from its own transcript and declared descriptor, drive one
* follow-up turn, and return a fresh run. Method presence is the capability
* — the service rejects `resume` dispatch and continuable starts on
* — the service rejects continuable starts and cold-resume dispatch on
* providers without it. Same publication contract as {@link start}: if
* reconstruction fails or `request.signal` aborts before fulfillment, the
* provider rolls its creation transaction back to quiescence before
* rejecting; after fulfillment the same signal cancels the published run.
*/
resume?(request: SubagentResumeRequest): Promise<SubagentRun>
resume?(request: SubagentProviderResumeRequest): Promise<SubagentRun>
}
```
`start()` fulfills only with a ready run; `resume()` shares the same publication and lifecycle-observation contract. The service mints a unique `runId`, snapshots `local` from the provider's exact `localAgent`, observes the result, emits `subagent/start`, and returns the same run; rejection implies provider cleanup and emits no lifecycle pair. The paired `subagent/end` carries the same identity and the final output or infrastructure failure. Both events are observe-only and contain listener exceptions.
Provider `start()` fulfills only with a ready run; provider `resume()` shares the same publication and lifecycle-observation contract but is dispatched only by the continuation manager. The service mints a unique `runId`, snapshots `local` from the provider's exact `localAgent`, observes the result, emits `subagent/start`, and returns the same run; rejection implies provider cleanup and emits no lifecycle pair. The paired `subagent/end` carries the same identity and the final output or infrastructure failure. Both events are observe-only and contain listener exceptions.
## In-process backends: depth and seed

View File

@@ -39,8 +39,8 @@ interface SubagentCapabilities {
/**
* What a caller asks for when starting a 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, then
* passes it to {@link SubagentProvider.start}.
* validates {@link SubagentCapabilities} against the named provider and
* resolves a {@link SubagentProviderStartRequest} for dispatch.
*/
interface SubagentStartRequest {
/** Content delivered as the child's user message. */
@@ -89,23 +89,36 @@ interface SubagentStartRequest {
* persona (strict `{{…}}` interpolation against the registered variables).
*/
readonly persona?: string
/**
* Continuable-child intent, resolved by `ctx.subagents` before start.
* The provider MUST publish exactly `sessionId` as the child identity
* instead of allocating one internally, and MUST append the snapshotted
* `descriptor` as the child's turn-enclosed `subagent/descriptor` event
* before its first request. Requires {@link SubagentProvider.resume} (the
* continuation capability); the service rejects the request otherwise.
*/
readonly continuation?: SubagentContinuation
}
```
`signal` 是就绪前后唯一的取消通道。[subagent 组合控制 Agent Note](../../.agents/notes/implemented/feature/2026-07-12-subagent-persona-tool-filter-and-depth.md)规定 persona、live 全局工具过滤、绝对深度以及「可见性而非权限」的设计理由。
## 可继续子 agent`SubagentContinuation` 与 `SubagentResumeRequest`
提供方会接收单独的已解析请求类型。直接调用 `SubagentService.start()` 会清除继续执行状态;只有 `startContinuable()` 才会提供由服务分配的标识和描述符。
**可继续后台 subagent** 是一份持久化子 agent 会话,由一系列由 Task 支撑的激活组成。`SubagentService.startContinuable()` 会分配稳定的子 agent id、对版本化的 `subagent/descriptor` payload 建立快照,并通过已解析的启动请求传入二者;提供方会准确发布该 id并在初始 prompt 获准前追加描述符。`SubagentService.sendMessage()` 会先加载并授权已停止的子 agent再通过底层 `resume()` 操作分发完全解析的恢复请求,或引导其实时激活。只有 `ctx.tasks` 和 `ctx.agents` 存在时,内部管理器才会负责描述符查找与 Task 关联;每项继续执行操作都要求持久化,而加载提供方注册表不要求持久化。`startContinuable()` 返回两个标识,`sendMessage()` 则报告消息是对现有 Task 执行了 `steered`,还是 `started` 一个新 Task。每个发送方都会提供 `MessageSource` 和取消信号;若在在线投递等待准入期间中止该信号,则会取消共享激活,并在其完全停稳后拒绝调用。可选的面向模型工具使用 `CoordinatorMessageSource` 及其工具执行信号,人工适配器则使用 `{ kind: 'user' }` 及其交互信号。
```ts type-equiv
/**
* Provider-facing start request after the service resolves optional
* continuation state. Ordinary callers use {@link SubagentStartRequest}; only
* the Task-backed continuation path can attach a stable child identity and
* durable descriptor.
*/
interface SubagentProviderStartRequest extends SubagentStartRequest {
/**
* Continuable-child state resolved by `ctx.subagents` before provider dispatch.
* The provider MUST publish exactly `sessionId` as the child identity
* instead of allocating one internally, and MUST append the snapshotted,
* model-hidden `subagent/descriptor` before the initial prompt is admitted.
* Requires {@link SubagentProvider.resume} (the
* continuation capability); the service rejects the request otherwise.
*/
readonly continuation?: SubagentContinuation | undefined
}
```
## 可继续子 agent 与提供方恢复
**可继续后台 subagent** 是一份持久化子 agent 会话,由一系列由 Task 支撑的激活组成。`SubagentService.startContinuable()` 会分配稳定的子 agent id、对版本化的 `subagent/descriptor` payload 建立快照,并通过面向提供方的启动请求传入二者;提供方会准确发布该 id并在初始 prompt 获准前追加描述符。`SubagentService.followup()` 沿用 `Agent` 的意图动词:它会引导实时激活,或在加载并授权已停止的子 agent 后,仅在内部向提供方分发已解析的恢复请求。只有 `ctx.tasks` 和 `ctx.agents` 存在时,内部管理器才会负责描述符查找与 Task 关联;每项继续执行操作都要求持久化,而加载提供方注册表不要求持久化。`startContinuable()` 返回两个标识,`followup()` 则报告内容是对现有 Task 执行了 `steered`,还是 `started` 一个新 Task。每个发送方都通过一个选项对象提供 `MessageSource` 和取消信号;若在在线投递等待准入期间中止该信号,则会取消共享激活,并在其完全停稳后拒绝调用。可选的面向模型工具使用 `CoordinatorMessageSource` 及其工具执行信号,人工适配器则使用 `{ kind: 'user' }` 及其交互信号。
```ts type-equiv
/** Attribution for a model coordinator's follow-up to one of its children. */
@@ -118,8 +131,33 @@ interface CoordinatorMessageSource {
```ts type-equiv
/**
* The resolved continuable-child identity and durable composition record a
* continuation caller attaches to a start request.
* Options for following up with one continuable child.
*/
interface SubagentFollowupOptions {
/** Durable attribution retained on either live or resumed delivery. */
readonly source: MessageSource
/** Caller cancellation for a live-delivery admission wait. */
readonly signal: AbortSignal
}
```
```ts type-equiv
/**
* How a continuable follow-up was routed:
* `steered` joined the running activation's existing Task without creating a
* Task of its own; `started` created a fresh Task that cold-resumes the
* durable child with the content. Failure is an exception, never a result —
* undelivered content throws.
*/
type SubagentFollowupResult =
| { readonly route: 'steered'; readonly taskId: TaskId }
| { readonly route: 'started'; readonly taskId: TaskId }
```
```ts type-equiv
/**
* The resolved continuable-child identity and durable composition record the
* service attaches before provider dispatch.
*/
interface SubagentContinuation {
/** Service-allocated stable child session id, published verbatim. */
@@ -131,14 +169,13 @@ interface SubagentContinuation {
```ts type-equiv
/**
* What a caller asks for when resuming a persisted continuable child. The
* continuation manager loads the child log, folds and authorizes its descriptor,
* and passes this fully resolved request to
* {@link SubagentService.resume}, which dispatches to
* Provider-facing request for reconstructing a persisted continuable child.
* The continuation manager loads the child log, folds and authorizes its
* descriptor, then privately dispatches this resolved request to
* {@link SubagentProvider.resume}. The provider reconstructs the declared
* composition under the live parent's scope and drives one turn with `prompt`.
*/
interface SubagentResumeRequest {
interface SubagentProviderResumeRequest {
/** The persisted child session id to resume. */
readonly sessionId: SessionId
/** The follow-up message that starts the resumed activation's turn. */
@@ -297,22 +334,22 @@ interface SubagentProvider {
* 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: SubagentProviderStartRequest): Promise<SubagentRun>
/**
* OPTIONAL (continuation capability): reconstruct a persisted continuable
* child from its own transcript and declared descriptor, drive one
* follow-up turn, and return a fresh run. Method presence is the capability
* — the service rejects `resume` dispatch and continuable starts on
* — the service rejects continuable starts and cold-resume dispatch on
* providers without it. Same publication contract as {@link start}: if
* reconstruction fails or `request.signal` aborts before fulfillment, the
* provider rolls its creation transaction back to quiescence before
* rejecting; after fulfillment the same signal cancels the published run.
*/
resume?(request: SubagentResumeRequest): Promise<SubagentRun>
resume?(request: SubagentProviderResumeRequest): Promise<SubagentRun>
}
```
`start()` 仅在 run 就绪时 fulfill`resume()` 采用相同的发布与生命周期观察契约。服务铸造唯一 `runId`,从提供方的确切 `localAgent` 快照 `local`观察结果emit `subagent/start`,并返回同一个 runrejection 意味着提供方已清理,且不会 emit 生命周期事件对。配对的 `subagent/end` 携带相同标识与最终输出或基础设施失败。两个事件都仅用于观察,每个 listener 异常都会被独立隔离。
提供方的 `start()` 仅在 run 就绪时 fulfill提供方的 `resume()` 采用相同的发布与生命周期观察契约,但只有继续执行管理器会分发它。服务铸造唯一 `runId`,从提供方的确切 `localAgent` 快照 `local`观察结果emit `subagent/start`,并返回同一个 runrejection 意味着提供方已清理,且不会 emit 生命周期事件对。配对的 `subagent/end` 携带相同标识与最终输出或基础设施失败。两个事件都仅用于观察,每个 listener 异常都会被独立隔离。
## 进程内后端:深度与种子

View File

@@ -37,14 +37,14 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `session/created` | `emit` | [`packages/core/session/src/index.ts:71`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | `apiproxy`, [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-telemetry`](../packages/telemetry/session-telemetry), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval) |
| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:81`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `apiproxy`, [`session-persistence`](../packages/session-persistence/session-persistence), [`session-projection-cache`](../packages/session-projection/session-projection-cache), [`session-telemetry`](../packages/telemetry/session-telemetry), [`session-title`](../packages/session-title/session-title) |
| `session/event` | `emit` | [`packages/core/session/src/index.ts:93`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/acp/acp), `apiproxy`, [`cli-demo`](../packages/examples/cli-demo), [`compact`](../packages/compact/compact), [`compact-basic`](../packages/compact/compact-basic), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-projection`](../packages/session-projection/session-projection), [`session-projection-cache`](../packages/session-projection/session-projection-cache), [`session-telemetry`](../packages/telemetry/session-telemetry), [`session-title`](../packages/session-title/session-title), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`tui`](../packages/ui/tui), [`user-approval`](../packages/ui/user-approval), [`workspace-context`](../packages/context/workspace-context) |
| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:104`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence`](../packages/session-persistence/session-persistence), [`session-telemetry`](../packages/telemetry/session-telemetry) |
| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:102`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence`](../packages/session-persistence/session-persistence), [`session-telemetry`](../packages/telemetry/session-telemetry) |
| `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:165`](../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:139`](../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:145`](../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:156`](../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:166`](../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:140`](../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:146`](../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:157`](../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`) | - |