Skip to content

Type Alias: AgentDocumentCommand

agentmux


agentmux / agent-document-store / AgentDocumentCommand

AgentDocumentCommand = { at: number; type: "SessionStart"; } | { at: number; type: "SessionEnd"; } | { nodes: DocumentNode[]; type: "HistoryLoaded"; } | { fromSnapshot: true; nodes: DocumentNode[]; type: "HistoryRestored"; } | { newNodes: DocumentNode[]; type: "StreamFlush"; updatedNodes: DocumentNode[]; } | { chunk: ToolLogChunk; toolId: string; type: "ToolChunkAppend"; } | { node: ShellNode; type: "ShellNodeCreate"; } | { chunk: ToolLogChunk; shellId: string; type: "ShellChunkAppend"; } | { exitCode?: number; exitedAt: number; shellId: string; status: ShellNode["status"]; type: "ShellStatusUpdate"; } | { reason: string; type: "StreamTruncate"; } | { type: "UserClear"; } | { at: number; scope?: "tools-only"; type: "ScrubOrphanedInProgress"; } | { nodeId: string; type: "ForceCancelToolNode"; } | { keepIds?: ReadonlySet<string>; keepTurns: number; maxFinishedBytes?: number; pinned: boolean; type: "RollOff"; visibleIds: ReadonlySet<string>; } | { keepIds: ReadonlySet<string>; type: "UnloadToolResults"; } | { nodeId: string; result: ToolResult; type: "ResultLoaded"; }

Defined in: agent-document/types.ts:66

Hooks emit these. The reducer decides what to do based on current state + invariants.

{ at: number; type: "SessionStart"; }

Hook signal: live stream subscription is up.


{ at: number; type: "SessionEnd"; }

Hook signal: subscription torn down (cleanup).


{ nodes: DocumentNode[]; type: "HistoryLoaded"; }

Persisted history (older messages from blockfile) — prepended.


{ fromSnapshot: true; nodes: DocumentNode[]; type: "HistoryRestored"; }

Restore from a snapshot file (output.state.json). Semantically identical to HistoryLoaded (prepend with id-dedup), with one additional effect: sessionPhase jumps directly to "active" because the snapshot represents the full pre-close history — there is no further history to page in.

Why prepend (not full-replace): useAgentStream may dispatch StreamFlush during the async snapshot read window. A full replace would wipe those live arrivals. Existing nodes (live arrivals) win on id collision; the snapshot version is dropped.

fromSnapshot: true is a discriminator field per spec §4.5 — the view layer reads it from the audit event (history-restored) to distinguish snapshot restore from partial HistoryLoaded prepend.

Spec: docs/specs/SPEC_AGENT_PANE_STATE_PERSISTENCE_2026_05_15.md §4.5.


{ newNodes: DocumentNode[]; type: "StreamFlush"; updatedNodes: DocumentNode[]; }

Generic merge: newNodes are appends (with dedup against existing IDs — collisions route to in-place update), updatedNodes are targeted mutations against existing IDs. The primary caller is the stream’s RAF flush, but any frontend-local mutation that needs to append or update document nodes (e.g. optimistic decision-update, login-success row) routes through the same command so slot.state stays authoritative.


{ chunk: ToolLogChunk; toolId: string; type: "ToolChunkAppend"; }

Append one streaming chunk to a tool’s live-log buffer (ToolNode.log.chunks). Append-only, idempotent on the timestamp

  • content dedup key. Dispatched at high frequency from useAgentStream for tool_chunk stream events — kept distinct from StreamFlush so chunk traffic doesn’t re-trigger memos that watch the full node array length. See SPEC_TOOL_BLOCK_LIVE_LOG_2026_05_11.md §3.3.

{ node: ShellNode; type: "ShellNodeCreate"; }

Create a new ShellNode in the document (fired on shell_node_create MPS event).


{ chunk: ToolLogChunk; shellId: string; type: "ShellChunkAppend"; }

Append a streaming chunk to a ShellNode’s live-log.


{ exitCode?: number; exitedAt: number; shellId: string; status: ShellNode["status"]; type: "ShellStatusUpdate"; }

Update a ShellNode’s terminal status (exit, stop).


{ reason: string; type: "StreamTruncate"; }

Backend fileop=truncate arrived on the file subject. The reducer decides whether to honor (initialization, legitimate clear) or suppress (stale event after socket reconnect — this is the bug we’re fixing).


{ type: "UserClear"; }

User invoked /clear — always honored.


{ at: number; scope?: "tools-only"; type: "ScrubOrphanedInProgress"; }

Scrub orphaned in-progress nodes. Walks nodes[] and:

  • flips any markdown with metadata.thinking === true to metadata.canceled === true (clearing the thinking flag).
  • flips any tool with status === "running" to status: "canceled".

Dispatched as a side-effect of SessionEnd (clean exits) and HistoryRestored / HistoryLoaded (resumed sessions where the kill happened before SessionEnd ever fired). Idempotent — running it twice is a no-op against the already-scrubbed state.

scope: "tools-only" narrows the sweep to tool nodes with status === "running" — dispatched shortly after every TurnEnd (agent-view.tsx): a foreground tool call cannot outlive its turn (it blocks it) and a backgrounded harness call resolves its ToolNode immediately, so a running tool node observed after the turn ended is provably an orphan (rejected call / dropped tool_result). Thinking markdown, shells (turn-independent — a live MCP shell legitimately spans turns), and awaiting_answer questions are deliberately untouched in this scope; their lifecycles are session-bounded, not turn-bounded.

Spec: docs/specs/SPEC_ORPHAN_THINKING_NODES_2026_05_27.md.


{ nodeId: string; type: "ForceCancelToolNode"; }

Force one specific ToolNode to status: "canceled", regardless of how long it’s been running or whether a session boundary has happened. Dispatched when a dock:clear MPS event arrives (a muxspect dock clear request for this pane’s block) — the manual escape hatch for a stuck node, distinct from ScrubOrphanedInProgress’s blanket sweep. No-op (empty events) if nodeId isn’t a currently tracked tool node — already resolved, or a stale/duplicate event. Spec: docs/specs/SPEC_MUXSPECT_DOCK_DIAGNOSIS_AND_REMEDIATION_2026_08_06.md §3.2.


{ keepIds?: ReadonlySet<string>; keepTurns: number; maxFinishedBytes?: number; pinned: boolean; type: "RollOff"; visibleIds: ReadonlySet<string>; }

Roll finished turns off the live feed (spec SPEC_AGENT_PANE_BOUNDED_LIVE_WINDOW_MIGRATION_2026_09_23.md §6.9). The reducer plans against its CURRENT nodes (planRollOff), so what the pane saw when it scheduled the pass can’t be stale; the pane supplies only what the reducer can’t know — what is on screen, and whether the reader follows the bottom. The removed turns stay in the transcript, where History shows them.

optional keepIds?: ReadonlySet<string>

Nodes the user pinned: their turns stay, like visible ones.

keepTurns: number

optional maxFinishedBytes?: number

pinned: boolean

type: "RollOff"

visibleIds: ReadonlySet<string>


{ keepIds: ReadonlySet<string>; type: "UnloadToolResults"; }

Unload collapsed tool results the reducer plans against its current nodes (planUnload): each becomes a stub until it’s read back. SPEC_AGENT_PANE_TOOL_RESULT_UNLOADING_2026_10_01.md §3.3.


{ nodeId: string; result: ToolResult; type: "ResultLoaded"; }

A tool’s unloaded result, read back from the transcript (§3.4).