Merge remote-tracking branch 'origin/master' into cross-family-fs-sandbox
# Conflicts: # .agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.i18n.yaml # .agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md # .agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.zh.md # docs/capability-seams.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/event-producer-consumer.md # docs/module-graph.md # docs/persistence-catalog.md # docs/rfc/INDEX.md # examples/acp-agent/README.md # examples/acp-agent/fs.cordis.snapshot.yml # examples/acp-agent/fs.cordis.yml # examples/acp-agent/tests/snapshots/escalation-approved/session.jsonl # examples/acp-agent/tests/snapshots/escalation-rejected/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl # examples/acp-agent/tests/snapshots/permission-switching/session.jsonl # examples/acp-agent/tests/snapshots/workspace-context/system-prompt.expected.md # examples/acp-agent/tests/snapshots/workspace-context/tool-schemas.expected.json # examples/acp-agent/tests/snapshots/workspace-edit/system-prompt.expected.md # examples/acp-agent/tests/snapshots/workspace-edit/tool-schemas.expected.json # packages/bash/bash/src/index.ts # packages/bash/tool-bash/package.json # packages/bash/tool-bash/src/index.ts # packages/bash/tool-bash/tests/tools.spec.ts # packages/cordis/tool-cordis/src/api-catalog.ts # packages/fs/README.md # packages/fs/tool-fs/src/edit.ts # packages/fs/tool-fs/src/write.ts # packages/sandbox/README.md # pnpm-lock.yaml
This commit is contained in:
@@ -1,13 +1,85 @@
|
||||
<!-- Generated by scripts/gen-persistence-catalog.ts — do not edit by hand.
|
||||
Run `pnpm run gen-persistence-catalog` to regenerate. -->
|
||||
|
||||
# Persistence Log Event Catalog
|
||||
# Session Persistence Event Catalog
|
||||
|
||||
Every event type that can appear in a session's durable event log: each member of the merge-extensible `SessionEventMap` — the owning vocabulary in `@deepseek-ai/dsh-session` plus every plugin declaration merge in this repo — with the payload it carries, its surface badge, and the declaration it comes from. It complements [session.md](core-data-structures/session.md) (the `SessionEvent` envelope, surface list, and `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).
|
||||
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).
|
||||
|
||||
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. Payload blocks use a `ts persistence-catalog` fence (skipped by doc-typecheck, since a bare payload fragment is not standalone-compilable). Type names in a payload link to the page that documents them. See [the persistence-log-catalog RFC](rfc/implemented/process/2026-07-04-persistence-log-catalog.md).
|
||||
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/implemented/process/2026-07-04-persistence-log-catalog.md).
|
||||
|
||||
The on-disk envelope around every payload is `SessionEvent` — `type`, monotonic `seq`, epoch-ms `time`, the `data` documented here, plus `surfaceOp`/`sourceEventSeqs` on **surface** events only ([envelope](core-data-structures/session.md#sessioneventt--one-log-entry)). **surface** marks a `SurfaceEventType` member: it produces an LLM message and declares how it joins the surface list. **log-only** marks everything else: 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.
|
||||
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'
|
||||
| 'context/message'
|
||||
| 'steering/message'
|
||||
|
||||
/**
|
||||
* How a session event entered the ordered surface. Only valid on
|
||||
* {@link SurfaceEventType} events.
|
||||
*
|
||||
* - `'append'`: added to the tail — normal path for user/assistant/tool/context
|
||||
* 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`,
|
||||
* `assistant/message`, `tool/result`, `context/message`, `steering/message`).
|
||||
* 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]
|
||||
```
|
||||
|
||||
Sources: [`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:262`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:292`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:324`](../packages/core/session/src/types.ts)
|
||||
|
||||
## Events
|
||||
|
||||
@@ -15,10 +87,21 @@ The on-disk envelope around every payload is `SessionEvent` — `type`, monotoni
|
||||
|
||||
#### `approval/asked` — log-only
|
||||
|
||||
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).
|
||||
|
||||
```ts persistence-catalog
|
||||
'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: CallId; reason?: string }
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
```
|
||||
|
||||
Types: [CallId](core-data-structures/core.md)
|
||||
@@ -27,19 +110,31 @@ Source: [`packages/ui/user-approval/src/index.ts:45`](../packages/ui/user-approv
|
||||
|
||||
#### `approval/decided` — log-only
|
||||
|
||||
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'`.
|
||||
|
||||
```ts persistence-catalog
|
||||
'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome }
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/ui/user-approval/src/index.ts:56`](../packages/ui/user-approval/src/index.ts)
|
||||
|
||||
#### `approval/policy` — log-only
|
||||
|
||||
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 event is the session's override (effectiveApprovalPolicy); who asked for it is derivable from position (an event after the log's last `request/header*` was a runtime switch by the user).
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* 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
|
||||
* event is the session's override ({@link effectiveApprovalPolicy});
|
||||
* who asked for it is derivable from position (an event after the log's
|
||||
* last `request/header` was a runtime switch by the user).
|
||||
*/
|
||||
'approval/policy': { policy: ApprovalPolicy }
|
||||
```
|
||||
|
||||
@@ -49,45 +144,46 @@ Source: [`packages/ui/user-approval/src/index.ts:68`](../packages/ui/user-approv
|
||||
|
||||
#### `assistant/chunk` — log-only
|
||||
|
||||
Raw stream chunk — token-level replay fidelity.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Raw stream chunk — token-level replay fidelity. */
|
||||
'assistant/chunk': { turn: number; step: number; chunk: StreamChunk }
|
||||
```
|
||||
|
||||
Types: [StreamChunk](core-data-structures/llm-streaming.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:242`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:219`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `assistant/message` — surface
|
||||
|
||||
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.
|
||||
|
||||
```ts persistence-catalog
|
||||
'assistant/message': { turn: number; step: number; content: ContentBlock[]; usage?: TokenUsage }
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
'assistant/message': { turn: number; step: number; content: ContentBlock[]; provenance: AssistantProvenance; usage?: TokenUsage }
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md) · [TokenUsage](core-data-structures/llm-streaming.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:249`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:226`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `compact/*`
|
||||
|
||||
#### `compact/end` — log-only
|
||||
|
||||
Marks the end of a compaction — log-only, releases the lock. `error` set if summarization failed.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Marks the end of a compaction — log-only, releases the lock. `error` set if summarization failed. */
|
||||
'compact/end': { turn: number; error?: string }
|
||||
```
|
||||
|
||||
Source: [`packages/compact/compact/src/types.ts:38`](../packages/compact/compact/src/types.ts)
|
||||
Source: [`packages/compact/compact/src/types.ts:40`](../packages/compact/compact/src/types.ts)
|
||||
|
||||
#### `compact/start` — log-only
|
||||
|
||||
Marks the start of a compaction — log-only, holds the lock until `compact/end`.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Marks the start of a compaction — log-only, holds the lock until `compact/end`. */
|
||||
'compact/start': { turn: number }
|
||||
```
|
||||
|
||||
@@ -95,10 +191,30 @@ Source: [`packages/compact/compact/src/types.ts:15`](../packages/compact/compact
|
||||
|
||||
#### `compact/summary` — log-only
|
||||
|
||||
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.
|
||||
|
||||
```ts persistence-catalog
|
||||
'compact/summary': { summary: ContentBlock[]; shadowedRange: { start: number; end: number }; shadowedSeqs: number[]; shadowedTokenCount: number; model: string; maxTokens?: number }
|
||||
/**
|
||||
* 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[]
|
||||
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
|
||||
* this summary" has a durable answer (the reconstructability Agent Note).
|
||||
*/
|
||||
model: string
|
||||
/** The generation cap the summarize call sent, when one applied. */
|
||||
maxTokens?: number
|
||||
}
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md)
|
||||
@@ -109,34 +225,68 @@ Source: [`packages/compact/compact/src/types.ts:22`](../packages/compact/compact
|
||||
|
||||
#### `context/message` — surface
|
||||
|
||||
In-session context injection (file-change notices, subdir AGENTS.md, skill content, cron notifications, …). Rendered into the derived history as tagged synthetic context — NOT a user prompt.
|
||||
|
||||
```ts persistence-catalog
|
||||
'context/message': { content: ContentBlock[]; source: MessageSource }
|
||||
/**
|
||||
* In-session context injection (file-change notices, subdir AGENTS.md,
|
||||
* skill content, cron notifications, …). Rendered into the derived history
|
||||
* as synthetic context — NOT a user prompt. `envelope: 'raw'` lets a caller
|
||||
* own the complete model-facing frame; `meta` is durable JSON state omitted
|
||||
* from the model projection.
|
||||
*/
|
||||
'context/message': {
|
||||
content: ContentBlock[]
|
||||
source: MessageSource
|
||||
envelope?: ContextEnvelope
|
||||
meta?: JsonValue
|
||||
}
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:240`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:212`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `hook/*`
|
||||
|
||||
#### `hook/invoked` — log-only
|
||||
|
||||
A hook command was invoked at a hook point — log-only provenance (like `compact/*`; NOT a 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.
|
||||
|
||||
```ts persistence-catalog
|
||||
'hook/invoked': { turn: number; point: string; dialect: HookDialect; matcher?: string; handlerId: string }
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/hooks/hook-protocol/src/types.ts:19`](../packages/hooks/hook-protocol/src/types.ts)
|
||||
|
||||
#### `hook/result` — log-only
|
||||
|
||||
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.
|
||||
|
||||
```ts persistence-catalog
|
||||
'hook/result': { turn: number; point: string; handlerId: string; decision: string; exitCode?: number; stderrSummary?: string; durationMs: number }
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook-protocol/src/types.ts)
|
||||
@@ -145,9 +295,13 @@ Source: [`packages/hooks/hook-protocol/src/types.ts:31`](../packages/hooks/hook-
|
||||
|
||||
#### `permission/preset` — log-only
|
||||
|
||||
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 effectivePermissionPreset preserve a selection when bundles match.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
'permission/preset': { preset: string }
|
||||
```
|
||||
|
||||
@@ -157,45 +311,45 @@ Source: [`packages/ui/permission/src/index.ts:36`](../packages/ui/permission/src
|
||||
|
||||
#### `prompt/blocked` — log-only
|
||||
|
||||
Durable record of a prompt veto and its reason. It is log-only: the blocked prompt never enters the model-visible surface, including in a mixed batch.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* Durable record of a prompt veto and its reason. It is log-only: the blocked
|
||||
* prompt never enters the model-visible surface, including in a mixed batch.
|
||||
*/
|
||||
'prompt/blocked': { content: ContentBlock[]; source: MessageSource; reason: string }
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:234`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:204`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `request/*`
|
||||
|
||||
#### `request/header` — log-only
|
||||
|
||||
Full EpochHeader for the next request, appended inside its step before dispatch. It is log-only and anchors subsequent deltas.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* Full header for the next request, appended inside its step before dispatch.
|
||||
* It is log-only; the latest snapshot reconstructs the request header.
|
||||
*/
|
||||
'request/header': { header: EpochHeader; reason: RequestHeaderReason }
|
||||
```
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:277`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `request/header-delta` — log-only
|
||||
|
||||
Log-only amendment to the folded EpochHeader. System and tools use their delta codecs; config and prefix replace whole, with an empty prefix encoding removal. Writers verify round-trip equality or log a fallback snapshot.
|
||||
|
||||
```ts persistence-catalog
|
||||
'request/header-delta': { system?: SystemDelta; tools?: ToolsDelta; config?: LlmCallConfig; messagePrefix?: Message[] }
|
||||
```
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:283`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:251`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `sandbox/*`
|
||||
|
||||
#### `sandbox/mode` — log-only
|
||||
|
||||
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 override (effectiveSandboxMode); who asked for it is derivable from position (an event after the log's last `request/header*` was a runtime switch by the user; see the tool layer's narrator).
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* 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
|
||||
* override ({@link effectiveSandboxMode}); who asked for it is derivable
|
||||
* from position (an event after the log's last `request/header*` was a
|
||||
* runtime switch by the user; see the tool layer's narrator).
|
||||
*/
|
||||
'sandbox/mode': { mode: SandboxMode }
|
||||
```
|
||||
|
||||
@@ -205,126 +359,151 @@ Source: [`packages/sandbox/sandbox-policy/src/session-mode.ts:34`](../packages/s
|
||||
|
||||
#### `steering/message` — surface
|
||||
|
||||
Steering content injected between steps of a running turn.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Steering content injected between steps of a running turn. */
|
||||
'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource }
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:267`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:244`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `step/*`
|
||||
|
||||
#### `step/end` — log-only
|
||||
|
||||
Closes step `step` of turn `turn`.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Closes step `step` of turn `turn`. */
|
||||
'step/end': { turn: number; step: number }
|
||||
```
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:227`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:197`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `step/start` — log-only
|
||||
|
||||
Opens step `step` of turn `turn` — one model call plus the tool executions it requested.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Opens step `step` of turn `turn` — one model call plus the tool executions it requested. */
|
||||
'step/start': { turn: number; step: number }
|
||||
```
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:225`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:195`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `todo/*`
|
||||
|
||||
#### `todo/write` — log-only
|
||||
|
||||
Whole-list snapshot; the latest write wins on replay. It is log-only UI state and never enters derived model history.
|
||||
|
||||
```ts persistence-catalog
|
||||
/** Whole-list snapshot; latest write wins on replay. Log-only UI state; never derived history. */
|
||||
'todo/write': { todos: TodoItem[] }
|
||||
```
|
||||
|
||||
Types: [TodoItem](core-data-structures/session.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:272`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:246`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `tool/*`
|
||||
|
||||
#### `tool/call` — log-only
|
||||
|
||||
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`.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* 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`.
|
||||
*/
|
||||
'tool/call': { turn: number; step: number; callId: CallId; name: string; arguments: string }
|
||||
```
|
||||
|
||||
Types: [CallId](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:232`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `tool/code-dispatch` — log-only
|
||||
|
||||
One bridged sub-dispatch from a `run_code` program: the parent `run_code` call id, the deterministic sub-call id (`<parent>:code:<n>`), the tool `name` with its JSON-normalized `arguments` — the exact value dispatched, normalized before dispatch, so this append can never fail on payload shape — whether the sub-call errored, and a bounded `resultSummary` of its model-facing text.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* One bridged sub-dispatch from a `run_code` program: the parent
|
||||
* `run_code` call id, the deterministic sub-call id
|
||||
* (`<parent>:code:<n>`), the tool `name` with its JSON-normalized
|
||||
* `arguments` — the exact value dispatched, normalized BEFORE dispatch,
|
||||
* so this append can never fail on payload shape — whether the sub-call
|
||||
* errored, and a bounded `resultSummary` of its model-facing text. Before
|
||||
* bounding, occurrences of a non-root session workspace path are
|
||||
* normalized to `.` so host-specific absolute path lengths cannot change
|
||||
* the summary.
|
||||
* Log-only: `deriveMessages()` ignores it, so sub-calls never re-enter
|
||||
* model context; persistence and UIs get every call. Appended inside the
|
||||
* parent `run_code`'s execution (the bridge drains its queue before
|
||||
* returning), so the turn-enclosure invariant holds by construction.
|
||||
*/
|
||||
'tool/code-dispatch': { parentCallId: CallId; subCallId: CallId; name: string; arguments: unknown; isError: boolean; resultSummary: string }
|
||||
```
|
||||
|
||||
Types: [CallId](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/tools/src/code-mode.ts:25`](../packages/core/tools/src/code-mode.ts)
|
||||
Source: [`packages/core/tools/src/code-mode.ts:34`](../packages/core/tools/src/code-mode.ts)
|
||||
|
||||
#### `tool/result` — surface
|
||||
|
||||
A completed tool call's model-facing result, plus an optional tool-private `meta` presentation payload. `meta` is opaque to the core (`unknown` — 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 unless the tool attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here).
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* A completed tool call's model-facing result, plus an optional tool-private
|
||||
* `meta` presentation payload. `meta` is opaque to the core (`unknown` — 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 unless the tool
|
||||
* attaches one (e.g. `dsh-tool-fs` carries its result-time contextual diff here).
|
||||
*/
|
||||
'tool/result': { turn: number; step: number; callId: CallId; content: ContentBlock[]; isError: boolean; error?: { name: string; code: string }; meta?: unknown }
|
||||
```
|
||||
|
||||
Types: [CallId](core-data-structures/core.md) · [ContentBlock](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:265`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:242`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `turn/*`
|
||||
|
||||
#### `turn/end` — log-only
|
||||
|
||||
Closes turn `turn` with the TurnEndReason that ended it. The loop fires the awaited `session/flush` checkpoint at every turn end, so the turn boundary is also the durable-commit boundary.
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* Closes turn `turn` with the {@link TurnEndReason} that ended it. The loop
|
||||
* fires the awaited `session/flush` checkpoint at every turn end, so the turn
|
||||
* boundary is also the durable-commit boundary.
|
||||
*/
|
||||
'turn/end': { turn: number; reason: TurnEndReason }
|
||||
```
|
||||
|
||||
Types: [TurnEndReason](core-data-structures/session.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:223`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:193`](../packages/core/session/src/types.ts)
|
||||
|
||||
#### `turn/start` — log-only
|
||||
|
||||
Opens turn `turn`. `trigger` records what started it — a drained message batch or an idle-time injection. The turn is the durability/replay boundary: every event sits between a `turn/start` and its matching `turn/end` (the turn-enclosure invariant).
|
||||
|
||||
```ts persistence-catalog
|
||||
/**
|
||||
* Opens turn `turn`. `trigger` records what started it — a drained message
|
||||
* batch or an idle-time injection. The turn is the durability/replay
|
||||
* boundary: every event sits between a `turn/start` and its matching
|
||||
* `turn/end` (the turn-enclosure invariant).
|
||||
*/
|
||||
'turn/start': { turn: number; trigger: TurnTrigger }
|
||||
```
|
||||
|
||||
Types: [TurnTrigger](core-data-structures/session.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:217`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:187`](../packages/core/session/src/types.ts)
|
||||
|
||||
### `user/*`
|
||||
|
||||
#### `user/message` — surface
|
||||
|
||||
A user-visible prompt (queued message drained at turn start).
|
||||
|
||||
```ts persistence-catalog
|
||||
/** A user-visible prompt (queued message drained at turn start). */
|
||||
'user/message': { content: ContentBlock[]; source: MessageSource }
|
||||
```
|
||||
|
||||
Types: [ContentBlock](core-data-structures/core.md) · [MessageSource](core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/core/session/src/types.ts:229`](../packages/core/session/src/types.ts)
|
||||
Source: [`packages/core/session/src/types.ts:199`](../packages/core/session/src/types.ts)
|
||||
|
||||
Reference in New Issue
Block a user