--- title: State Streaming description: Stream partial agent state updates to the UI while a tool call is still running. icon: "lucide/Podcast" hideTOC: true snippet_cell: shared-state-streaming --- ## What is this? By default, agent state only updates *between* LangGraph node transitions, so a long-running tool call (writing a full document, drafting an email) appears to the UI as one big burst at the end. For agent-native apps, that feels broken: users expect to watch the output materialise. **State streaming** forwards the value of a specific tool argument straight into an agent state key *as the argument is being generated*. The UI, subscribed via `useAgent`, re-renders every token. ## When should I use this? Use state streaming whenever a tool's output is long-form text or a growing structured value and you want the user to see it assemble in real time. Common shapes: - A collaborative writing agent that emits a document - A research agent that accumulates a list of findings - A planning agent that builds up a step-by-step plan Without streaming, the user stares at a spinner. With streaming, they see the answer grow token-by-token. ## The backend: one streaming state mapping The backend pattern is always the same: map one streaming tool argument to one shared-state key. In Python prebuilt agents, that is `StateStreamingMiddleware` with one or more `StateItem(...)` entries. TypeScript graphs use `copilotkitCustomizeConfig` with an `emitIntermediateState` mapping for the same shape. When the LLM streams that argument, CopilotKit writes every partial value into shared state before the tool even finishes executing. A few things to note: - The `state_key` must exist on your `AgentState` schema (`document: str` in this demo). - The `tool` and `tool_argument` name the exact LLM-facing tool and argument to forward. - When the tool call completes, its final return value is written to the same key, so the streamed partial eventually becomes the authoritative final value. ## The frontend: useAgent + OnStateChanged The UI side is identical to any other shared-state subscription: `useAgent` with `OnStateChanged` gives you a reactive `agent.state`. Add `OnRunStatusChanged` if you want a "LIVE" / "done" indicator. From there, `agent.state.document` is just a string that grows on every token, and `agent.isRunning` tells you whether to show a streaming indicator. ## Related - **[Shared State (overview)](/shared-state)** — the bidirectional read + write pattern this extends. - **[Agent read-only context](/shared-state/agent-readonly)** — for the inverse, UI → agent one-way channel.