AI Application Integration · 90 minutes
Stream, stop, and replace a response
Explain how a streaming feedback UI shows partial output, what Stop really cancels, and how run IDs keep late events from an old attempt out of a new answer.
1.5 h
Used in interview rounds:
Technical Screen (Easy)Overview
A model-backed feature is more than a model call: the browser shows partial output, the backend owns each run, and either side can stop or lose the stream. This level teaches streaming, cancellation, run identity, and visible request states, practiced on a stop-and-resubmit session in an interview-feedback UI.
Study time: 90 minutes
Interview format: Conceptual screen with a chat-interface scenario and a step-by-step prediction exercise
By the end you can
- Separate what the browser controls from what the backend must enforce for a model-backed feature
- Explain why a transport chunk is not a token or an event, and why a closed stream does not prove a completed answer
- Describe what Stop cancels on the client and on the server, and what it cannot undo
- Use run IDs to keep late events from an old attempt out of a new answer
- Label partial, interrupted, and completed output honestly and announce state changes accessibly
Prerequisites
Helpful background: Basic web development (HTTP requests, browser events, and a UI framework such as React) is enough.
This topic covers client and server streaming state, cancellation, reconnects, citations, and accessible UI. Model Serving & Inference covers runtime scheduling, memory, and hardware.
The application boundary
A typical browser sends a user request to an application backend. The backend authenticates the caller, checks access and limits, constructs the model request, and returns a response. Provider credentials belong in protected server configuration, never in browser code.
The browser controls presentation and user interaction. The backend controls authoritative conversation ownership, tool permissions, source eligibility, model access, and the saved record of each run. A hidden client-side button cannot enforce authorization because a caller can send requests directly.
For example, an interview-practice assistant might receive a learner's answer and return written feedback. The UI should distinguish the learner's submission, the generated feedback, and any score still under review.
Buffered and streamed responses
A buffered response arrives as a complete result after processing. A streamed response arrives incrementally. Streaming can show progress and reduce perceived waiting, but it introduces partial state and interruption handling.
A transport chunk is not necessarily a model token, sentence, or application event. Network boundaries can split a UTF-8 character or combine several events. Decode bytes incrementally (a streaming text decoder holds the bytes of a split character until the rest arrive) and parse an explicit framing format. In the server-sent events format, each event is one or more field: value lines followed by a blank line:
event: delta
data: {"runId":"R1","text":"Your answer picks the right data structure."}
event: done
data: {"runId":"R1"}
One chunk may end halfway through the first data line, and the next may carry the rest of it plus the whole done event. The parser buffers text until it sees the blank line, then handles one complete event.
A stream ending does not automatically prove task completion. The application protocol should identify successful completion or an authoritative terminal status, such as the done event above. A dropped connection can look like an unexpected end.
Transport choices
| Approach | Useful property | Integration consideration |
|---|---|---|
| Fetch with a streamed body | Supports request bodies and incremental reading | Application handles framing and reconnect policy |
| Server-sent events | Event-oriented server-to-client updates | Native EventSource has a specific request and reconnection model |
| WebSocket | Bidirectional ongoing communication | Requires connection lifecycle and message routing |
| Polling | Simple recovery and status checks | Adds repeated requests and update delay |
Choose based on the interaction. A text-answer stream may need only server-to-client updates. Real-time audio or bidirectional collaboration may need a different transport. Transport selection alone does not implement persistence or reliable resumption.
Native EventSource always opens a GET request without a body or custom headers, and reconnects on its own, sending the last event ID it received when the server set one. To post the user's text, read a fetch response body and parse the same format, or create the run first and then open the stream.
Make state visible
| State | User meaning | Typical control |
|---|---|---|
| Idle | Ready for a request | Send |
| Submitting | Request is being accepted | Prevent accidental duplicate submission |
| Streaming | Partial response is arriving | Stop |
| Complete | Server confirmed completion | Copy, review, or continue |
| Interrupted | Response ended without completion | Reconnect or retry |
| Cancelled locally | User stopped this client operation | Start a new attempt if desired |
| Failed | A defined error prevents continuation | Explain and offer a suitable next action |
Keep partial text when it helps the user, but label it accurately. Do not display a completed checkmark simply because some text arrived.
Cancellation has several meanings
A browser can abort a fetch with AbortController. Calling abort() on the controller whose signal was passed to fetch() rejects the pending request, or errors a response body that is still being read, with an AbortError by default. This stops the client's operation. The server may need to detect disconnection or receive a separate cancellation request to stop upstream work.
Cancellation does not undo a tool action already completed. If the assistant sent a message or changed a record, stopping the visible stream cannot reverse that effect. Use authoritative operation state for final reporting.
The UI can acknowledge that the user stopped receiving output while separately checking whether the server run ended. Avoid promising that all provider processing or billing stopped instantly.
Request identity and stale responses
Assign a stable identity to each accepted run and distinguish new attempts. If a user stops one request and immediately starts another, late events from the old request must not modify the new answer. Late events happen in practice: a chunk already in flight, or a read that resolves just after the user pressed Stop, can still reach the event handler.
A message ID identifies a conversation item, while a run or attempt ID identifies the execution producing it. Keeping these separate supports retries, alternative answers, and reliable rendering.
A simple guard: apply a stream event only when its run ID matches the active run and that run is still streaming. A handler that appends to "the current message" without this check writes an old run's text into whatever message is current when the event lands. In React, a reducer can centralize these transitions and ignore stale events. Use stable message keys so incremental updates do not recreate unrelated components or move keyboard focus unexpectedly.
Error and retry UX
A request may fail before output, after partial output, or after backend completion but before the client sees the result. These cases need different handling.
Retrying generation creates a new answer attempt unless the server explicitly resumes the existing run. Do not append a new generation to old partial text as though it were a continuation. Preserve the earlier attempt or replace it deliberately with a clear label.
A reconnect can replay already-produced events or retrieve a final snapshot if the backend supports that contract. Automatic retry should not repeat side-effecting tool operations without the operation controls covered in Tool Calling & Agents.
Citations and rendering
Display citations using source metadata returned through a trusted mapping. The UI should show a useful title or section and handle a source that becomes unavailable. A model-generated arbitrary URL should not automatically become a trusted citation.
Partial Markdown can be syntactically incomplete. Use safe rendering and avoid enabling raw HTML or unapproved remote resources. The completed response should pass the application's validation before it is treated as authoritative structured data.
A citation marker shows attribution, not proof that the cited source supports the claim.
Accessibility and interaction
Keep Send and Stop keyboard-accessible with descriptive labels. Announce meaningful states such as generating, stopped, interrupted, and complete through a polite status region (role="status"). Announcing every token can overwhelm screen-reader users.
Preserve focus while content updates. If a control disappears when it is used, as Stop often does, move focus to a sensible neighbor such as the input or Send; otherwise focus falls back to the page body, and keyboard and screen-reader users lose their place. Auto-scroll only when the user is already following the bottom or has opted in. If the user scrolls upward to read, provide a new-content indicator instead of pulling them back down.
Provide a readable completed transcript and an alternative way to obtain the final response when streaming is unavailable. Test long code blocks, narrow screens, zoom, and keyboard navigation.
Scenario: the feedback session
Worked example
Suppose a fictional coding-practice platform has an interview-practice assistant: a learner types an answer to an interview question, and the assistant streams written feedback into a chat thread.
How the platform works
- The browser talks only to the platform's backend. The backend calls a model provider and saves every run.
- Each submission starts a new run with its own ID (R1, R2, and so on). Every stream event the client receives carries the run ID it belongs to.
- Stream events are
delta(more feedback text),done(the backend finished and saved the full feedback), anderror(the run failed, with a message). POST /feedback-runs/{runId}/cancelasks the backend to stop a run.GET /feedback-runs/{runId}returns the run's saved status (running,completed,cancelled, orfailed) and, when it iscompleted, the full feedback text.- The backend cannot resume a broken stream from the middle.
- The assistant has no side-effecting tools.
Timeline
| Step | What happens |
|---|---|
| 1 | The learner submits answer A. The backend accepts it as run R1, and R1's feedback starts streaming. |
| 2 | After two paragraphs of R1 feedback, the learner presses Stop. |
| 3 | The learner submits a revised answer B. The backend accepts it as run R2, and R2's feedback starts streaming. |
| 4 | A delayed R1 delta event, already in flight when the learner pressed Stop, reaches the client's event handler. |
| 5 | The response to R1's cancel request says R1 is already completed, with its full feedback saved. |
| 6 | After three paragraphs of R2 feedback, R2's connection drops. No done or error event arrived for R2. |
| 7 | R2's saved status on the backend is completed, with its full feedback saved. |
Predict each step
Use the platform facts and the timeline in the scenario, and the states in "Make state visible".
Predict the outcome
Predict each step of the feedback session
For each step of the feedback session, write what the UI shows for R1 and R2 and what the client does, including anything it announces. Then reveal the answers.
| Step | What happens | What the UI shows | What the client does |
|---|---|---|---|
| 1 | The learner submits answer A; the backend accepts run R1 and starts streaming. | ? | ? |
| 2 | After two paragraphs, the learner presses Stop. | ? | ? |
| 3 | The learner submits answer B; the backend accepts run R2. | ? | ? |
| 4 | A delayed R1 delta reaches the event handler. | ? | ? |
| 5 | The backend reports R1 completed, with full feedback saved. | ? | ? |
| 6 | R2's connection drops after three paragraphs, with no done or error event. | ? | ? |
| 7 | R2's saved status is completed, with full feedback saved. | ? | ? |
Completion checklist
- I can say which decisions the browser makes and which the backend must enforce.
- I can explain why a chunk is not a token and why a closed stream is not a completed answer.
- I can predict each run's state and the client's action at every step of the feedback session.
- I can explain what Stop cancels, what it cannot undo, and how a late event from a stopped run is handled.
- I can name the state changes to announce and how focus and scrolling behave while a response streams.
Sources
- MDN: Using readable streams Reading a fetch response body chunk by chunk with a reader, and cancelling a stream.
- MDN: TextDecoderStream Converts a stream of bytes in a text encoding such as UTF-8 into a stream of strings.
- MDN: AbortSignal Aborting a fetch request and the reading of its response body from the client: the promise or the body read rejects with a DOMException named AbortError.
- MDN: Using server-sent events The event stream format (event and data fields, events separated by a blank line), EventSource reconnection, and the last event ID.
- W3C: Understanding Success Criterion 4.1.3 Status Messages Status messages should reach assistive technology without moving focus.
- W3C technique ARIA22: Using role=status to present status messages A polite status region that announces a change without interrupting the user.
- WHATWG HTML Standard: Server-sent events The EventSource request model: a GET request, automatic reconnection, and the Last-Event-ID header sent on reconnect.
The feedback session, application protocol, run identifiers, timeline, and rubric are original synthetic teaching material about a fictional coding-practice platform. They are not a provider API schema; adapt them to your backend and browser support. Study times and readiness thresholds are editorial estimates. Browser API and accessibility guidance is as of November 2026.
Related on CodeSnatch
Lessons, problems, and articles that build the skills this question uses.
System Design
Compares SSE, WebSockets, and polling and shows the SSE event format, matching the transport choices here.
Code snippet
Runnable AbortController examples showing what an abort stops on the client and how AbortError surfaces.
Community snippet
Parses the SSE line protocol by buffering text until a blank line, the framing this question describes.
AI Engineering
Explains what delays the first token and how a client cancellation should reach the serving backend.
Community article
A practical accessibility pass: keyboard paths, live regions for status changes, and a screen reader check.
Practice the interview question
Answer it in your own words before you look at the reference answer.
