diff --git a/docs/core-data-structures/session.md b/docs/core-data-structures/session.md index fc461e7f49..1e1d6da87c 100644 --- a/docs/core-data-structures/session.md +++ b/docs/core-data-structures/session.md @@ -36,20 +36,17 @@ interface SessionEventMap { /** Steering content injected between steps of a running turn. */ 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } /** - * The agent's whole todo list, replaced wholesale on each write - * (last-write-wins on replay — the current list is the last `todo/write`). - * Written by the `todo_write` tool via - * `agent.session.append('todo/write', { todos })`. + * 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 {@link SurfaceEventType}: it produces no LLM message and never reaches - * `deriveMessages()` — it is durable, replayable UI state. The full snapshot - * travels each time, so a resume re-derives the current list from the last - * event with no fold. UIs render off `session/event`: the stdio UI prints the - * list; the ACP bridge maps it to a `plan` sessionUpdate. This is a - * `SessionEventMap` member (it rides the existing `session/event` emit), not a - * first-class `interface Events` notification, so the cordis catalog gains no - * row for it. - * @mode emit + * `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. */ 'todo/write': { todos: TodoItem[] } } @@ -57,7 +54,7 @@ interface SessionEventMap { ### `TodoItem` — one todo-list entry -The unit of the `todo_write` tool's whole-list state. Deliberately minimal — a `content` line and a three-state `status` (no id, priority, or `activeForm`): the list is replaced wholesale on every write, so entries need no stable identity, and the status triple is exactly the ACP `PlanEntryStatus`, so the ACP bridge maps a todo list to a `plan` update 1:1 (synthesizing the priority ACP additionally requires). +The unit of the `todo/write` event's whole-list snapshot. Deliberately minimal — a `content` line and a three-state `status` (no id, priority, or `activeForm`): the list is replaced wholesale on every write, so entries need no stable identity, and the status triple is exactly the ACP `PlanEntryStatus`, so a UI bridge can map a todo list onto an ACP `plan` 1:1 (synthesizing the priority ACP additionally requires). ```ts type-equiv export interface TodoItem { diff --git a/packages/core/session/src/types.ts b/packages/core/session/src/types.ts index 57b0e3a7c8..581fc29df1 100644 --- a/packages/core/session/src/types.ts +++ b/packages/core/session/src/types.ts @@ -150,14 +150,14 @@ export interface TurnEndReasonMap { export type TurnEndReason = TurnEndReasonMap[keyof TurnEndReasonMap] /** - * One entry in an agent's todo list — the unit of the `todo_write` tool's - * whole-list state (the `todo/write` {@link SessionEventMap} event). + * One entry in an agent's todo list — the unit of the `todo/write` + * {@link SessionEventMap} event's whole-list snapshot. * * Deliberately minimal: a human-readable `content` line and a three-state * `status`. No id, priority, or `activeForm` — the list is replaced wholesale * on every write (last-write-wins), so entries need no stable identity, and the - * status triple is exactly the ACP `PlanEntryStatus` (so the ACP bridge maps a - * todo list to a `plan` update 1:1, synthesizing the priority ACP additionally + * status triple is exactly the ACP `PlanEntryStatus`, so a UI bridge can map a + * todo list onto an ACP `plan` 1:1 (synthesizing the priority ACP additionally * requires). */ export interface TodoItem { @@ -213,20 +213,17 @@ export interface SessionEventMap { /** Steering content injected between steps of a running turn. */ 'steering/message': { turn: number; content: ContentBlock[]; source: MessageSource } /** - * The agent's whole todo list, replaced wholesale on each write - * (last-write-wins on replay — the current list is the last `todo/write`). - * Written by the `todo_write` tool via - * `agent.session.append('todo/write', { todos })`. + * 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 {@link SurfaceEventType}: it produces no LLM message and never reaches - * `deriveMessages()` — it is durable, replayable UI state. The full snapshot - * travels each time, so a resume re-derives the current list from the last - * event with no fold. UIs render off `session/event`: the stdio UI prints the - * list; the ACP bridge maps it to a `plan` sessionUpdate. This is a - * `SessionEventMap` member (it rides the existing `session/event` emit), not a - * first-class `interface Events` notification, so the cordis catalog gains no - * row for it. - * @mode emit + * `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. */ 'todo/write': { todos: TodoItem[] } }