Hedronite · Cert Prep · CCA-F · Anthropic Day · Sun 2026-07-05

Streaming Claude Responses to Production UIs — the Messages Streaming API, Server-Sent Events, and the Partial-Message Assembly Discipline

The user should see the answer forming. The harness should never move on a fragment.

Lesson Class: Cert Prep · CCA-F · Post-sweep cross-domain integration
Domains Touched: D1 Agentic Architecture · D2 Claude Code · D5 Context Management
Domain Status: D1-D5 sweep ✅ complete (05-31 → 06-28); today opens the second pass
Word Count: ~2,560
Grounding: Huyen "AI Engineering" Ch.9 Inference Optimization pp.435-437 (grounded-in) + Flanagan JS Definitive Guide §15.11.2 SSE (cross-pair)
Paired Ops: Real-Time Data Delivery to Web UIs
Paired Dev: Streaming Live Market Data into React and Three.js
Discipline: ROD v3 · aether-accent meta-card · q-card practice questions · HEDRONITE-AETHER-THEME v2.1

§ IFrame

A model that streams feels twice as fast as a model that does not, and generates at exactly the same speed. The difference is where the user's wait lives. A non-streaming call makes the user stare at nothing until the entire response is done. A streaming call shows the first token as soon as it exists and fills the rest in as the model writes. Huyen is exact about this in the inference-optimization chapter: streaming changes perceived latency, not actual latency, and perceived latency is the one the user feels.

The CCA-F domain sweep closed last Sunday with Domain Three. The five domains are covered once each. This lesson is the first pass back through them from a single production concern that touches three at once: streaming. Streaming is an Agentic Architecture question (Domain One — how the harness consumes model output), a Claude Code question (Domain Two — how an interactive runtime shows work as it happens), and a Context Management question (Domain Five — the token budget spent one delta at a time). The transport underneath is the same Server-Sent Events channel today's Ops and Dev lessons built. This lesson is those lessons one layer up: instead of streaming market ticks to a scene, stream model tokens to a UI, and instead of assembling bars, assemble a message.

§ IIDomain Foundations

The streaming event sequence

The Messages API streams over SSE. When a request sets stream: true, the response is a text/event-stream, and the events arrive in a fixed grammar the client assembles into a complete message.

The sequence opens with message_start, which carries the message shell — id, model, role, and an empty content array with usage counting only input tokens so far. Then, for each content block the model produces, a content_block_start announces the block and its type, a run of content_block_delta events carries the incremental payload, and a content_block_stop closes it. After all blocks, a message_delta carries the top-level changes — the stop_reason and the cumulative output-token usage — and message_stop ends the stream. Interleaved ping events keep the connection warm, exactly the heartbeat role the Ops lesson gave the SSE comment line.

The deltas come in types matching their block. A text block emits text_delta events, each carrying a fragment of prose to append. A tool-use block emits input_json_delta events, each carrying a fragment of the JSON arguments as a string. The distinction is the whole game: a text delta is safe to show the instant it arrives; a JSON delta is not safe to do anything with until the block closes.

Partial-message assembly

Assembly is the discipline of turning the delta stream back into a whole message without acting on a fragment. The rule has two halves, split by block type.

For text, accumulate and display. Append each text_delta to the running text for that block and paint it. The user watches the answer form. This is the perceived-latency win, and it is safe because prose is meaningful in fragments.

For tool use, accumulate but do not parse until closed. The input_json_delta fragments are pieces of a JSON string. Concatenated mid-stream, they are almost always invalid JSON — a half-open brace, a truncated string, a trailing comma. Parsing a partial tool call throws or, worse, parses to something plausible and wrong. The discipline is to buffer the fragments as raw text and parse the accumulated string only after content_block_stop. The tool does not execute until the block is whole. This is the streaming twin of the 06-28 single-retry discipline: validate the complete structure against the schema before acting, never the partial one.

§ IIICCA-F Flavor: Agentic Architecture and Context Management

Domain One asks how the harness turns model output into action. Streaming complicates the answer because output now arrives in pieces, and the harness must decide, per piece, whether it is display-safe or action-gated. The clean architecture separates two consumers of the stream. The display consumer receives text deltas and renders them live. The action consumer receives tool-use blocks, waits for each to close, parses, validates against the tool schema, and only then executes. One stream, two consumers, two different timing rules — and the action consumer never runs on a partial.

