refactor(subagent): drop host-user authority and split lifecycle publication

Remove the host-user continuation capability and the public residency query,
then separate the seam's public event payloads from its internal lifecycle
control interfaces.

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

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

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

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

Also drops now-unused dsh-tasks-local and dsh-tool-tasks dev dependencies, and
corrects the README claim that a pre-residency failure emits a terminal edge —
that path only ever rethrew.
This commit is contained in:
Dudu-0223
2026-07-30 17:47:48 +08:00
committed by Tianyi Cui
parent 7428cdf41e
commit 853f4d5cfb
25 changed files with 524 additions and 671 deletions

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:143`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:136`](../../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:117`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:110`](../../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:123`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:116`](../../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:134`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:127`](../../packages/subagent/subagent/src/index.ts)
## `system-prompt/*`

View File

@@ -1967,35 +1967,18 @@ async startContinuable(spec: ContinuableStartSpec): Promise<ContinuableStart>
* Deliver one later message to a continuable child as its next FIFO turn. A
* resident child's Agent inbox accepts it directly (waking a `waiting`
* Activation), while an absent one is cold-resumed from its persisted
* Session. The Agent inbox is the only queue, so parent and user messages
* share one observable order.
* @param authority - trusted parent or user authority for this delivery.
* Session. The Agent inbox is the only queue, so every accepted message has
* one observable order.
* @param parent - the exact live direct parent authorizing this delivery.
* @param childId - durable child session id.
* @param content - user-role content to deliver.
* @param options - durable provenance and caller cancellation, which stops the
* operation only before inbox acceptance.
* @returns the accepted message's inbox id.
* @throws when continuation services are unavailable, authority is rejected,
* or the message was not admitted.
* @throws when continuation services are unavailable, parent authority is
* rejected, or the message was not admitted.
*/
async followup( authority: SubagentAuthority, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions, ): Promise<MessageId>
/**
* Host-user authority for continuable operations, which may continue any
* durable child without its parent. A composition passes this only to a
* trusted host adapter carrying real human interaction; a model-facing tool
* uses `{ kind: 'parent', agent }` from its own execution context instead.
* @returns the authority a host adapter supplies to {@link followup}.
*/
userAuthority(): SubagentAuthority
/**
* Read one durable child's live residency state.
* @param childId - durable child session id.
* @returns its Activation state, or `undefined` when no Activation is live.
* @throws when continuation services are unavailable.
*/
activationState(childId: SessionId): ActivationState | undefined
async followup( parent: Agent, childId: SessionId, content: ContentBlock[], options: SubagentFollowupOptions, ): Promise<MessageId>
/**
* Close continuable admission synchronously, then dispose every live
@@ -2040,9 +2023,9 @@ list(): string[]
async start(name: string, request: SubagentStartRequest): Promise<SubagentRun>
```
Types: [ActivationState](../core-data-structures/subagent.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) · [SubagentAuthority](../core-data-structures/subagent.md) · [SubagentFollowupOptions](../core-data-structures/subagent.md) · [SubagentProvider](../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) · [MessageId](../core-data-structures/core.md) · [SessionId](../core-data-structures/core.md) · [SubagentFollowupOptions](../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:176`](../../packages/subagent/subagent/src/index.ts)
Source: [`packages/subagent/subagent/src/index.ts:141`](../../packages/subagent/subagent/src/index.ts)
## `ctx.subprocess` — `SubprocessService` (abstract seam)