docs/persistence-catalog/log-events.md enumerates every SessionEventMap member — the owning dsh-session vocabulary plus the dsh-compact and dsh-hook-protocol declaration merges — with payload, surface/log-only badge, JSDoc prose, and declaration site. scripts/gen-persistence-catalog.ts is a pure AST pass in the gen-cordis-catalog mold: verify-persistence-catalog (--check) joins doc-sync, so a stale committed catalog fails pre-push and CI. The walk enforces JSDoc completeness (every member needs description prose; @mode is rejected as a category error — log events do not dispatch on the cordis bus), derives the surface badge from the SurfaceEventType union with a stale-member cross-check, and hard-errors on duplicate declarations. Payloads render through the TypeScript printer so newline-separated multi-line type literals still emit valid one-line fragments. Documented the five previously JSDoc-less core events (turn/step boundaries, tool/call), removed the two stray @mode tags on the hook/* merges, and replaced the hand-restated event enumerations (session.md hook/* table, compact README table, hook-protocol README bullets, session README name-list — whose merge note had already drifted) with links to the catalog. RFC: docs/rfc/implemented/process/2026-07-04-persistence-log-catalog.md.
241 lines
12 KiB
Markdown
241 lines
12 KiB
Markdown
<!-- Generated by scripts/gen-persistence-catalog.ts — do not edit by hand.
|
|
Run `pnpm run gen-persistence-catalog` to regenerate. -->
|
|
|
|
# Persistence Log 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 catalog](../cordis-catalog/events-and-services.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).
|
|
|
|
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.
|
|
|
|
## Events
|
|
|
|
### `assistant/*`
|
|
|
|
#### `assistant/chunk` — log-only
|
|
|
|
Raw stream chunk — token-level replay fidelity.
|
|
|
|
```ts persistence-catalog
|
|
'assistant/chunk': { turn: number; step: number; chunk: StreamChunk }
|
|
```
|
|
|
|
Types: [StreamChunk](../core-data-structures/llm-streaming.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:238`](../../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 }
|
|
```
|
|
|
|
Types: [ContentBlock](../core-data-structures/core.md) · [TokenUsage](../core-data-structures/llm-streaming.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:245`](../../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
|
|
'compact/end': { turn: number; error?: string }
|
|
```
|
|
|
|
Source: [`packages/compact/compact/src/types.ts:37`](../../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
|
|
'compact/start': { turn: number }
|
|
```
|
|
|
|
Source: [`packages/compact/compact/src/types.ts:23`](../../packages/compact/compact/src/types.ts)
|
|
|
|
#### `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 }
|
|
```
|
|
|
|
Types: [ContentBlock](../core-data-structures/core.md)
|
|
|
|
Source: [`packages/compact/compact/src/types.ts:30`](../../packages/compact/compact/src/types.ts)
|
|
|
|
### `context/*`
|
|
|
|
#### `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 }
|
|
```
|
|
|
|
Types: [ContentBlock](../core-data-structures/core.md) · [MessageSource](../core-data-structures/core.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:236`](../../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`/`native`), `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 }
|
|
```
|
|
|
|
Source: [`packages/hooks/hook-protocol/src/types.ts:27`](../../packages/hooks/hook-protocol/src/types.ts)
|
|
|
|
#### `hook/result` — log-only
|
|
|
|
A hook command's outcome — log-only, paired with a prior `hook/invoked` (same `handlerId`). `decision` is the resolved dialect-neutral outcome the bridge mapped it to (`allow`/`deny`/`ask`/`block`/`continue`/`stop`/`pass`), `exitCode` the process exit (absent if it never ran), `stderrSummary` a truncated stderr (the block reason source on exit 2), `durationMs` the wall time. `turn` matches the `hook/invoked`.
|
|
|
|
```ts persistence-catalog
|
|
'hook/result': { turn: number; point: string; handlerId: string; decision: string; exitCode?: number; stderrSummary?: string; durationMs: number }
|
|
```
|
|
|
|
Source: [`packages/hooks/hook-protocol/src/types.ts:42`](../../packages/hooks/hook-protocol/src/types.ts)
|
|
|
|
### `prompt/*`
|
|
|
|
#### `prompt/blocked` — log-only
|
|
|
|
A queued prompt an `agent/prompt-submit` listener VETOED — the durable record of a blocked prompt and why. Appended in place of the `user/message` the prompt would have become, so the block survives replay even in a MIXED batch where another queued prompt is allowed (there the turn does not end `rejected`, so the boundary reason alone would not preserve it). `content` is the original prompt the listener rejected; `reason` is the veto text (PromptDecision `block.reason`). NOT a SurfaceEventType: a blocked prompt produces no LLM message and never reaches `deriveMessages()`.
|
|
|
|
```ts persistence-catalog
|
|
'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:230`](../../packages/core/session/src/types.ts)
|
|
|
|
### `steering/*`
|
|
|
|
#### `steering/message` — surface
|
|
|
|
Steering content injected between steps of a running turn.
|
|
|
|
```ts persistence-catalog
|
|
'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:263`](../../packages/core/session/src/types.ts)
|
|
|
|
### `step/*`
|
|
|
|
#### `step/end` — log-only
|
|
|
|
Closes step `step` of turn `turn`.
|
|
|
|
```ts persistence-catalog
|
|
'step/end': { turn: number; step: number }
|
|
```
|
|
|
|
Source: [`packages/core/session/src/types.ts:217`](../../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
|
|
'step/start': { turn: number; step: number }
|
|
```
|
|
|
|
Source: [`packages/core/session/src/types.ts:215`](../../packages/core/session/src/types.ts)
|
|
|
|
### `todo/*`
|
|
|
|
#### `todo/write` — log-only
|
|
|
|
The agent's whole todo list, carried as a full snapshot and replaced wholesale on each write — the current list is the most recent `todo/write` (last-write-wins on replay, no fold). Appended by an owning agent via `session.append('todo/write', { todos })`.
|
|
|
|
NOT a SurfaceEventType: it produces no LLM message and never reaches `deriveMessages()`, so it carries no `surfaceOp` and stays off the surface — it is durable, replayable UI state, distinct from the conversation history. It is a `SessionEventMap` member riding the existing `session/event` emit, not a first-class Cordis `interface Events` notification, so it has no cordis-catalog row.
|
|
|
|
```ts persistence-catalog
|
|
'todo/write': { todos: TodoItem[] }
|
|
```
|
|
|
|
Types: [TodoItem](../core-data-structures/session.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:277`](../../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
|
|
'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:251`](../../packages/core/session/src/types.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
|
|
'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:261`](../../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
|
|
'turn/end': { turn: number; reason: TurnEndReason }
|
|
```
|
|
|
|
Types: [TurnEndReason](../core-data-structures/session.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:213`](../../packages/core/session/src/types.ts)
|
|
|
|
#### `turn/start` — log-only
|
|
|
|
Opens turn `turn`. `trigger` records what started it — a drained message batch, a continuation, 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
|
|
'turn/start': { turn: number; trigger: TurnTrigger }
|
|
```
|
|
|
|
Types: [TurnTrigger](../core-data-structures/session.md)
|
|
|
|
Source: [`packages/core/session/src/types.ts:207`](../../packages/core/session/src/types.ts)
|
|
|
|
### `user/*`
|
|
|
|
#### `user/message` — surface
|
|
|
|
A user-visible prompt (queued message drained at turn start).
|
|
|
|
```ts persistence-catalog
|
|
'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:219`](../../packages/core/session/src/types.ts)
|