Skip to content

primitives chat stream event

Zachary BENSALEM edited this page Aug 15, 2026 · 1 revision

Chat stream event

Active contributors: Mario Zechner, kt, Armin Ronacher

ChatStreamEvent is the wire event of the Qredence chat UI. It is the discriminated union of frame types emitted as one NDJSON line per frame on the chat turn stream (POST /api/chat). It is defined in web/protocol/src/chat-protocol.ts, validated by zod in web/protocol/src/schemas/chat.ts, produced by web/server/src/event-mapper.ts, and consumed by the web reducer and design renderers.

Purpose

  • Define a stable, validated wire contract between the coding agent session runtime and the browser chat UI.
  • Carry streaming text, thinking, tool lifecycle, lifecycle state, plan, queue, compaction, retry, and terminal signals in one typed union.
  • Let the server translate AgentSessionEvent frames into web-oriented frames while keeping the client reducers and renderers typed.

How it works

The union (web/protocol/src/chat-protocol.ts) is discriminated by type:

  • start - opens a turn, with id, runId, sessionFile, sessionId, optional sessionReset and diagnostics.
  • delta - streamed assistant text, with optional messageId.
  • tool - a tool lifecycle part (ChatToolPart), with optional messageId.
  • plan - plan mode execution, with mode, executing, completed, total, optional message, and the state object.
  • state - lifecycle state with ChatStateEvent name (agent_start, agent_end, agent_settled, turn_start, turn_end, message_start, message_end) and optional message.
  • queue - steering and follow-up arrays (the QueueState).
  • thinking - streamed thinking text, with optional messageId.
  • compaction - phase: "start" (reason) or phase: "end" (reason, aborted, willRetry, optional errorMessage).
  • retry - phase: "start" (attempt, maxAttempts, delayMs, errorMessage) or phase: "end" (success, attempt, optional finalError).
  • done - terminal success with runId, the full ChatMessage, optional sessionFile, sessionId, sessionReset.
  • error - terminal failure with message and optional runId.

Each variant has a matching zod schema in web/protocol/src/schemas/chat.ts (ChatStartEventSchema, ChatDeltaEventSchema, ChatToolEventSchema, ChatPlanEventSchema, ChatStateStreamEventSchema, ChatQueueEventSchema, ChatThinkingEventSchema, ChatCompactionStartEventSchema, ChatCompactionEndEventSchema, ChatRetryStartEventSchema, ChatRetryEndEventSchema, ChatDoneEventSchema, ChatErrorEventSchema). ChatStreamEventSchema is the union of all of them and validates every NDJSON line.

Production happens in web/server/src/event-mapper.ts. mapAgentSessionEvent takes one AgentSessionEvent and per-session EventMapperState and returns zero or more ChatStreamEvent frames. Core agent-loop events (agent_start/end, turn_start/end, message_*, tool_execution_*) and assistant stream events (text_delta, thinking_delta) are mapped to state, done, tool, delta, and thinking frames; session-specific events map to compaction, retry, queue, error, and a few state frames. Events in KNOWN_IGNORED and unknown future events map to nothing.

flowchart LR
    A[AgentSessionEvent] --> B[mapAgentSessionEvent]
    B --> C[ChatStreamEvent[]]
    C --> D[NDJSON over POST /api/chat]
    D --> E[applyChatStreamEvent reducer]
    E --> F[design renderers]
Loading

The client applies frames with applyChatStreamEvent in web/app/src/lib/pi/chat-stream-state.ts, which drives use-pi-chat-messaging.ts. It reconciles the in-flight assistant bubble id, appends delta text, upserts thinking and tool parts, sets the activity label from state / compaction / retry frames, updates the queue on queue, and merges the final ChatMessage on done. Helper logic for suggestions and session labels lives in web/app/src/lib/pi/use-chat-view.ts.

Renderers dispatch on the part type. web/design/src/components/agent-elements/message-turns.tsx (buildAssistantElements) walks normalized assistant parts, joining text, suppressing tool-TaskOutput, turning error parts into ErrorMessage, and routing tool-* parts to the tool renderer. web/design/src/components/agent-elements/tools/tool-renderer.tsx (ToolRenderer) switches on part.type to specialized components (tool-Bash, tool-IPython, tool-Edit/tool-Write, tool-WebSearch/tool-Grep/tool-Glob, tool-PlanWrite, tool-TodoWrite, tool-Question, tool-Task/tool-Agent, tool-Thinking), then falls back to MCP tool renderers, custom tool-* renderers, the generic tool registry, or a fallback name.

Integration points

  • web/protocol/src/chat-protocol.ts declares the ChatStreamEvent union and ChatMode, QueueState, ChatPlanState, and transport types.
  • web/protocol/src/schemas/chat.ts validates every frame with zod; ChatStreamEventSchema unions the per-frame schemas.
  • web/server/src/event-mapper.ts produces frames from AgentSessionEvent.
  • web/app/src/lib/pi/chat-stream-state.ts reduces frames into a ChatStreamSnapshot.
  • web/app/src/lib/pi/use-pi-chat-messaging.ts feeds frames into the reducer.
  • web/design/src/components/agent-elements/message-turns.tsx and web/design/src/components/agent-elements/tools/tool-renderer.tsx render message parts and tool parts.

Key source files

Path Purpose
web/protocol/src/chat-protocol.ts ChatStreamEvent union, ChatMode, QueueState, ChatPlanState, settings and response types
web/protocol/src/schemas/chat.ts zod schemas for every frame, ChatMessageSchema, and ChatStreamEventSchema union
web/protocol/src/chat-types.ts ChatMessage, ChatMessagePart, ChatToolPart, roles
web/server/src/event-mapper.ts mapAgentSessionEvent / mapAgentSessionEvents producing frames
web/app/src/lib/pi/chat-stream-state.ts applyChatStreamEvent reducer
web/app/src/lib/pi/use-pi-chat-messaging.ts feeds frames to the reducer
web/app/src/lib/pi/use-chat-view.ts suggestions and session labels derived from messages
web/design/src/components/agent-elements/message-turns.tsx buildAssistantElements walks message parts
web/design/src/components/agent-elements/tools/tool-renderer.tsx ToolRenderer dispatches on tool part type

Related pages

Clone this wiki locally