Free learning / 40-minute streaming lab
Streaming 101: when is a response actually finished?
See how bytes become events and a partial draft becomes a reviewable result. Compare six local HTTP responses, including interrupted streams and incomplete messages.
No account needed. Use your own copy for writing and keep the original as a reference.
Engineering lab library / Run locally
See what arrived—and what actually completed.
Predict six responses, then change byte grouping and completion requirements separately. Keep partial output distinct from a finished result.
Real HTTP on a temporary loopback port with scripted text. No model, credentials, external service or files. Byte slices and events are observed; model tokens and latency are not measured.
Start here / Node.js 24 · Offline exercise
Streaming 101 · real local HTTP
Reconstruct events across byte boundaries, withhold interrupted output and expose a premature-completion defect.
Node.js 24 · Standard library · Loopback only · No model
You ask an assistant for a draft. Words begin appearing, then the answer stops halfway through a sentence. Did it finish? Did the connection fail? Can you use what appeared? Those are separate questions, and a forward-deployed engineer needs an interface that tells the difference.
This original 40-minute lesson starts with the mechanism, then follows six actual local HTTP responses. It uses fictional text and no model, credentials, packages or cloud account. You need Node.js 24 and permission to listen on a temporary loopback port on your own computer. Nothing is exposed to your network.
1. Name the pieces before following the stream
Streaming is a way to deliver a response incrementally while work proceeds, instead of waiting to deliver the whole body at once. It is a delivery behavior, not a language, model or agent framework. It can make progress visible sooner; it does not by itself make generation faster or the answer correct.
Think of a download progress display. Seeing bytes arrive is different from having a complete, usable file. The analogy has a limit: a generated response usually does not have a known final size, and its content still needs review.
| Piece | Plain meaning | What it does not establish |
|---|---|---|
| Byte chunk | A portion of the response body delivered to the reader | One complete event, character or model token |
| UTF-8 decoder | Code that reconstructs text from bytes, keeping unfinished characters between reads | A complete application message |
| Server-sent events (SSE) | A text format for sending events from a server over HTTP | The event names or success rules of a particular model API |
| Delta | An addition or change to the result being assembled | A complete answer or executable tool arguments |
| Completion event | An application-defined signal that a message has ended | A factual answer, approved action or acceptable stop reason |
In the supplied lab, an event has an event: line, a data: line containing JSON and a blank line that ends the event. The reader must wait for that boundary before parsing the JSON. The service invents start, text_delta and done for this teaching exercise. They are not a provider's API contract.
2. Follow a draft from bytes to a reviewable result
Our fictional service writes three additions: Café , pump: and check seal. The client accumulates them into Café pump: check seal. while marking the preview as partial. The accented character is intentional: one character can occupy more than one byte. The same decoder keeps its state across reads.
Follow four decisions in order:
- Confirm the HTTP status and content type before interpreting the body.
- Decode bytes, retain unfinished text, then parse complete event records.
- Update the preview as deltas arrive while keeping it visibly provisional.
- Require the documented completion and acceptable stop reason, then validate the assembled result before the application's next action.
HTTP 200 only describes the response status. The body can subsequently break, end early or contain invalid events. Our lab waits for normal transport end, valid records and done with reason normal before marking a result ready-for-content-review. That deliberately narrow result is not permission to execute a tool or publish the text.
UNDERSTAND THE SYSTEM
The text arrived. Did the response finish?
Follow a fictional maintenance draft through an HTTP stream. The visible preview, event record and completion decision change independently. These are explained examples of the accompanying local lab, not a live model call.
See what moves and why.
Read the connections in plain English
- 01Response service → Byte reader
One read can contain partial or multiple records. It is not a token boundary.
- 02Byte reader → Complete event
Decode and retain partial text before parsing a complete event.
- 03Complete event → Draft preview
Only text additions change the draft. Progress remains provisional.
- 04Complete event → Acceptance check
Inspect the completed message and its stop reason before continuing.
- 05Draft preview → Acceptance check
A nonempty draft is insufficient without valid completion evidence.
Check your understanding: The connection ended normally and some text appeared. Can the app mark the draft complete?
Only if the service's documented completion evidence and your acceptance checks are satisfied. In the lab, the missing-done case has both a normal HTTP end and partial text, yet must remain incomplete.
3. Predict and run six local responses
Download fde-streaming-lab.mjs into a new folder. Use the same Node.js 24 command throughout:
node --version
node fde-streaming-lab.mjsThe file starts a server bound to 127.0.0.1 on an available port, makes six requests and closes the listener. It writes no files and reads no credentials. The server's short pauses make intermediate states observable; they are not measurements of inference performance. It does not retry failed requests.
Before running it, predict the completion decision for each case:
| Case | What the server or reader changes | Expected observation |
|---|---|---|
| complete | Three deltas followed by normal completion | Full text, completion observed, ready for content review |
| fragmented | Same response; client feeds its decoder one byte at a time | Same text and events despite many more parser slices |
| missing-done | HTTP body ends normally after two deltas, without completion | Partial text, transport ended, completion absent; withheld |
| connection-lost | Connection is destroyed after two deltas | Partial text, body-read-interrupted; withheld |
| limited | Full-looking text followed by a length-limit reason | Completion observed, but withheld by this app's contract |
| malformed | Final event contains invalid JSON | Invalid record; withheld |
Compare httpStatus, transportEnded, events, completionObserved, reason and decision. All six begin with 200. In previews, find text that appeared before any completion event. Do not infer a token count from text length, event count or receivedChunkBytes: the lab runs no model or tokenizer.
receivedChunkBytes records actual body reads; their grouping can vary by runtime and transport. parserSlices counts the pieces passed into our decoder. The fragmented case deliberately re-slices received bytes on the client. It does not claim that the network delivered one-byte packets. The controlled experiment isolates the parser's ability to preserve boundaries.
4. Change one assumption and explain the consequence
Keep the original file. In a first copy, change SLICE_BYTES = 1 to SLICE_BYTES = 7 and rerun. The fragmented case should have fewer parser calls but the same five events and complete text. A reader that relies on each read being a complete JSON object cannot meet that property.
Starting from the original, make a second copy and change REQUIRE_DONE = true to REQUIRE_DONE = false. This deliberately weakens the example's acceptance rule. The missing-done case now promotes Café pump: even though no completion arrived. The lost connection, invalid record and explicit length limit should still be withheld. Explain why a check that only asserts a nonempty response would miss this defect. Do not carry this broken rule into an application.
This is a small protocol lesson, not a general-purpose SSE implementation. The reader supports only the two-field, LF-delimited records emitted by this server. A complete SSE parser also handles other line endings, comments, multiple data lines and additional fields. Use the maintained SDK or parser appropriate to your production service, then test its behavior at your application's boundary.
5. Connect this to Claude and an agent workflow
Claude's documented stream has message and content-block events, text or tool input deltas, a stop reason and final message_stop. These names differ from our teaching protocol. Follow the provider's current SDK and event contract. Tool input can arrive as JSON fragments: a fragment is not yet validated tool arguments. Assemble the intended input, validate its schema and authorize the operation in trusted application code before executing it.
If the stream fails, retain an explicitly incomplete preview and the request's safe diagnostic metadata. A missing final event does not tell you whether a remote operation continued, how much it cost or whether an external effect occurred. Reconnection and safe retry are separate designs. This lab performs one attempt per case and has no continuation, replay or effect reconciliation.
In the UI, separate “receiving,” “ready for review,” “stopped” and “interrupted.” Do not let partial markup run as HTML or partial tool input trigger an action. When a user cancels, stop consuming and request supported cancellation; verify what the provider actually promises about remote work and billing. The local connection-lost case does not test provider cancellation.
For a real deployment, inspect buffering at the application, proxy and gateway. Measure first useful output and completed useful output separately. A responsive animation cannot establish either result. Do not add timing claims based on this fixture's deliberate pauses.
6. Hand over a response contract
Produce a small integration card with:
- The actual endpoint, content type, event schema and supported client version.
- Which preview states are visible and what qualifies as completed input.
- The acceptable stop reasons and content checks before downstream work.
- What happens after malformed data, a disconnect, timeout or user cancellation.
- How request identity, retry policy and unknown usage are recorded safely.
Keep your six predictions, observed report and two independent changes. Ask a receiver why both a clean HTTP end and a visible sentence can still be insufficient. Then give them a tool-input fragment and ask what must happen before an agent may use it. A good explanation names assembly, validation, authorization and the unresolved remote outcome without inventing certainty.
Continue in the guided streaming lesson with existing training access, then build the first bounded LangChain agent.
Primary references checked 22 October 2026: