2026-07-04 22:58:28 +08:00
<!-- Generated by scripts/gen-persistence-catalog.ts — do not edit by hand.
Run `pnpm run gen-persistence-catalog` to regenerate. -->
2026-07-18 15:11:51 +08:00
# Session Persistence Event Catalog
2026-07-04 22:58:28 +08:00
2026-07-18 15:11:51 +08:00
Every event type that can appear in a session's durable event log: the complete persisted `SessionEvent` envelope and each member of the merge-extensible `SessionEventMap` — the owning vocabulary in `@deepseek-ai/dsh-session` plus every plugin declaration merge in this repo — with source JSDoc, full payload declaration, surface badge, and declaration site. It complements [session.md ](core-data-structures/session.md ) (surface ordering and the `deriveMessages()` projection), [persistence.md ](core-data-structures/persistence.md ) (how the log is made durable), and the [cordis events catalog ](cordis-catalog/events.md ) (the live bus wiring — a log event is NOT a cordis event; it reaches listeners via the single `session/event` emit).
2026-07-04 22:58:28 +08:00
2026-07-27 23:56:18 +08:00
This file is GENERATED from source (`scripts/gen-persistence-catalog.ts` ) and verified fresh by `pnpm run verify-persistence-catalog` (part of `doc-sync` ) — do not edit it by hand. Declaration blocks retain the source declaration and nested property JSDoc, removing only the indentation imposed by a containing interface/module, and use a `ts persistence-catalog` fence (skipped by doc-typecheck because declarations reference types from their owning modules). Type names in a payload link to the page that documents them. See [the persistence-log-catalog Agent Note ](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md ).
2026-07-04 22:58:28 +08:00
2026-07-18 15:11:51 +08:00
The envelope declarations below compose each event's `type` , monotonic `seq` , epoch-ms `time` , `data` , and the conditional `surfaceOp` /`sourceEventSeqs` fields. **surface ** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only ** marks everything else: a durable, replayable record with no derived-history contribution. Every payload is JSON-serializable (enforced at `Session.append` ), and the whole format is pinned at `SESSION_FORMAT_VERSION = 0` — pre-release, no compatibility implied ([the version stance ](core-data-structures/persistence.md )). Scope: the packages in this repo; a downstream plugin can merge further event types, which are outside this catalog by construction.
## Event envelope
```ts persistence-catalog
/** The appendable event-type keys of {@link SessionEventMap}, plugin-merged extensions included. */
export type SessionEventType = keyof SessionEventMap
/**
* The subset of {@link SessionEventType} values whose events produce LLM
* messages and are eligible to appear on the ordered surface. Only these
* event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}.
*/
export type SurfaceEventType =
| 'user/message'
| 'assistant/message'
| 'tool/result'
| 'steering/message'
/**
* How a session event entered the ordered surface. Only valid on
* {@link SurfaceEventType} events.
*
2026-07-23 19:15:45 +08:00
* - ` 'append'`: added to the tail — normal path for user/assistant/tool/steering
2026-07-18 15:11:51 +08:00
* messages.
* - ` { op: 'replace', start, end }`: replaces surface nodes from ` start`
* (inclusive) through ` end` (inclusive) with this node. Both must exist as
* surface nodes in the current surface. ` start === end` replaces a single
* node. The node's {@link SessionEvent.sourceEventSeqs} must include every
* shadowed surface node. Used by compaction and possible other manipulations.
*/
export type SurfaceOp =
| 'append'
| { op: 'replace'; start: number; end: number }
/**
* One immutable entry in the session log.
*
* A proper discriminated union over ` type` (not independent ` type`/` data`
* unions), so ` switch (event.type)` narrows ` event.data` without casts.
*
* The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional:
* they only exist on {@link SurfaceEventType} variants (` user/message`,
2026-07-23 19:15:45 +08:00
* ` assistant/message`, ` tool/result`, ` steering/message`).
2026-07-18 15:11:51 +08:00
* Non-surface events (boundary markers, chunks, usage, errors) never carry
* surface metadata — the compiler enforces this at ` Session.append()`
* call sites.
*/
export type SessionEvent<T extends SessionEventType = SessionEventType> = {
[K in SessionEventType]: {
type: K
/** Monotonic sequence number within the session. */
seq: number
/** Unix epoch milliseconds. */
time: number
data: SessionEventMap[K]
} & (K extends SurfaceEventType ? {
/**
* Seq numbers of events that are provenance sources of this event
* (e.g. the ` assistant/chunk` seqs that built an ` assistant/message`,
* or the surface nodes shadowed by a compaction replace node). An
* ` assistant/message` may carry a present empty array for a known empty
* provider stream; omission means unrecorded provenance.
*/
sourceEventSeqs?: number[]
/** How this event entered the surface; absent for non-surface events. */
surfaceOp?: SurfaceOp
} : object)
}[T]
` ``
2026-07-31 13:24:30 +08:00
Sources: [` packages/core/session/src/types.ts:284`](../packages/core/session/src/types.ts) · [` packages/core/session/src/types.ts:291`](../packages/core/session/src/types.ts) · [` packages/core/session/src/types.ts:320`](../packages/core/session/src/types.ts) · [` packages/core/session/src/types.ts:352`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
## Events
2026-07-09 15:25:18 +08:00
### ` approval/*`
#### ` approval/asked` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* An approval question was put to the answerer chain — log-only audit
* (like ` hook/*`; NOT a surface event, carries no ` surfaceOp`). ` id` pairs
* it with the ` approval/decided` that always follows; ` toolName` is the
* tool the question is about, ` callId` the exact tool call when the asker
* had one, ` reason` the asker's human-readable explanation (e.g. a hook's
* permission-decision reason).
*/
'approval/asked': {
id: ApprovalRequestId
toolName: string
callId?: CallId
reason?: string
}
2026-07-09 15:25:18 +08:00
` ``
Types: [CallId](core-data-structures/core.md)
2026-07-28 23:55:00 +08:00
Source: [` packages/ui/user-approval/src/index.ts:44`](../packages/ui/user-approval/src/index.ts)
2026-07-09 15:25:18 +08:00
#### ` approval/decided` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* The outcome of a prior ` approval/asked` (same ` id`) — log-only audit.
* Exactly one per ask, appended when the outcome is known: a decision, a
* cancellation, or the fail-closed ` 'unavailable'`.
*/
'approval/decided': {
id: ApprovalRequestId
outcome: ApprovalOutcome
}
2026-07-09 15:25:18 +08:00
` ``
2026-07-28 23:55:00 +08:00
Source: [` packages/ui/user-approval/src/index.ts:55`](../packages/ui/user-approval/src/index.ts)
2026-07-09 16:41:03 +08:00
#### ` approval/policy` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* The session's approval policy was switched — log-only, durable,
* replayable, never in the model transcript (the model learns the policy
* from the prompt section and the narrator's notices). The LAST such
2026-07-28 21:31:17 +08:00
* event is the session's override ({@link effectiveApprovalPolicy}).
* ` source: 'delegation'` marks an override seeded into a child; an absent
* source is a runtime switch.
2026-07-18 15:11:51 +08:00
*/
2026-07-28 21:31:17 +08:00
'approval/policy': {
policy: ApprovalPolicy
/** Marks an override seeded into a child at delegation. */
source?: 'delegation'
}
2026-07-09 16:41:03 +08:00
` ``
2026-07-28 23:55:00 +08:00
Source: [` packages/ui/user-approval/src/index.ts:67`](../packages/ui/user-approval/src/index.ts)
2026-07-09 15:25:18 +08:00
2026-07-04 22:58:28 +08:00
### ` assistant/*`
#### ` assistant/chunk` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Raw stream chunk — token-level replay fidelity. */
2026-07-04 22:58:28 +08:00
'assistant/chunk': { turn: number; step: number; chunk: StreamChunk }
` ``
2026-07-06 22:26:06 +08:00
Types: [StreamChunk](core-data-structures/llm-streaming.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:215`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` assistant/message` — surface
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Assembled assistant message for one step (derived history uses this).
* Carries the step's ` usage` when the adapter reported token accounting, so
* the model output and its accounting travel together (there is no separate
* usage record). ` usage` is absent when the adapter reported none.
*/
2026-07-28 13:55:59 +08:00
'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage }
2026-07-04 22:58:28 +08:00
` ``
2026-07-28 13:55:59 +08:00
Types: [TokenUsage](core-data-structures/llm-streaming.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:222`](../packages/core/session/src/types.ts)
2026-07-09 16:41:03 +08:00
2026-07-28 01:09:55 +08:00
### ` command/*`
#### ` command/done` — log-only
` ``ts persistence-catalog
/**
* The paired command settled. ` kind`/` text` carry the handler's verbatim
* outcome (a thrown/aborted handler settles as ` kind: 'error'` with the
* rendered failure); presentation stays client-computed at render time.
*/
2026-07-28 10:54:35 +08:00
'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string }
2026-07-28 01:09:55 +08:00
` ``
2026-07-28 16:50:07 +08:00
Source: [` packages/ui/commands/src/index.ts:138`](../packages/ui/commands/src/index.ts)
2026-07-28 01:09:55 +08:00
#### ` command/run` — log-only
` ``ts persistence-catalog
/**
* A resolved slash command entered its handler. Log-only (never model
* surface); paired with ` command/done` by ` commandId`, mirroring the
* ` tool/call`↔` tool/result` pairing. The payload is structured — ` name`
* and ` args` are ` parseCommand`'s own split (name and verbatim rawInput,
* separator whitespace included), so a consumer (a projection unit
* folding its own command records, a rich command card) never re-parses
* a line.
*/
2026-07-28 10:54:35 +08:00
'command/run': { commandId: CommandId; name: string; args: string; source: CommandSource }
2026-07-28 01:09:55 +08:00
` ``
2026-07-28 16:50:07 +08:00
Source: [` packages/ui/commands/src/index.ts:132`](../packages/ui/commands/src/index.ts)
2026-07-09 16:41:03 +08:00
2026-07-04 22:58:28 +08:00
### ` compact/*`
#### ` compact/end` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Marks the end of a compaction — log-only, releases the lock. ` error` set if summarization failed. */
2026-07-04 22:58:28 +08:00
'compact/end': { turn: number; error?: string }
` ``
2026-07-28 10:28:25 +08:00
Source: [` packages/compact/compact/src/types.ts:44`](../packages/compact/compact/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` compact/start` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Marks the start of a compaction — log-only, holds the lock until ` compact/end`. */
2026-07-04 22:58:28 +08:00
'compact/start': { turn: number }
` ``
2026-07-13 23:27:00 +08:00
Source: [` packages/compact/compact/src/types.ts:15`](../packages/compact/compact/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` compact/summary` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Provenance record of a completed summarization — log-only, no surfaceOp.
* The summary content is in ` data.summary`; the actual surface replacement
* is performed by a subsequent ` user/message` event that shadows the
* compacted range.
*/
'compact/summary': {
summary: ContentBlock[]
2026-07-28 10:28:25 +08:00
/** Complete provider output before the backend's safe summary projection. */
rawOutput?: ContentBlock[]
2026-07-18 15:11:51 +08:00
shadowedRange: { start: number; end: number }
shadowedSeqs: number[]
shadowedTokenCount: number
/** The provider route that wrote the summary. */
provider: string
/**
* The model that wrote the summary — the summarize call's envelope,
* reported by the backend that made the call, logged so the one-shot
* request is reconstructable from log + code and "which model wrote
2026-07-19 22:50:49 +08:00
* this summary" has a durable answer (the reconstructability Agent Note).
2026-07-18 15:11:51 +08:00
*/
model: string
/** The generation cap the summarize call sent, when one applied. */
maxTokens?: number
2026-07-28 10:28:25 +08:00
/** Provider-reported token usage for the summarization request, when emitted. */
usage?: TokenUsage
2026-07-18 15:11:51 +08:00
}
2026-07-04 22:58:28 +08:00
` ``
2026-07-28 10:28:25 +08:00
Types: [ContentBlock](core-data-structures/core.md) · [TokenUsage](core-data-structures/llm-streaming.md)
2026-07-04 22:58:28 +08:00
2026-07-13 23:27:00 +08:00
Source: [` packages/compact/compact/src/types.ts:22`](../packages/compact/compact/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` hook/*`
#### ` hook/invoked` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* A hook command was invoked at a hook point — log-only provenance (like
* ` compact/*`; NOT a {@link SurfaceEventType}, carries no ` surfaceOp`).
* ` dialect` is the bridge that ran it (` claude`/` codex`), ` point`
* the hook point (` PreToolUse`, ` Stop`, …), ` matcher` the matcher-group
* pattern that selected it (absent for match-all), ` handlerId` a stable id
* for the command (so an invoked/result pair correlates). ` turn` is the open
* turn the invocation lives inside.
*/
'hook/invoked': {
turn: number
point: string
dialect: HookDialect
matcher?: string
handlerId: string
}
2026-07-04 22:58:28 +08:00
` ``
2026-07-12 03:36:43 +08:00
Source: [` packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` hook/result` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Log-only outcome paired to ` hook/invoked` by ` handlerId`. Decision is the
* parsed permission result, ` stop` for ` continue:false`, or ` pass`; exit code
* may be absent, stderr is bounded, and duration is wall-clock runtime.
*/
'hook/result': {
turn: number
point: string
handlerId: string
decision: string
exitCode?: number
stderrSummary?: string
durationMs: number
}
2026-07-04 22:58:28 +08:00
` ``
2026-07-13 23:27:00 +08:00
Source: [` packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook-protocol/src/types.ts)
2026-07-04 22:58:28 +08:00
2026-07-20 03:34:19 +08:00
### ` llm/*`
#### ` llm/retry` — log-only
` ``ts persistence-catalog
2026-07-25 10:18:16 +08:00
/** Durable, non-surface record of one provider-routed retry scheduled after a closed failed step. */
2026-07-20 03:34:19 +08:00
'llm/retry': {
turn: number
step: number
2026-07-25 10:18:16 +08:00
provider: string
mode: 'normal'
2026-07-25 15:38:58 +08:00
policyKey: string
2026-07-20 03:34:19 +08:00
retry: number
maxRetries: number
delayMs: number
failure: LlmFailure
2026-07-25 10:18:16 +08:00
} | {
turn: number
step: number
provider: string
mode: 'always'
2026-07-25 15:38:58 +08:00
policyKey: string
2026-07-25 10:18:16 +08:00
retry: number
delayMs: number
failure: LlmFailure
2026-07-20 03:34:19 +08:00
}
` ``
Source: [` packages/llm/llm-retry/src/index.ts:18`](../packages/llm/llm-retry/src/index.ts)
2026-07-12 21:03:41 +08:00
### ` permission/*`
#### ` permission/preset` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Records the selected preset as durable, log-only user intent. The knob
* events follow in the same turn and control execution; this event stays
* out of the model transcript and lets {@link effectivePermissionPreset}
* preserve a selection when bundles match.
*/
2026-07-12 21:03:41 +08:00
'permission/preset': { preset: string }
` ``
2026-07-31 12:48:19 +08:00
Source: [` packages/ui/permission/src/index.ts:50`](../packages/ui/permission/src/index.ts)
2026-07-12 21:03:41 +08:00
2026-07-22 16:57:23 +08:00
### ` plan/*`
#### ` plan/mode` — log-only
` ``ts persistence-catalog
/**
* Whether plan mode is in force from this point on: log-only, non-surface,
* whole-value replace. The last ` plan/mode` wins; a log with none folds to
* inactive through {@link foldPlanMode}.
*/
'plan/mode': { active: boolean }
` ``
2026-07-28 21:46:48 +08:00
Source: [` packages/plan/plan-mode/src/index.ts:51`](../packages/plan/plan-mode/src/index.ts)
2026-07-22 16:57:23 +08:00
2026-07-06 02:42:51 +08:00
### ` request/*`
#### ` request/header` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Full header for the next request, appended inside its step before dispatch.
* It is log-only; the latest snapshot reconstructs the request header.
*/
2026-07-06 02:42:51 +08:00
'request/header': { header: EpochHeader; reason: RequestHeaderReason }
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
2026-07-14 20:05:57 +08:00
### ` sandbox/*`
#### ` sandbox/mode` — log-only
` ``ts persistence-catalog
2026-07-20 11:40:29 +08:00
/**
* The session's sandbox mode was switched — log-only (like ` approval/*`;
* NOT a surface event, carries no ` surfaceOp`): durable and replayable,
* never in the model transcript. The LAST such event is the session's
2026-07-28 21:31:17 +08:00
* override ({@link effectiveSandboxMode}). ` source: 'delegation'` marks
* an override seeded into a child; an absent source is a runtime switch.
2026-07-20 11:40:29 +08:00
*/
2026-07-28 21:31:17 +08:00
'sandbox/mode': {
mode: SandboxMode
/** Marks an override seeded into a child at delegation. */
source?: 'delegation'
}
2026-07-14 20:05:57 +08:00
` ``
2026-07-28 21:31:17 +08:00
Source: [` packages/sandbox/sandbox-policy/src/session-mode.ts:33`](../packages/sandbox/sandbox-policy/src/session-mode.ts)
2026-07-04 22:58:28 +08:00
2026-07-21 01:54:00 +08:00
### ` session/*`
2026-07-30 15:32:06 +08:00
#### ` session/end-seed` — log-only
2026-07-30 11:38:51 +08:00
` ``ts persistence-catalog
/**
2026-07-30 15:32:06 +08:00
* Marks the end of a constructor seed. Events before it have smaller seq
* values and came from the seed (resume, fork, or replay); this lifecycle
2026-07-31 13:24:30 +08:00
* produced none of them. An explicitly supplied empty seed puts the marker
* at seq 0, distinguishing an empty resumed session from a fresh session.
* This log-only event is the durable projection of
2026-07-30 15:32:06 +08:00
* {@link Session.firstLiveSeq}. Its payload is empty — position and ` time`
* carry the meaning.
2026-07-30 11:38:51 +08:00
*
2026-07-30 15:32:06 +08:00
* Locate the LAST one in stored history. A seed already ending in one is not
* re-marked, so reopening an untouched session does not grow its log per
* pickup and the event need not be at the current ` firstLiveSeq`.
2026-07-30 13:59:08 +08:00
*
2026-07-30 14:46:38 +08:00
* ` Session`'s constructor is the only legitimate writer. The invariant
* companion deliberately constrains nothing here, so a plugin appending one
2026-07-30 15:32:06 +08:00
* would silently classify every live bracket before it as seed history.
2026-07-30 14:46:38 +08:00
*
2026-07-30 12:01:45 +08:00
* An owner of a standalone open/close bracket (` compact/start` …
2026-07-30 15:32:06 +08:00
* ` compact/end`) reads it because seed history and live work are otherwise
* byte-identical: an unmatched opening marker before this event belongs to
* an ended lifecycle, whatever ended it. NOT a liveness signal about other
* writers — a concurrently live session holds its own boundary elsewhere,
* so tolerating concurrent writers needs a signal beyond the log.
2026-07-30 11:38:51 +08:00
*/
2026-07-30 15:32:06 +08:00
'session/end-seed': Record<string, never>
2026-07-30 11:38:51 +08:00
` ``
2026-07-31 13:24:30 +08:00
Source: [` packages/core/session/src/types.ts:280`](../packages/core/session/src/types.ts)
2026-07-30 11:38:51 +08:00
2026-07-21 01:54:00 +08:00
#### ` session/title` — log-only
` ``ts persistence-catalog
/**
* Latest-wins session title snapshot. Log-only: it never enters the model
* surface or derived history.
*/
'session/title': SessionTitleEventData
` ``
Types: [SessionTitleEventData](core-data-structures/session-title.md)
2026-07-29 18:59:09 +08:00
Source: [` packages/session-title/session-title/src/index.ts:100`](../packages/session-title/session-title/src/index.ts)
2026-07-21 01:54:00 +08:00
2026-07-21 12:08:00 +08:00
#### ` session/title-llm-request` — log-only
` ``ts persistence-catalog
/** Log-only pre-dispatch record of one session-title model request. */
'session/title-llm-request': SessionTitleLlmRequestEventData
` ``
Types: [SessionTitleLlmRequestEventData](core-data-structures/session-title.md)
2026-07-28 14:41:51 +08:00
Source: [` packages/session-title/session-title-llm/src/index.ts:43`](../packages/session-title/session-title-llm/src/index.ts)
2026-07-21 12:08:00 +08:00
2026-07-04 22:58:28 +08:00
### ` steering/*`
#### ` steering/message` — surface
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Steering content injected between steps of a running turn. */
2026-07-28 13:55:59 +08:00
'steering/message': { turn: number; message: UserMessage }
2026-07-04 22:58:28 +08:00
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:248`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` step/*`
#### ` step/end` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Closes step ` step` of turn ` turn`. */
2026-07-04 22:58:28 +08:00
'step/end': { turn: number; step: number }
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:204`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` step/start` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Opens step ` step` of turn ` turn` — one model call plus the tool executions it requested. */
2026-07-04 22:58:28 +08:00
'step/start': { turn: number; step: number }
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:202`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` todo/*`
#### ` todo/write` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */
2026-07-04 22:58:28 +08:00
'todo/write': { todos: TodoItem[] }
` ``
2026-07-06 22:26:06 +08:00
Types: [TodoItem](core-data-structures/session.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:250`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` tool/*`
#### ` tool/call` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* The model requested one tool invocation: ` name` with the raw ` arguments`
* JSON string exactly as the model produced it (unparsed). ` callId` pairs the
* call with its ` tool/result`.
*/
2026-07-04 22:58:28 +08:00
'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string }
` ``
2026-07-06 22:26:06 +08:00
Types: [CallId](core-data-structures/core.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:228`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
2026-07-08 12:58:23 +08:00
#### ` tool/code-dispatch` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
2026-07-26 06:02:36 +08:00
* One bridged sub-dispatch SETTLING: the pairing ids (matching the
* ` tool/code-dispatch-start` with the same ` subCallId`), the tool ` name`
* with the same JSON-normalized ` arguments`, and the sub-call's complete
* model-facing outcome in ` tool/result`'s own vocabulary
2026-07-26 02:43:34 +08:00
* (` content` + ` isError`), so UIs render a sub-call through the exact
2026-07-26 06:02:36 +08:00
* code path that renders a native call. Every started sub-call settles
* with exactly one of these (abort included: the aborted pipeline result
* is an ` isError` outcome).
2026-07-18 15:11:51 +08:00
* Log-only: ` deriveMessages()` ignores it, so sub-calls never re-enter
* model context; persistence and UIs get every call. Appended inside the
2026-07-26 06:02:36 +08:00
* parent ` run_code`'s execution (the bridge drains in-flight dispatches
2026-07-28 14:41:51 +08:00
* before returning), so its execution-enclosure relation holds by
2026-07-26 06:02:36 +08:00
* construction.
2026-07-18 15:11:51 +08:00
*/
2026-07-26 02:43:34 +08:00
'tool/code-dispatch': { parentCallId: CallId; subCallId: CallId; name: string; arguments: unknown; isError: boolean; content: ContentBlock[] }
2026-07-08 12:58:23 +08:00
` ``
2026-07-26 02:43:34 +08:00
Types: [CallId](core-data-structures/core.md) · [ContentBlock](core-data-structures/core.md)
2026-07-08 12:58:23 +08:00
2026-07-26 13:24:34 +08:00
Source: [` packages/core/tools/src/code-mode.ts:49`](../packages/core/tools/src/code-mode.ts)
2026-07-26 06:02:36 +08:00
#### ` tool/code-dispatch-start` — log-only
` ``ts persistence-catalog
/**
* One sub-dispatch STARTING inside a ` run_code` program: the parent
* ` run_code` call id, the deterministic sub-call id (` <parent>:code:<n>`,
* numbered in submission order), and the tool ` name` with its
* JSON-normalized ` arguments` — the exact value dispatched, normalized
* BEFORE dispatch, so this append can never fail on payload shape.
* Appended when the scheduler actually starts the call (not at
* submission), so a start means the tool body pipeline was entered; a
* call abandoned in the queue logs nothing. Log-only: ` deriveMessages()`
* ignores it; UIs use it for live per-sub-call running state and pair it
* with ` tool/code-dispatch` by ` subCallId` (timing = the two events'
* ` time` fields).
2026-07-18 15:11:51 +08:00
*/
2026-07-26 06:02:36 +08:00
'tool/code-dispatch-start': { parentCallId: CallId; subCallId: CallId; name: string; arguments: unknown }
2026-07-08 12:58:23 +08:00
` ``
Types: [CallId](core-data-structures/core.md)
2026-07-26 13:24:34 +08:00
Source: [` packages/core/tools/src/code-mode.ts:33`](../packages/core/tools/src/code-mode.ts)
2026-07-08 12:58:23 +08:00
2026-07-04 22:58:28 +08:00
#### ` tool/result` — surface
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
2026-07-21 18:03:01 +08:00
* A completed tool call's model-facing result, optional internal failure
* identity, and optional tool-private ` meta` presentation payload. ` meta` is
* opaque to the core (the producing tool owns its shape and reads it back in
* ` presentResult`) but MUST be JSON-serializable: ` Session.append`
* runtime-validates all event data with ` isJsonValue`, so a non-serializable
* ` meta` is rejected at the source, and the durable log reproduces the
* identical card on replay. Absent
2026-07-21 03:08:35 +08:00
* unless the tool attaches one (e.g. ` dsh-tool-fs` carries its result-time
* contextual diff here).
2026-07-18 15:11:51 +08:00
*/
2026-07-21 03:08:35 +08:00
'tool/result': {
turn: number
step: number
2026-07-28 13:55:59 +08:00
message: ToolResultMessage
2026-07-21 18:03:01 +08:00
error?: { name: string; code: string }
2026-07-21 03:08:35 +08:00
meta?: JsonValue
}
2026-07-04 22:58:28 +08:00
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:240`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` turn/*`
#### ` turn/end` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
* Closes turn ` turn` with the {@link TurnEndReason} that ended it. The loop
2026-07-20 11:53:49 +08:00
* awaits ` session/flush` after an ordinary turn ends before claiming the next
* queued item. Success commits the turn; rejection is reported live and does
* not prevent later work.
2026-07-18 15:11:51 +08:00
*/
2026-07-04 22:58:28 +08:00
'turn/end': { turn: number; reason: TurnEndReason }
` ``
2026-07-06 22:26:06 +08:00
Types: [TurnEndReason](core-data-structures/session.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:200`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
#### ` turn/start` — log-only
` ``ts persistence-catalog
2026-07-18 15:11:51 +08:00
/**
2026-07-26 14:29:30 +08:00
* Opens turn ` turn`. ` trigger` records what started the model loop.
2026-07-18 15:11:51 +08:00
*/
2026-07-04 22:58:28 +08:00
'turn/start': { turn: number; trigger: TurnTrigger }
` ``
2026-07-06 22:26:06 +08:00
Types: [TurnTrigger](core-data-structures/session.md)
2026-07-04 22:58:28 +08:00
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:193`](../packages/core/session/src/types.ts)
2026-07-04 22:58:28 +08:00
### ` user/*`
#### ` user/message` — surface
` ``ts persistence-catalog
2026-07-23 19:15:45 +08:00
/**
* A user-role message on the model-visible surface: a direct human prompt
* (the queued message claimed for this turn), a synthetic ` agent.inject()`
* context (file-change notices, subdir AGENTS.md, skill content, cron
* notifications, …), or an admitted goal continuation round. All three
2026-07-26 14:29:30 +08:00
* project their ` content` verbatim; ` source` tells them apart. An idle
* injection may append this event between turns without running the model.
2026-07-23 19:15:45 +08:00
*/
2026-07-28 13:55:59 +08:00
'user/message': UserMessage
2026-07-04 22:58:28 +08:00
` ``
2026-07-30 21:49:58 +08:00
Source: [` packages/core/session/src/types.ts:213`](../packages/core/session/src/types.ts)