Domain Five — Context Management — reads the stream as a budget meter. The message_start usage reports input tokens; the final message_delta reports cumulative output tokens. A harness that tracks the running output count against a ceiling can enforce a budget mid-generation: if the model is streaming past the allotted output tokens, the harness can stop the stream rather than pay for a runaway completion. The 06-14 context-budget lesson set the ceiling; the stream is where it is spent, one delta at a time, and stopping early is the enforcement.

§ IVAcademy Flavor: The Interactive Harness and the SDK Helpers

The Anthropic Academy Claude Code and API courses show streaming from the runtime side. An interactive agent runtime — the Domain Two subject — shows its work as it happens: the model's text appears live, a tool call announces itself, the result comes back, the next text streams. That live-work display is the streaming sequence rendered as a session. The user sees the agent think and act rather than waiting for a silent runtime to return a wall of output.

The SDK carries helpers so the assembly discipline is not hand-rolled per app. The streaming helper exposes the raw event stream and also a set of higher-level events — text as it accumulates, an input-JSON accumulator for tool blocks, and a terminal final message that returns the fully assembled message object once message_stop arrives. The production posture is to use the accumulator for anything you will act on and the raw text events for anything you will display. The helper does the buffering the partial-message-assembly rule requires; the discipline is knowing which stream feeds display and which feeds action. An app that pipes raw JSON deltas into a tool executor has skipped the helper's whole reason for existing.

Reconnection is the piece the transport lessons already taught. If a stream drops mid-message, the assembled-so-far text is partial and the message never reached message_stop, so it has no stop_reason and must be treated as incomplete. Unlike the market feed, a language generation cannot resume from a Last-Event-ID; the model has no memory of the dropped completion. The recovery is to discard the partial and re-request, which is the resync path from the Ops lesson with a stricter rule: a half-streamed answer is not a shorter answer, it is no answer, and showing it as if it were complete is the same lie the frozen market bar tells.

§ VWorked Example

A support agent UI streams Claude's response. The request sets stream: true and provides one tool, lookup_order, with a schema requiring an order_id string.

The client opens the SSE stream and runs two consumers. The user asks about a late order. The stream produces message_start, then a text block: content_block_start (type text), a run of text_delta events — "Let me check that order for you." — and content_block_stop. The display consumer paints each fragment; the user reads the sentence forming.

Next a tool block: content_block_start (type tool_use, name lookup_order), then input_json_delta events carrying {"order_, then id":"A-4, then 21"}. The action consumer buffers these three fragments as raw text. It does not parse after the first, which would be {"order_ and throw. It waits for content_block_stop, concatenates to {"order_id":"A-421"}, parses that whole string, validates order_id is a string per the schema, and executes the lookup. The message_delta reports stop_reason: tool_use and the output-token count; the harness records the spend against the budget.

The tool result feeds back, a second streamed message renders the answer, and the session shows the whole arc — think, act, answer — live. Had the stream dropped after the first input_json_delta, the action consumer would hold {"order_ — invalid, incomplete, never closed — and correctly refuse to parse or execute. No lookup fires on a fragment. The harness re-requests rather than guessing the order id.

The Partial-Message-Assembly Discipline Text deltas: accumulate and display, safe in fragments. Tool-use JSON deltas: accumulate and hold, parse only after content_block_stop, execute only after schema validation. A stream that never reached message_stop is incomplete, not short — discard and re-request. Perceived latency is the win; acting on a partial is the trap.

§ VIConnection to Today's Ops and Dev Lessons

The three lessons share one transport and one rule. The Ops lesson built the SSE delivery channel — heartbeats, reconnection, the freshness contract. The Dev lesson assembled a market feed into a scene by sampling newest-per-key. This lesson assembles a token feed into a message by accumulating deltas-per-block. The Ops heartbeat is the API's ping event. The Dev lesson's rule to never render a partial is this lesson's rule to never execute a partial tool call. And all three carry the same freshness ethic: a market bar must not look live when the feed is dead, and a streamed answer must not look complete when the stream dropped. The seam is the same seam — where a fast producer's fragments become a slow consumer's whole — read three times, at three layers.

§ VIIPractice Questions

Q1 · Delta Types

A streamed response contains a tool-use block. The client concatenates each input_json_delta and calls JSON.parse after every delta so the tool can start early. What is the flaw?

A) Nothing; early parsing reduces latency
B) input_json_delta fragments are pieces of a JSON string and are almost always invalid until the block closes; parse only after content_block_stop
C) Tool-use blocks never emit deltas
D) JSON.parse cannot handle streamed input at all
Correct: B. JSON arguments arrive as string fragments; mid-stream concatenations are typically malformed. Buffer as raw text and parse only after the block's content_block_stop, then validate against the schema before executing.
Q2 · Perceived vs Actual Latency

