ctx.tools.register(definition, { when }) adds a synchronous or asynchronous
condition. AgentLoop resolves conditions once per proposed step with the
agent, the model selection that step preparation captured, and the turn
signal, before prompt assembly and agent/pre-step. The resulting
ResolvedToolSet governs tool declarations, Native dispatch, PTC bindings,
and nested calls for that step and its retries, and the turn disposes it
when the proposal is rejected or fails, when no step opens, and after the
step. A false condition removes the tool everywhere; a thrown condition
ends the turn with TOOL_ACTIVATION_FAILED. Calls whose registration was
replaced or removed during the step return UNKNOWN_TOOL.
system-prompt/assemble now transforms PromptPresentation without a tool
array, so tool declarations stay provider-owned. exit_plan_mode is declared
only for steps whose selected plan state is active, the same state that
renders plan guidance; it still rejects a call before the selection is
logged.
Model selection stays as master defines it; this change adds no model
selection event or Agent field.
94 lines
5.6 KiB
Markdown
94 lines
5.6 KiB
Markdown
<!-- Generated by scripts/gen-doc-graphs.ts - do not edit by hand.
|
|
Run `pnpm run gen-doc-graphs` to regenerate. -->
|
|
|
|
# Agent Turn And Step Lifecycle
|
|
|
|
This sequence is the visual companion to [architecture.md](architecture.md#turn-flow). It keeps durable replay facts on `session/event` and live control/status on `agent/*`.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Agent
|
|
participant Driver
|
|
participant Hooks as hook listeners
|
|
participant Prompt as ctx.systemPrompt
|
|
participant LLM as ctx.llm
|
|
participant Tools as ctx.tools
|
|
participant Session
|
|
participant SDK as UI or SDK listener
|
|
User->>Agent: followup(content)
|
|
Agent-->>SDK: <code>agent/inbox/spliced</code>
|
|
Agent-->>SDK: <code>agent/inbox/inserted</code> { message }
|
|
Agent->>Driver: queued work wakes driver
|
|
Driver-->>SDK: <code>agent/status</code> running
|
|
Driver->>Session: <code>turn/start</code>
|
|
Note over Agent,Driver: claim pending next-step input plus one queued prompt
|
|
Driver-->>SDK: <code>agent/inbox/spliced</code> pure deletion
|
|
Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
|
|
Driver->>Tools: resolve({ agent, modelSelection, signal }) once per proposed step
|
|
Driver->>Prompt: <code>system-prompt/assemble</code> waterfall with the step tool set
|
|
Driver->>Hooks: <code>agent/pre-step</code> waterfall
|
|
Hooks-->>Driver: authoritative reject or enter(messages)
|
|
alt proposed step rejected, first batch empty, or pre-step failed
|
|
Driver-->>Driver: claimed batch stays removed, the open turn spends no step
|
|
else enter proposed step
|
|
Driver->>Session: <code>step/start</code>
|
|
Driver->>Hooks: <code>agent/request</code> waterfall
|
|
Driver->>LLM: prepareCall(config, signal)
|
|
Note over Driver,LLM: cancellation during either async phase commits neither system nor users
|
|
Note over Driver,Session: synchronous admission using the prepared call capability
|
|
Driver->>Session: <code>system/message</code> ordered per-node reconciliation
|
|
Driver->>Session: <code>user/message</code> per entered message
|
|
Driver->>Session: <code>request/header</code> and <code>request/context</code> as needed
|
|
Driver->>Driver: derive and freeze request from the log
|
|
Driver->>LLM: bound prepared call through <code>llm/stream</code> waterfall
|
|
LLM-->>Driver: StreamChunk*
|
|
Driver-->>SDK: <code>agent/assistant-stream</code> chunk*
|
|
alt final adapter or terminal in-band request failure
|
|
Driver->>Session: <code>assistant/attempt</code>
|
|
Driver-->>SDK: <code>agent/assistant-stream</code> committed end
|
|
Driver->>Hooks: <code>agent/request-error</code> waterfall
|
|
Hooks-->>Driver: return retry action or preserve the original error
|
|
Note over Driver,LLM: retry in the open step: prepare and reconcile the same rendered assembly without repeating pre-step or users
|
|
else model request succeeded
|
|
Driver->>Session: <code>assistant/message</code>
|
|
Driver-->>SDK: <code>agent/assistant-stream</code> committed end
|
|
Driver->>Tools: classify pending call by executionMode
|
|
loop barriers and bounded rolling pool, reclassify before start
|
|
opt call starts
|
|
Driver->>Session: <code>tool/call</code>
|
|
Driver->>Tools: ordered pre, concurrent execute
|
|
Tools-->>Session: tool-owned events when applicable
|
|
end
|
|
opt next model-order result ready
|
|
Driver->>Tools: ordered post
|
|
Driver->>Session: <code>tool/result</code>
|
|
end
|
|
end
|
|
Driver->>Session: <code>step/end</code>
|
|
Driver->>Tools: dispose the step tool set
|
|
opt natural stop and next-step inbox empty
|
|
Driver->>Hooks: <code>agent/turn-stopping</code> serial terminal checkpoint
|
|
end
|
|
opt next-step input is pending
|
|
Driver-->>Driver: claim pending next-step input
|
|
Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
|
|
Driver->>Hooks: <code>agent/pre-step</code> waterfall
|
|
Hooks-->>Driver: authoritative reject or enter(messages)
|
|
end
|
|
end
|
|
end
|
|
Driver->>Session: <code>turn/end</code>
|
|
Driver-->>SDK: <code>agent/status</code> idle
|
|
```
|
|
|
|
The `assistant/message` event records every successful provider call, including content-less and `max-tokens` finishes, and embeds the exact compact timed stream. Empty content stays out of derived history. A failed, retried, cancelled, or stream-error attempt that reaches settlement without a surface message records its stream as `assistant/attempt`. Live `agent/assistant-stream` chunk frames are transient; replay reads either durable settlement, and a hard process loss before settlement leaves no durable attempt stream.
|
|
|
|
`dsh-compaction-basic` uses `agent/pre-step` for pressure before request derivation and `agent/request-error` only for canonical context overflow. Once either trigger qualifies, optional tool-result pruning runs before summary selection. Recovery runs within the open step and retries only when pruning or summarization advances the surface replacement generation; otherwise the original request error remains authoritative. Each retry prepares its call and reconciles the retained rendered assembly before request derivation, without repeating assembly, pre-step, or user admission.
|
|
|
|
The returned `agent/pre-step` decision is authoritative; listeners wrapping `next()` preserve downstream messages and `startsRequestSeries` unless replacement is intentional. Steering and injected context pass through the same waterfall after a later claim operation takes their next-step batch.
|
|
|
|
SDK users that need replayable transcript data should consume `session/event`; `agent/*` is the live coordination API for queue/status, prompt interception, request construction, steering, continuation, and errors.
|
|
|
|
Maintenance mode: curated Mermaid sequence; exact event signatures live in the generated Cordis catalog.
|