refactor(agent-loop): simplify observable state machine

This commit is contained in:
_Kerman
2026-07-24 21:18:48 +08:00
parent fb0ef82aa6
commit b73eb7663c
131 changed files with 2011 additions and 4292 deletions

View File

@@ -15,15 +15,15 @@ Dispatch modes: **emit** (fire-and-forget), **waterfall** (each listener gets `n
### `agent/cancel-requested` — emit
Effective broad cancellation was requested, before queued/steering work is cleared or the active turn is aborted. This observe-only notification cannot veto cancellation; listener failures are contained.
Effective broad cancellation was requested, before queued/outbox work is cleared or the active turn is aborted. This observe-only notification cannot veto cancellation; listener failures are contained.
```ts cordis-catalog
/**
* Effective broad cancellation was requested, before queued/steering work
* Effective broad cancellation was requested, before queued/outbox work
* is cleared or the active turn is aborted. This observe-only notification
* cannot veto cancellation; listener failures are contained.
* @param agent - the agent whose current work is being cancelled.
* @param cause - resolved typed cancellation cause, including the default.
* @param cause - the explicit typed cancellation cause.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
@@ -32,7 +32,7 @@ Effective broad cancellation was requested, before queued/steering work is clear
Types: [Agent](../core-data-structures/core.md) · [AgentCancelCause](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:359`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:328`](../../packages/core/agent/src/types.ts)
### `agent/created` — emit
@@ -54,16 +54,16 @@ A fully configured agent and live session were published. Setup is composition-o
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:295`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:270`](../../packages/core/agent/src/types.ts)
### `agent/disposed` — emit
An agent left the registry; AgentLoop emits this after driver quiescence but before session detachment and scoped-registration unwind. Custom registry users own their driver-ordering contract.
An agent left the registry; AgentLoop emits this after driver quiescence and scoped-registration unwind, but before session detachment. Custom registry users own their driver-ordering contract.
```ts cordis-catalog
/**
* An agent left the registry; AgentLoop emits this after driver quiescence
* but before session detachment and scoped-registration unwind. Custom
* and scoped-registration unwind, but before session detachment. Custom
* registry users own their driver-ordering contract.
* @param agent - the exact agent removed from the registry.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
@@ -74,16 +74,16 @@ An agent left the registry; AgentLoop emits this after driver quiescence but bef
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:304`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:279`](../../packages/core/agent/src/types.ts)
### `agent/error` — emit
A step or turn errored. The loop reports a failure here (plus the logger) even when the error has no in-turn position for a session `error` event.
A step or turn errored. The machine reports a failure here (plus the logger) even when the error has no in-turn position for a durable record.
```ts cordis-catalog
/**
* A step or turn errored. The loop reports a failure here (plus the logger)
* even when the error has no in-turn position for a session `error` event.
* A step or turn errored. The machine reports a failure here (plus the
* logger) even when the error has no in-turn position for a durable record.
* @param agent - the agent whose turn errored.
* @param turn - the turn in which the failure surfaced.
* @param step - the step at which the failure surfaced.
@@ -96,7 +96,30 @@ A step or turn errored. The loop reports a failure here (plus the logger) even w
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:507`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:436`](../../packages/core/agent/src/types.ts)
### `agent/idle` — emit
One drain chain reached its terminal turn: that turn's `turn/end` is already committed. Automatically recovered failed turns do not emit this notification. `reason` says why; model-request recovery is exhausted when an error reaches it.
```ts cordis-catalog
/**
* One drain chain reached its terminal turn: that turn's `turn/end` is
* already committed. Automatically recovered failed turns do not emit this
* notification. `reason` says why; model-request recovery is exhausted when
* an error reaches it.
* @param agent - the agent whose turn closed.
* @param turn - the terminal turn number.
* @param reason - why the terminal turn ended, with live error facts when it failed.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
'agent/idle'(this: Scoped<Agent>, agent: Agent, turn: number, reason: IdleReason): void
```
Types: [Agent](../core-data-structures/core.md) · [IdleReason](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:423`](../../packages/core/agent/src/types.ts)
### `agent/inbox/dequeue` — emit
@@ -117,21 +140,19 @@ The driver claimed one item out of the inbox: a queued item at a turn boundary,
Types: [Agent](../core-data-structures/core.md) · [AgentMessage](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:335`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:306`](../../packages/core/agent/src/types.ts)
### `agent/inbox/discard` — emit
Pending inbox items were dropped without delivering them, so every enqueued id receives exactly one terminal `agent/inbox/dequeue` OR `agent/inbox/discard`. Emitters: `cancel()` without `keepInbox` (after `agent/cancel-requested`, before the abort); a terminal `agent/turn-stop` dropping pending steering (in-turn and on the post-turn late-steering drain); and disposal of any still-pending items (before `agent/status('disposed')`). Fires once per drop with every dropped item.
Pending inbox items were dropped without delivering them, so every enqueued id receives exactly one terminal `agent/inbox/dequeue` OR `agent/inbox/discard`. `cancel()` without `keepInbox`, including disposal, emits this after `agent/cancel-requested` when applicable and before aborting the active work. Fires once per drop with every dropped item.
```ts cordis-catalog
/**
* Pending inbox items were dropped without delivering them, so every
* enqueued id receives exactly one terminal `agent/inbox/dequeue` OR
* `agent/inbox/discard`. Emitters: `cancel()` without `keepInbox` (after
* `agent/cancel-requested`, before the abort); a terminal `agent/turn-stop`
* dropping pending steering (in-turn and on the post-turn late-steering
* drain); and disposal of any still-pending items (before
* `agent/status('disposed')`). Fires once per drop with every dropped item.
* `agent/inbox/discard`. `cancel()` without `keepInbox`, including disposal,
* emits this after `agent/cancel-requested` when applicable and before
* aborting the active work. Fires once per drop with every dropped item.
* @param agent - the agent whose inbox items were dropped.
* @param messages - the discarded messages in FIFO order (queued then steering); never empty.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
@@ -142,21 +163,17 @@ Pending inbox items were dropped without delivering them, so every enqueued id r
Types: [Agent](../core-data-structures/core.md) · [AgentMessage](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:349`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:318`](../../packages/core/agent/src/types.ts)
### `agent/inbox/enqueue` — emit
A detached, frozen item entered the agent's inbox (queued or steering FIFO). Source defaults are already applied, so `message` holds the exact accepted values. This is the enqueue-time live signal; the durable record is the eventual `user/message`/`steering/message`. Injection (`next-step`/no-wakeup) bypasses the FIFOs and does not emit this.
An item entered the queued or steering inbox.
```ts cordis-catalog
/**
* A detached, frozen item entered the agent's inbox (queued or steering
* FIFO). Source defaults are already applied, so `message` holds the exact
* accepted values. This is the enqueue-time live signal; the durable record
* is the eventual `user/message`/`steering/message`. Injection
* (`next-step`/no-wakeup) bypasses the FIFOs and does not emit this.
* @param agent - the agent whose inbox received the item.
* @param message - the accepted message (its returned `id`, content, source, contexts, steering, and wakeup facts).
* An item entered the queued or steering inbox.
* @param agent - the owning agent.
* @param message - accepted content, source, and correlation identity.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode emit
*/
@@ -165,67 +182,17 @@ A detached, frozen item entered the agent's inbox (queued or steering FIFO). Sou
Types: [Agent](../core-data-structures/core.md) · [AgentMessage](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:325`](../../packages/core/agent/src/types.ts)
### `agent/post-step` — serial
Awaited serial checkpoint after the response, real or synthetic tool results, injected context, and steering are durable but before `step/end`. A cancelled tool batch reaches this checkpoint with an aborted signal.
```ts cordis-catalog
/**
* Awaited serial checkpoint after the response, real or synthetic tool
* results, injected context, and steering are durable but before `step/end`.
* A cancelled tool batch reaches this checkpoint with an aborted signal.
* @param agent - the agent whose step is settling.
* @param turn - the open turn number.
* @param step - the open step number.
* @param signal - the turn abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode serial
*/
'agent/post-step'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, signal: AbortSignal): Promise<void> | void
```
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:457`](../../packages/core/agent/src/types.ts)
### `agent/pre-step` — serial
Awaited serial checkpoint before `step/start`; appends land outside the pending step and are included when the loop derives request history. `signal` cancels listener work. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
```ts cordis-catalog
/**
* Awaited serial checkpoint before `step/start`; appends land outside the
* pending step and are included when the loop derives request history.
* `signal` cancels listener work.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @param agent - the agent opening the step.
* @param turn - the open turn number.
* @param step - the pending step number.
* @param signal - the turn abort signal.
* @mode serial
*/
'agent/pre-step'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, signal: AbortSignal): Promise<void> | void
```
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:388`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:296`](../../packages/core/agent/src/types.ts)
### `agent/prompt-submit` — waterfall
Allow, rewrite, or block one claimed prompt before it becomes a user message. Call `next()` for the unchanged default. A listener wrapping a downstream `allow` must preserve its `content` and `additionalContexts` unless it intentionally replaces them. The signal controls only this turn; listeners may cooperate with it but must not retain it to control another turn. Steering messages do not dispatch this event; they join an open turn at a steering checkpoint.
Allow, rewrite, or block one claimed prompt before it becomes a user message. Call `next()` for the unchanged default. The signal controls only this turn; listeners may cooperate with it but must not retain it for another turn.
```ts cordis-catalog
/**
* Allow, rewrite, or block one claimed prompt before it becomes a user
* message. Call `next()` for the unchanged default. A listener wrapping a
* downstream `allow` must preserve its `content` and `additionalContexts`
* unless it intentionally replaces them. The signal controls only this turn;
* listeners may cooperate with it but must not retain it to control another
* turn. Steering messages do not dispatch this event; they join an open turn
* at a steering checkpoint.
* message. Call `next()` for the unchanged default. The signal controls only this turn;
* listeners may cooperate with it but must not retain it for another turn.
* @param agent - the agent whose turn claimed the message.
* @param content - the claimed message's blocks, as queued.
* @param source - the message's resolved source.
@@ -238,84 +205,57 @@ Allow, rewrite, or block one claimed prompt before it becomes a user message. Ca
Types: [Agent](../core-data-structures/core.md) · [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md) · [PromptDecision](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:404`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:355`](../../packages/core/agent/src/types.ts)
### `agent/request` — waterfall
Replace the frozen call configuration. Model-visible content must use logged channels; this seam cannot mutate messages. Injection here joins the next request because the current step boundary is already fixed.
Replace the frozen call configuration. `await next()` yields the config the machine would use (agent options on the first request, the logged header afterwards); return a replacement to switch. Model-visible content must use logged channels; this seam cannot mutate messages.
```ts cordis-catalog
/**
* Replace the frozen call configuration. Model-visible content must use
* logged channels; this seam cannot mutate messages. Injection here joins
* the next request because the current step boundary is already fixed.
* Replace the frozen call configuration. `await next()` yields the config
* the machine would use (agent options on the first request, the logged
* header afterwards); return a replacement to switch. Model-visible
* content must use logged channels; this seam cannot mutate messages.
* @param agent - the agent making the model call.
* @param turn - the open turn number.
* @param step - the step whose request this is.
* @param config - the config the loop would use (frozen); return a replacement to switch.
* @param signal - the current turn's explicit abort signal; ambient
* initiator identity does not imply liveness or cancellation authority.
* @param signal - the current turn's explicit abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode waterfall
*/
'agent/request'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, config: LlmCallConfig, signal: AbortSignal, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>
*/
'agent/request'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, signal: AbortSignal, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>
```
Types: [Agent](../core-data-structures/core.md) · [LlmCallConfig](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:418`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:381`](../../packages/core/agent/src/types.ts)
### `agent/request-error` — waterfall
Recover a model-request failure after its failed step has closed. `retry` opens a new numbered step; `fail` preserves the original request error. Call `next()` to delegate to the next recovery listener or the default.
Handle a model-request failure after its failed step has closed but before the failed turn closes. A listener calls Agent.retry to schedule one retry turn, returns without `next()` when it owns the error, or calls `next()` to delegate. The default leaves the failure terminal.
```ts cordis-catalog
/**
* Recover a model-request failure after its failed step has closed. `retry`
* opens a new numbered step; `fail` preserves the original request error.
* Call `next()` to delegate to the next recovery listener or the default.
* Handle a model-request failure after its failed step has closed but
* before the failed turn closes. A listener calls {@link Agent.retry} to
* schedule one retry turn, returns without `next()` when it owns the error,
* or calls `next()` to delegate. The default leaves the failure terminal.
* @param agent - the agent whose request failed.
* @param turn - the open turn number.
* @param step - the failed step number.
* @param error - the original model-request failure.
* @param failure - serializable facts normalized at the final adapter boundary.
* @param priorFailures - immutable failures that already authorized another request in this consecutive sequence.
* @param signal - the turn abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode waterfall
*/
'agent/request-error'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, error: RequestError, failure: LlmFailure, priorFailures: readonly LlmFailure[], signal: AbortSignal, next: () => Promise<RequestErrorDecision>): Promise<RequestErrorDecision>
'agent/request-error'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, error: RequestError, failure: LlmFailure, signal: AbortSignal, next: () => Promise<void>): Promise<void>
```
Types: [Agent](../core-data-structures/core.md) · [LlmFailure](../core-data-structures/llm-streaming.md) · [RequestError](../core-data-structures/core.md) · [RequestErrorDecision](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Types: [Agent](../core-data-structures/core.md) · [LlmFailure](../core-data-structures/llm-streaming.md) · [RequestError](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:472`](../../packages/core/agent/src/types.ts)
### `agent/session-prefix` — waterfall
Compose request-only messages placed before derived history. The frozen result is computed once per loop instance, logged on its anchoring request header, and reused so the provider prefix remains stable. Interrupted composition is discarded. Composition precedes the first `agent/pre-step` and request boundary, so listener appends join the current request. Changing context belongs in history; contributors should prepend to `await next()` to preserve registration order. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
```ts cordis-catalog
/**
* Compose request-only messages placed before derived history. The frozen
* result is computed once per loop instance, logged on its anchoring request
* header, and reused so the provider prefix remains stable. Interrupted
* composition is discarded. Composition precedes the first `agent/pre-step`
* and request boundary, so listener appends join the current request.
* Changing context belongs in history; contributors should prepend to
* `await next()` to preserve registration order.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @param agent - the agent whose session prefix is being composed.
* @param prefix - the frozen seed; return an extended replacement.
* @param signal - the current turn's explicit abort signal.
* @mode waterfall
*/
'agent/session-prefix'(this: Scoped<Agent>, agent: Agent, prefix: Message[], signal: AbortSignal, next: () => Promise<Message[]>): Promise<Message[]>
```
Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:433`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:396`](../../packages/core/agent/src/types.ts)
### `agent/session-start` — emit
@@ -337,16 +277,16 @@ The session lifecycle began, once before the first turn. Use `agent.inject()` to
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md) · [SessionStartSource](../core-data-structures/core.md)
Source: [`packages/core/agent/src/types.ts:372`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:341`](../../packages/core/agent/src/types.ts)
### `agent/status` — emit
Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does not enter `running` synchronously; drive lifecycle from this event.
Agent status changed (`idle` ⇄ `running`). `send()` does not enter `running` synchronously; drive lifecycle from this event.
```ts cordis-catalog
/**
* Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does
* not enter `running` synchronously; drive lifecycle from this event.
* Agent status changed (`idle` ⇄ `running`). `send()` does not enter
* `running` synchronously; drive lifecycle from this event.
* @param agent - the agent whose status flipped.
* @param status - the status just entered (the transition's destination).
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
@@ -357,74 +297,57 @@ Agent status changed (`idle` ⇄ `running`, or → `disposed`). `send()` does no
Types: [Agent](../core-data-structures/core.md) · [AgentStatus](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:313`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:288`](../../packages/core/agent/src/types.ts)
### `agent/step-result` — waterfall
### `agent/step` — serial
Waterfall: post-process the assembled assistant Message before tool dispatch (validation, content rewriting, …).
Awaited serial checkpoint before EVERY request of a turn is built (the first as well as each post-tools continuation). The single "between steps" seam: inject context, steer, or edit the session log here — the request's history derives from the log right after this settles.
```ts cordis-catalog
/**
* Waterfall: post-process the assembled assistant {@link Message} before
* tool dispatch (validation, content rewriting, …).
* @param agent - the agent that received the step's response.
* Awaited serial checkpoint before EVERY request of a turn is built (the
* first as well as each post-tools continuation). The single "between
* steps" seam: inject context, steer, or edit the session log here — the
* request's history derives from the log right after this settles.
* @param agent - the agent about to send a request.
* @param turn - the open turn number.
* @param step - the step that produced the message.
* @param message - the assistant message as assembled from the stream.
* @param signal - the current turn's explicit abort signal.
* @param step - the step number about to open.
* @param signal - the turn abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode waterfall
* @mode serial
*/
'agent/step-result'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, message: Message, signal: AbortSignal, next: () => Promise<Message>): Promise<Message>
'agent/step'(this: Scoped<Agent>, agent: Agent, turn: number, step: number, signal: AbortSignal): Promise<void> | void
```
Types: [Agent](../core-data-structures/core.md) · [Message](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:445`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:368`](../../packages/core/agent/src/types.ts)
### `agent/turn-continuation` — waterfall
### `agent/stopping` — serial
Override whether the turn continues. The default continues after tool calls or steering and stops otherwise; a continue reason becomes steering.
The turn is about to close: the model owes no response (no live tool calls, no fresh steering). Awaited before the boundary commits — a listener that objects steers (`agent.steer(...)`) and the machine re-reads its inbox: fresh steering runs another step, none closes the turn. Data decides, so listener order cannot change the outcome. The inverse control (stop a tool loop early) is data too: a tool result carrying `concludesTurn` ends the turn at its step.
```ts cordis-catalog
/**
* Override whether the turn continues. The default continues after tool
* calls or steering and stops otherwise; a continue reason becomes steering.
* @param agent - the agent deciding whether to run another step.
* @param turn - the turn being continued or stopped.
* @param defaultDecision - what the loop would do absent an override.
* @param signal - the current turn's explicit abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode waterfall
*/
'agent/turn-continuation'(this: Scoped<Agent>, agent: Agent, turn: number, defaultDecision: ContinuationDecision, signal: AbortSignal, next: () => Promise<ContinuationDecision>): Promise<ContinuationDecision>
```
Types: [Agent](../core-data-structures/core.md) · [ContinuationDecision](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:483`](../../packages/core/agent/src/types.ts)
### `agent/turn-stop` — serial
Monotonic terminal-stop checkpoint after continuation and steering are folded; a stop remains authoritative through turn close and flush: steering queued in that window is discarded, while ordinary sends survive.
```ts cordis-catalog
/**
* Monotonic terminal-stop checkpoint after continuation and steering are
* folded; a stop remains authoritative through turn close and flush:
* steering queued in that window is discarded, while ordinary sends survive.
* @param agent - the agent whose composed continuation outcome may be stopped.
* @param turn - the turn at its terminal-stop checkpoint.
* The turn is about to close: the model owes no response (no live tool
* calls, no fresh steering). Awaited before the boundary commits — a
* listener that objects steers (`agent.steer(...)`) and the machine
* re-reads its inbox: fresh steering runs another step, none closes the
* turn. Data decides, so listener order cannot change the outcome. The
* inverse control (stop a tool loop early) is data too: a tool result
* carrying `concludesTurn` ends the turn at its step.
* @param agent - the agent whose turn is at its stop boundary.
* @param turn - the turn about to close.
* @param signal - the current turn's explicit abort signal.
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
* @mode serial
*/
'agent/turn-stop'(this: Scoped<Agent>, agent: Agent, turn: number, signal: AbortSignal): Promise<ContinuationStop | undefined> | ContinuationStop | undefined
'agent/stopping'(this: Scoped<Agent>, agent: Agent, turn: number, signal: AbortSignal): Promise<void> | void
```
Types: [Agent](../core-data-structures/core.md) · [ContinuationStop](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Types: [Agent](../core-data-structures/core.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/core/agent/src/types.ts:494`](../../packages/core/agent/src/types.ts)
Source: [`packages/core/agent/src/types.ts:411`](../../packages/core/agent/src/types.ts)
## `agent-loop/*`
@@ -447,7 +370,7 @@ A declarative agent entry failed before it could publish a live agent. Consumers
Types: [SessionId](../core-data-structures/core.md)
Source: [`packages/core/agent-loop/src/index.ts:353`](../../packages/core/agent-loop/src/index.ts)
Source: [`packages/core/agent-loop/src/index.ts:140`](../../packages/core/agent-loop/src/index.ts)
## `approval/*`
@@ -570,7 +493,7 @@ Goal mutation accepted by one live agent. The matching context event is already
Types: [Agent](../core-data-structures/core.md) · [GoalChanged](../core-data-structures/goal.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/goal/goal/src/types.ts:167`](../../packages/goal/goal/src/types.ts)
Source: [`packages/goal/goal/src/types.ts:169`](../../packages/goal/goal/src/types.ts)
## `llm/*`
@@ -620,7 +543,7 @@ Creation announcement during session publication. A synchronous throw vetoes and
Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
Source: [`packages/core/session/src/index.ts:79`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:70`](../../packages/core/session/src/index.ts)
### `session/disposed` — emit
@@ -641,7 +564,7 @@ Emitted once when an announced session leaves the store, including publication r
Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md)
Source: [`packages/core/session/src/index.ts:89`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:80`](../../packages/core/session/src/index.ts)
### `session/event` — emit
@@ -664,7 +587,7 @@ Post-commit, fire-and-forget append feed. The listener snapshot resolves before
Types: [Scoped](../core-data-structures/scope.md) · [Session](../core-data-structures/session.md) · [SessionEvent](../core-data-structures/core.md)
Source: [`packages/core/session/src/index.ts:101`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:92`](../../packages/core/session/src/index.ts)
### `session/flush` — parallel
@@ -685,7 +608,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:111`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:102`](../../packages/core/session/src/index.ts)
## `subagent/*`

View File

@@ -27,7 +27,7 @@ create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd
/**
* Create an owned agent on a caller-supplied session id.
* @param ownerCtx - caller context that structurally owns the transaction.
* @param ownerCtx - caller context that structurally owns the lifecycle.
* @param options - identities, session seed/metadata, loop options, setup, and cancellation.
* @returns the published handle.
*/
@@ -44,7 +44,7 @@ async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandl
Types: [Agent](../core-data-structures/core.md) · [AgentOptions](../core-data-structures/core.md) · [SessionHeader](../core-data-structures/persistence.md) · [SessionId](../core-data-structures/core.md)
Source: [`packages/core/agent-loop/src/index.ts:398`](../../packages/core/agent-loop/src/index.ts)
Source: [`packages/core/agent-loop/src/index.ts:188`](../../packages/core/agent-loop/src/index.ts)
## `ctx.agents` — `AgentRegistry`
@@ -216,7 +216,7 @@ roots(): Agent[]
Types: [Agent](../core-data-structures/core.md) · [SessionId](../core-data-structures/core.md)
Source: [`packages/core/agent/src/index.ts:225`](../../packages/core/agent/src/index.ts)
Source: [`packages/core/agent/src/index.ts:221`](../../packages/core/agent/src/index.ts)
## `ctx.approval` — `ApprovalService`
@@ -612,7 +612,7 @@ clear(agent: Agent, ref: GoalRef): GoalRef
Types: [Agent](../core-data-structures/core.md) · [CreateGoalRequest](../core-data-structures/goal.md) · [EditGoalRequest](../core-data-structures/goal.md) · [GoalBlockReason](../core-data-structures/goal.md) · [GoalRef](../core-data-structures/goal.md) · [GoalView](../core-data-structures/goal.md)
Source: [`packages/goal/goal/src/index.ts:135`](../../packages/goal/goal/src/index.ts)
Source: [`packages/goal/goal/src/index.ts:134`](../../packages/goal/goal/src/index.ts)
## `ctx.invariants` — `InvariantService`
@@ -1090,7 +1090,7 @@ async listCandidates( agent: Agent, query = '', limit = this.config.candidateLim
* @param content - already host-normalized readable message content.
* @param references - structured source sessions in mention order.
* @param signal - optional cancellation boundary for host request teardown.
* @returns detached content and zero or one prepared contexts.
* @returns detached content and optional referenced-session context.
*/
async prepare( agent: Agent, content: ContentBlock[], references: SessionReferenceInput[], signal?: AbortSignal, ): Promise<PreparedReferencedMessage>
```
@@ -1246,7 +1246,7 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId):
Types: [CreateSessionOptions](../core-data-structures/persistence.md) · [OutOfBandSessionEventType](../core-data-structures/session.md) · [Session](../core-data-structures/session.md) · [SessionEvent](../core-data-structures/core.md) · [SessionEventMap](../core-data-structures/session.md) · [SessionId](../core-data-structures/core.md) · [TurnTrigger](../core-data-structures/session.md)
Source: [`packages/core/session/src/index.ts:604`](../../packages/core/session/src/index.ts)
Source: [`packages/core/session/src/index.ts:593`](../../packages/core/session/src/index.ts)
## `ctx.sessionTitle` — `SessionTitleService`
@@ -1280,7 +1280,7 @@ register(provider: SessionTitleProvider): () => Promise<void>
Types: [Session](../core-data-structures/session.md) · [SessionTitleProvider](../core-data-structures/session-title.md) · [SessionTitleSnapshot](../core-data-structures/session-title.md)
Source: [`packages/session-title/session-title/src/index.ts:284`](../../packages/session-title/session-title/src/index.ts)
Source: [`packages/session-title/session-title/src/index.ts:283`](../../packages/session-title/session-title/src/index.ts)
## `ctx.skills` — `SkillService`
@@ -1686,7 +1686,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md)
Source: [`packages/core/tools/src/index.ts:634`](../../packages/core/tools/src/index.ts)
Source: [`packages/core/tools/src/index.ts:639`](../../packages/core/tools/src/index.ts)
## `ctx.tui` — `TuiExtensionService` (abstract seam)
@@ -1709,7 +1709,7 @@ The concrete provider retains pi-tui, focus, and terminal lifecycle state. Plugi
abstract openOverlay(request: TuiOverlayRequest): TuiOverlaySession
```
Source: [`packages/ui/tui/src/index.ts:150`](../../packages/ui/tui/src/index.ts)
Source: [`packages/ui/tui/src/index.ts:148`](../../packages/ui/tui/src/index.ts)
## `ctx.userInteraction` — `UserInteractionService`