A team enables streaming and reports the model "got faster." Total generation time is unchanged. What actually improved?

A) Actual latency, because streaming uses a faster decoder
B) Throughput, because tokens are batched
C) Perceived latency, because the first token displays as soon as it exists instead of after the whole response ✓
D) Nothing measurable changed
Correct: C. Per Huyen, streaming changes perceived latency, not actual latency. Time-to-first-token drops sharply while total generation time holds; the user feels the first-token moment.
Q3 · The Two Consumers

A harness streams a response that mixes displayed prose and a tool call. What is the correct consumer architecture?

A) One consumer that renders every delta, including JSON, to the screen
B) A display consumer that paints text deltas live, and an action consumer that buffers tool-use blocks and executes only after the block closes and validates ✓
C) Buffer the entire message, then decide what to do
D) Execute tool calls as each JSON fragment arrives to save time
Correct: B. Split by timing rule: text is display-safe in fragments; tool use is action-gated until the block is whole and schema-valid. One stream, two consumers, two timing rules.
Q4 · Dropped Stream

A streaming completion drops after two text_delta events and never reaches message_stop. The UI shows the two-fragment text. Why is this wrong?

A) The text is fine to show as the final answer
B) A message without message_stop is incomplete, not short; showing it as complete is a freshness lie, so discard and re-request ✓
C) The client should resume from the last event id
D) The model will automatically resend the rest
Correct: B. A language completion cannot resume from Last-Event-ID; the model has no memory of the dropped generation. A half-streamed answer is no answer. Discard and re-request rather than present a partial as final.
Q5 · Budget Enforcement

During streaming, how can a harness enforce an output-token ceiling mid-generation?

A) It cannot; the budget is only checkable after completion
B) Track cumulative output tokens as deltas arrive and stop the stream if the running count crosses the ceiling ✓
C) Set temperature to zero
D) Truncate the input prompt
Correct: B. message_start reports input usage and the final message_delta reports output usage, but the harness can also count deltas as they stream and abort a runaway completion before paying for the full overrun. The 06-14 ceiling is enforced at the stream.

§ VIIIClosing

Streaming buys perceived speed, not real speed, and it charges for that speed in a new discipline: assemble before you act. Show text as it arrives. Hold tool-call JSON until its block closes, then parse and validate before executing. Treat a stream that never said message_stop as no answer at all. Count the deltas against the budget and stop a runaway.

The user should see the answer forming. The harness should never move on a fragment.

Open your agent's streaming handler. Find where it parses tool-call arguments. If it parses before content_block_stop, you have a partial-execution bug waiting for a slow network to trigger it. Move the parse behind the block close.

Paired lessons → Ops 01-Earth-DevOps/Synthesis-Lessons/2026-07-05-real-time-data-delivery-to-web-uis-... · Dev Polyglot-Dev/Web/2026-07-05-streaming-live-market-data-into-react-and-three-js-...

🫡 ⚖️ 📜
Leo.Syri — Praetor Consulate, Imperium Luminaura
Filed 2026-07-05 Sunday Fajr · Anthropic Day · CCA-F post-sweep cross-domain integration (D1+D2+D5)
Backward-Synergy-Reach → Prompt Engineering D3 (06-28) · Claude Code D2 (06-21) · Context Management D5 (06-14)
HTML shipped in-cycle per HARD DISCIPLINE · aether-accent meta-card · q-card practice questions · tome-grounded Huyen Ch9 pp435-437