new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

LangChain · Agents · all subjects

agents/streaming

116 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Use streaming for progress updates

invoke returns the final response at the end of a run. If an agent executes multiple tool calls, use streaming to surface intermediate messages and tool activity as they happen, providing users with progress updates before completion.

JavaScript deployment uses Agent Streaming Protocol

JavaScript frameworks and platforms such as Next.js, SvelteKit, Nuxt, Cloudflare Workers, and Deno Deploy can deploy LangChain agents using the Agent Streaming Protocol (https://github.com/langchain-ai/agent-protocol/tree/main/streaming).

stream.messages yields ChatModelStream objects with text, reasoning, tool_calls, and output

stream.messages yields ChatModelStream objects. Each message stream exposes .text, .reasoning, .tool_calls, and .output. Sync projections are iterable for live deltas and drainable for final values: use str(message.text) for final text and message.tool_calls.get() for finalized tool calls. In JavaScript, stream.messages yields message streams with .text, .reasoning, .toolCalls, .output, and .usage.

Event streaming projections available in LangChain

Available projections for stream_events(version="v3") in Python: stream.messages (model message streams), message.text (text deltas and final text), message.reasoning (reasoning deltas), message.tool_calls (tool-call argument chunks and finalized calls), message.output (final message after model call), stream.values (agent state snapshots), stream.output (final agent state), stream.subgraphs (nested graph runs), stream.extensions (custom transformer projections), stream.tool_calls (tool execution lifecycle). For raw events: iterate stream directly for full envelope with method, params.namespace, and params.data.

Agent message streaming example with node and usage metadata

Example showing how to stream agent messages with node identification and usage metadata: ```py stream = agent.stream_events(input, version="v3") for message in stream.messages: print(f"[{message.node}] ", end="") for delta in message.text: print(delta, end="", flush=True) full_message = message.output usage = full_message.usage_metadata if usage: print(usage) ```

Streaming reasoning content from models

Reasoning content uses the same shape as text content and is available only when the selected model emits reasoning blocks. Iterate message.reasoning for reasoning deltas and message.text for text deltas separately.

Two tool-call projections for different uses

message.tool_calls streams tool-call argument chunks while the model is producing the tool call. stream.tool_calls streams the lifecycle of tool execution after the tool call starts, including inputs, output deltas, final output, and errors.

Tool calls streaming example with finalized calls and execution lifecycle

Example showing both message-level and stream-level tool call streaming: ```py stream = agent.stream_events(input, version="v3") for message in stream.messages: for chunk in message.tool_calls: print(f"tool call chunk: {chunk}") finalized = message.tool_calls.get() if finalized: print(f"finalized tool calls: {finalized}") for call in stream.tool_calls: print(f"{call.tool_name}({call.input})") for delta in call.output_deltas: print(delta, end="", flush=True) print(call.output, call.error) ```

stream.subagents for named sub-agent runs

When a create_agent call invokes another named create_agent (via a wrapping tool), the inner agent's events flow at a nested namespace. Named sub-agents surface on stream.subagents projection. Each handle exposes .messages, .tool_calls, .output, plus .name (the name= passed to create_agent) and .cause (the tool call that dispatched the sub-agent). Only named create_agent runs appear here, so plain subgraphs do not need to be filtered out.

Sub-agent streaming example with supervisor pattern

Example of streaming from named sub-agents in a supervisor pattern: ```py from langchain.agents import create_agent from langchain.chat_models import init_chat_model def get_weather(city: str) -> str: return f"It's always sunny in {city}!" weather_agent = create_agent( model=init_chat_model("openai:gpt-5.5"), tools=[get_weather], name="weather_agent", ) def call_weather(query: str) -> str: result = weather_agent.invoke({"messages": [{"role": "user", "content": query}]}) return result["messages"][-1].text supervisor = create_agent( model=init_chat_model("openai:gpt-5.5"), tools=[call_weather], name="supervisor", ) stream = supervisor.stream_events( {"messages": [{"role": "user", "content": "What's the weather in Boston?"}]}, version="v3", ) for subagent in stream.subagents: print(f"{subagent.name}: ", end="") for message in subagent.messages: for token in message.text: print(token, end="", flush=True) print() ```

stream.values and stream.output for state snapshots

Use stream.values to iterate state snapshots during execution and stream.output to get the final agent state after execution completes.

stream.interleave for synchronized multi-projection streaming

For synchronous code requiring multiple projections, use stream.interleave(...) to consume different projection types in order: ```py stream = agent.stream_events(input, version="v3") for name, item in stream.interleave("messages", "tool_calls", "values"): if name == "messages": print(item.text) elif name == "tool_calls": print(item.tool_name, item.input) elif name == "values": print(item) ```

Custom stream transformers with stream.extensions

Use custom stream transformers when your application needs a projection not built in, such as retrieval progress, artifacts, or domain-specific events. Pass transformers= to stream_events and access custom data via stream.extensions[key].

Custom transformer example with stream_events

Example using a custom stream transformer: ```py stream = agent.stream_events( input, version="v3", transformers=[ToolActivityTransformer], ) for activity in stream.extensions["tool_activity"]: print(activity) ```

Concurrent streaming with astream_events and asyncio.gather

For concurrent consumption of multiple projections in async code, use astream_events with asyncio.gather: ```py import asyncio stream = await agent.astream_events(input, version="v3") async def consume_messages(): async for message in stream.messages: print(await message.text) async def consume_tool_calls(): async for call in stream.tool_calls: print(call.tool_name, call.input) await asyncio.gather(consume_messages(), consume_tool_calls()) ```

stream_events with version=v3 returns typed projections

LangChain agents support Event Streaming through stream_events(..., version="v3"). This returns a run object with typed projections for messages, tool calls, state, and custom updates. Each projection can be consumed independently instead of parsing stream-mode tuples. This is the recommended approach for most application and frontend use cases.

Progressive rendering during streaming

During streaming, the spec is built up incrementally. Elements arrive one at a time and may initially lack `type` or `props`. Filter to only include elements with valid type and props, and pass `loading={true}` to the `Renderer`. This tells the Renderer to silently skip children that haven't arrived yet, enabling the UI to build up component by component as the AI response streams in.

Progressive rendering implementation with spec filtering

Example of filtering the streamed spec to only include complete elements and rendering progressively: ```tsx /* * Filter the streamed spec to only include elements with valid type/props, * enabling progressive rendering as the AI response builds up. Passing * loading={true} to the Renderer tells it to skip missing children silently. */ const spec = (() => { if (!rawSpec?.root || !rawSpec?.elements) return null; const rootEl = rawSpec.elements[rawSpec.root]; if (!rootEl?.type || rootEl?.props == null) return null; const safeElements = {}; for (const [key, el] of Object.entries(rawSpec.elements)) { if (el?.type && el?.props != null) { safeElements[key] = el; } } return { root: rawSpec.root, elements: safeElements }; })(); return ( <> {spec && ( <JSONUIProvider registry={registry}> <Renderer spec={spec} registry={registry} loading={stream.isLoading} /> </JSONUIProvider> )} </> ); ```

Best practice: validate before rendering generative UI

Always validate that elements have valid `type` and non-null `props` before passing to the Renderer, since streaming delivers partial data. This prevents rendering incomplete or invalid components.

Best practice: design for streaming in generative UI

Pass `loading={true}` to the Renderer during streaming so it gracefully handles children that haven't arrived yet. Users see the UI build up in real time rather than waiting for the full response.

useStream hook with headless tools

Pass implemented tools to the useStream hook in React, Vue, Svelte, or Angular. When the agent emits a matching tool call, the hook runs the client implementation and resumes the run automatically. useStream is available from @langchain/react, @langchain/vue, @langchain/svelte, and @langchain/angular.

Rendering tool activity inline with stream.toolCalls

Match each entry in stream.toolCalls back to the AI message that triggered it by filtering tool calls where call.id matches one of message.tool_calls ids. Render each tool call as a separate card or component. This works well with specialized rendering for each tool type instead of raw JSON output.

Example React useStream with headless tools

export function Chat() { const stream = useStream<AgentState>({ apiUrl: 'http://localhost:2024', assistantId: 'headless_tools', tools: [memoryPut, memoryGet, geolocationGet] }); return <ChatView messages={stream.messages} toolCalls={stream.toolCalls} />; } The useStream hook receives apiUrl, assistantId, and an array of implemented tools. It exposes stream.messages and stream.toolCalls for rendering.

Example filtering tool calls by AI message

function Message({ message, toolCalls }: { message: AIMessage, toolCalls: ToolCallWithResult[] }) { const messageToolCalls = toolCalls.filter((tc) => message.tool_calls?.some((call) => call.id === tc.call.id)); return ( <div> {message.text && <p>{message.text}</p>} {messageToolCalls.map((tc) => ( <HeadlessToolCard key={tc.call.id} toolCall={tc} /> ))} </div> ); } This pattern matches tool calls to their triggering AI message by comparing call IDs.

AI Elements PromptInput submission pattern

PromptInput component calls onSubmit with text input. Submit to stream via stream.submit({ messages: [{ type: "human", content: text }] }). Set submit button status to stream.isLoading ? "streaming" : "ready".

AI Elements wiring pattern with useStream

Render AI Elements components directly from stream.messages. Iterate over messages and map LangChain BaseMessage types to components: HumanMessage instances render as user bubbles using Message from="user", AIMessage instances render as assistant responses using Message from="assistant".

AI Elements example: Chat component with reasoning and tool calls

import { useStream } from "@langchain/react"; import { HumanMessage, AIMessage } from "langchain"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { Tool, ToolHeader, ToolContent, ToolInput, ToolOutput, } from "@/components/ai-elements/tool"; import { Reasoning, ReasoningTrigger, ReasoningContent, } from "@/components/ai-elements/reasoning"; import { PromptInput, PromptInputBody, PromptInputTextarea, PromptInputFooter, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; function getReasoningText(msg: AIMessage) { return msg.contentBlocks.find((block) => block.type === "reasoning")?.reasoning ?? ""; } function getTextContent(msg: AIMessage) { return msg.text; } function getToolCalls(msg: AIMessage) { return (msg.tool_calls ?? []).map((tc) => ({ id: tc.id, name: tc.name, args: tc.args, state: "input-available" as const, })); } export function Chat() { const stream = useStream({ apiUrl: "http://localhost:2024", assistantId: "ai_elements", }); return ( <div className="flex flex-col h-dvh"> <Conversation className="flex-1"> <ConversationContent> {stream.messages.map((msg, i) => { if (HumanMessage.isInstance(msg)) { return ( <Message key={i} from="user"> <MessageContent>{msg.text}</MessageContent> </Message> ); } if (AIMessage.isInstance(msg)) { return ( <div key={i}> {/* Reasoning block (shows when model emits thinking tokens) */} <Reasoning> <ReasoningTrigger /> <ReasoningContent>{getReasoningText(msg)}</ReasoningContent> </Reasoning> {/* Inline tool calls with input/output display */} {getToolCalls(msg).map((tc) => ( <Tool key={tc.id} defaultOpen> <ToolHeader type={`tool-${tc.name}`} state={tc.state} /> <ToolContent> <ToolInput input={tc.args} /> {tc.output && ( <ToolOutput output={tc.output} errorText={undefined} /> )} </ToolContent> </Tool> ))} {/* Streamed text response */} <Message from="assistant"> <MessageContent> <MessageResponse>{getTextContent(msg)}</MessageResponse> </MessageContent> </Message> </div> ); } })} </ConversationContent> <ConversationScrollButton /> </Conversation> <PromptInput onSubmit={({ text }) => stream.submit({ messages: [{ type: "human", content: text }] }) } > <PromptInputBody> <PromptInputTextarea placeholder="Ask me something..." /> </PromptInputBody> <PromptInputFooter> <PromptInputSubmit status={stream.isLoading ? "streaming" : "ready"} /> </PromptInputFooter> </PromptInput> </div> ); } This example shows how to wire AI Elements components with useStream, handle reasoning blocks extracted from AIMessage.contentBlocks, render tool calls with input and output, and manage conversation UI with scroll behavior.

AI Elements reasoning block extraction from AIMessage

Extract reasoning content from an AIMessage by finding the content block with type "reasoning": msg.contentBlocks.find((block) => block.type === "reasoning")?.reasoning. Reasoning blocks render with the Reasoning component wrapping ReasoningTrigger and ReasoningContent.

AI Elements MessageResponse for streaming

Use MessageResponse component for streamed partial tokens, not raw message content. MessageResponse handles streamed partial tokens correctly during streaming.

AI Elements message type checking with isInstance

Use HumanMessage.isInstance(msg) and AIMessage.isInstance(msg) rather than checking msg.getType() for proper TypeScript type narrowing when iterating stream.messages.

useStream setup for join/rejoin in Vue

To set up useStream for join/rejoin in Vue, import useStream from @langchain/vue. Initialize it with threadId retrieved from sessionStorage as a ref. Use the onThreadId callback to update the thread ID and persist it to sessionStorage. Example: const threadId = ref<string | null>(sessionStorage.getItem('activeThreadId')); const stream = useStream<typeof myAgent>({ apiUrl: 'http://localhost:2024', assistantId: 'join_rejoin', threadId, onThreadId(id) { threadId.value = id; if (id) sessionStorage.setItem('activeThreadId', id); } });

Use cases for join and rejoin

Join and rejoin enables several patterns: network interruptions where mobile users can seamlessly resume across cell towers or Wi-Fi networks; page navigation where users can navigate away from a chat page and return later without losing progress; mobile backgrounding where apps suspended by the OS can rejoin the stream when foregrounded; long-running tasks where agents performing multi-minute operations like research, code generation, or data analysis can continue while users don't keep the page open; and multi-device handoff where conversations started on one device can be resumed on another.

Core join/rejoin mechanisms

Join/rejoin involves four key mechanisms: threadId binds the stream to the LangGraph thread you want to observe; onThreadId persists newly-created thread IDs so a remount can reconnect; stream.disconnect() leaves the stream client-side while the agent keeps running server-side; and remounting with the same threadId reattaches to in-flight work for that thread.

useStream setup for join/rejoin in Svelte

To set up useStream for join/rejoin in Svelte, import useStream from @langchain/svelte. Initialize threadId from sessionStorage as a state variable and pass it as a function to useStream. Use the onThreadId callback to update the thread ID state and persist it to sessionStorage. Example: let threadId = $state<string | null>(sessionStorage.getItem('activeThreadId')); const stream = useStream<typeof myAgent>({ apiUrl: 'http://localhost:2024', assistantId: 'join_rejoin', threadId: () => threadId, onThreadId(id) { threadId = id; if (id) sessionStorage.setItem('activeThreadId', id); } });

useStream setup for join/rejoin in Angular

To set up useStream for join/rejoin in Angular, import injectStream from @langchain/angular and use it in a component. Create signals for threadId, connected, and mountKey. Initialize threadId from sessionStorage. Pass threadId as a signal to injectStream and use the onThreadId callback to update the threadId signal and persist it to sessionStorage. Example: threadId = signal<string | null>(sessionStorage.getItem('activeThreadId')); stream = injectStream<typeof myAgent>({ apiUrl: 'http://localhost:2024', assistantId: 'join_rejoin', threadId: this.threadId, onThreadId: (id) => { this.threadId.set(id); if (id) sessionStorage.setItem('activeThreadId', id); } });

Submitting messages in join/rejoin

Submit messages normally using stream.submit({ messages: [{ type: 'human', content: text }] }). The thread ID binding is what allows a later remount to reconnect to the same conversation.

Disconnecting from a stream

Call stream.disconnect() to leave the stream without cancelling the run. This is equivalent to calling stream.stop({ cancel: false }). Do not use stream.stop() for join/rejoin as it cancels the run on the server. After calling disconnect(), stream.isLoading becomes false, the message list retains all messages received up to the disconnect point, the agent continues running on the server, and no new messages are received until you rejoin.

Rejoining a stream

Remount the stream consumer with the saved thread ID to reconnect. In React, bump a mountKey (e.g., setMountKey((key) => key + 1)); in other frameworks, use the equivalent remount or conditional-render pattern. After rejoining, connected becomes true, any messages generated while disconnected are delivered, new streaming messages resume in real-time, and if the agent is still running, stream.isLoading becomes true; if it has already finished, you receive the final state immediately.

Best practices for join/rejoin

Use disconnect() for join/rejoin and stop() to cancel: navigating away or backgrounding the app should call stream.disconnect(), while a user-facing Stop or Cancel button should call stream.stop() or client.runs.cancel. Always save the thread ID without it, rejoining is impossible; use both component state and persistent storage for resilience. Show clear connection state so users always know whether they are receiving live updates or viewing a snapshot. Auto-rejoin on visibility change using the Page Visibility API to automatically rejoin when the user returns to the tab. Set reasonable timeouts; if a rejoin attempt takes too long, fall back to fetching the thread history instead. Clean up stale threads by removing persisted thread IDs when the user starts over or the backend reports that the thread is unavailable.

stream.disconnect() vs stream.stop()

Join/rejoin uses stream.disconnect(), not stream.stop(). By default, stream.stop() cancels the active run: it disconnects the client and cancels the run on the server. For join/rejoin, call stream.disconnect() (alias for stop({ cancel: false })) so the agent continues processing while you are away. To cancel execution explicitly from app code, use stream.stop() or client.runs.cancel.

useStream setup for join/rejoin in React

To set up useStream for join/rejoin in React, import useStream from @langchain/react and initialize it with threadId retrieved from persistent storage (e.g., sessionStorage). Pass the threadId to useStream and use the onThreadId callback to persist the thread ID when it is created. Example: const stream = useStream<typeof myAgent>({ apiUrl: 'http://localhost:2024', assistantId: 'join_rejoin', threadId, onThreadId(id) { setThreadId(id); if (id) sessionStorage.setItem('activeThreadId', id); } });

Join and rejoin pattern overview

Join and rejoin lets you disconnect from a running agent stream without stopping the agent, then reconnect to it later. The agent continues executing server-side while the client is away, and you pick up the stream exactly where you left off.

React useStream hook with TypeScript types

const stream = useStream<typeof myAgent>({ apiUrl: AGENT_URL, assistantId: "simple_agent", }); The useStream hook from @langchain/react takes a generic type parameter matching the agent type and returns a stream object with a messages array. Messages include AIMessage and HumanMessage instances with id and text properties.

Vue useStream hook with TypeScript types

const stream = useStream<typeof myAgent>({ apiUrl: AGENT_URL, assistantId: "simple_agent", }); The useStream hook from @langchain/vue takes a generic type parameter matching the agent type and returns a stream object with messages.value containing the message array. Messages include AIMessage and HumanMessage instances.

Svelte useStream hook with TypeScript types

const stream = useStream<typeof myAgent>({ apiUrl: AGENT_URL, assistantId: "simple_agent", }); The useStream hook from @langchain/svelte takes a generic type parameter matching the agent type and returns a stream object with a messages property containing the message array.

Angular injectStream function with TypeScript types

const stream = injectStream<typeof myAgent>({ apiUrl: AGENT_URL, assistantId: "simple_agent", }); Angular uses injectStream instead of useStream. It takes a generic type parameter matching the agent type and returns a stream object callable with stream.messages() to get the message array.

React does not require HTML sanitization

React's react-markdown converts markdown directly to React elements rather than producing raw HTML, so dompurify is not needed. There is no dangerouslySetInnerHTML involved, making React's approach inherently safer than Vue, Svelte, or Angular approaches that render HTML strings.

useStream hook for markdown message rendering

The useStream hook from @langchain packages (react, vue, svelte, angular) is used to accumulate streamed text into msg.text on each AI message. It takes two parameters: apiUrl (the agent URL like 'http://localhost:2024') and assistantId (like 'simple_agent'). It returns an object with a messages property containing the chat messages.

Markdown rendering pipeline for streamed LLM responses

The markdown rendering pipeline has three steps: (1) Receive - useStream accumulates streamed text into msg.text on each AI message, updating reactively as new tokens arrive; (2) Parse - a markdown parser converts the raw text to HTML or React element tree, running on every update but fast enough for chat-length content under 5ms for a 5 KB message; (3) Render - the parsed output is rendered into the DOM using React virtual DOM diffing or Vue/Svelte v-html/{@html} with sanitized HTML.

Recommended markdown libraries by framework

Framework selection for markdown rendering: React uses react-markdown + remark-gfm producing React elements with component-based virtual DOM diffing and no dangerouslySetInnerHTML; Vue uses marked + dompurify producing sanitized HTML via v-html; Svelte uses marked + dompurify producing sanitized HTML via {@html}; Angular uses marked + dompurify producing sanitized HTML via [innerHTML].

HTML sanitization with dompurify for markdown rendering

When rendering parsed markdown as raw HTML using v-html, {@html}, or [innerHTML], always sanitize the output with dompurify to prevent cross-site scripting. Use DOMPurify.sanitize(rawHtml) to strip dangerous elements. DOMPurify removes script tags, onclick attributes, javascript: URLs, and other XSS vectors while preserving safe markdown output like headings, lists, code blocks, tables, and links.

React Markdown component example with remark-gfm

import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; export function Markdown({ children }: { children: string }) { return ( <div className="markdown-content"> <ReactMarkdown remarkPlugins={[remarkGfm]}> {children} </ReactMarkdown> </div> ); } This example shows how to build a React Markdown component that renders LLM responses with GitHub Flavored Markdown support using react-markdown and remark-gfm plugins.

Vue Markdown component with marked and dompurify

import { computed, useSlots } from "vue"; import { marked } from "marked"; import DOMPurify from "dompurify"; marked.setOptions({ gfm: true, breaks: true }); const slots = useSlots(); const html = computed(() => { const slot = slots.default?.(); const text = slot ?.map((vnode) => typeof vnode.children === "string" ? vnode.children : "" ) .join("") ?? ""; if (!text) return ""; return DOMPurify.sanitize(marked.parse(text) as string); }); Template: <div class="markdown-content" v-html="html" /> This Vue component parses markdown with GFM and breaks enabled, sanitizes it, and renders it using v-html.

Svelte Markdown component with marked and dompurify

import { marked } from "marked"; import DOMPurify from "dompurify"; let { content }: { content: string } = $props(); marked.setOptions({ gfm: true, breaks: true }); let html = $derived.by(() => { if (!content) return ""; return DOMPurify.sanitize(marked.parse(content) as string); }); Template: <div class="markdown-content">{@html html}</div> This Svelte component parses markdown with GFM and breaks enabled, sanitizes it, and renders it using {@html}.

Angular Markdown component with marked and dompurify

import { Component, Input, computed, signal } from "@angular/core"; import { marked } from "marked"; import DOMPurify from "dompurify"; marked.setOptions({ gfm: true, breaks: true }); @Component({ selector: "app-markdown", template: `<div class="markdown-content" [innerHTML]="html()"></div>`, }) export class MarkdownComponent { @Input() set content(value: string) { this._content.set(value); } private _content = signal(""); html = computed(() => { const text = this._content(); if (!text) return ""; return DOMPurify.sanitize(marked.parse(text) as string); }); } This Angular component uses signals and computed properties to parse markdown with GFM and breaks enabled, sanitize it, and render it using [innerHTML].

Markdown parsing performance characteristics

Marked parses at approximately 1 MB/s. A 5 KB message takes less than 5ms to parse. React-markdown with remark pipeline is similarly fast for chat-length content. The browser layout engine handles DOM updates efficiently for typical chat messages.

Performance optimization for very long markdown responses

For responses longer than 50 KB, consider these optimizations: (1) Throttle renders using requestAnimationFrame to batch updates at 60fps instead of re-rendering on every token; (2) Incremental parsing - parse only new content and append to a rendered buffer, though this is advanced and typically not needed for chat UIs.

Markdown rendering best practices for LLM responses

Best practices for rendering markdown from LLMs: (1) Always sanitize when using v-html, {@html}, or [innerHTML], running parsed output through dompurify and never trusting raw HTML from markdown parsers; (2) Enable GFM (GitHub Flavored Markdown) which adds tables, strikethrough, task lists, and autolinks commonly used by LLMs; (3) Handle empty content by checking for empty strings before parsing; (4) Use breaks: true to enable line break conversion so single newlines render as <br> rather than being ignored; (5) Style for chat context with compact margins and sizes appropriate for chat bubbles; (6) Test with rich content including headings, nested lists, code blocks with long lines, wide tables, and blockquotes.

useStream and injectStream API usage

React, Vue, and Svelte frameworks use the useStream hook imported from their respective packages: useStream from @langchain/react for React, useStream from @langchain/vue for Vue, and useStream from @langchain/svelte for Svelte. Angular uses injectStream instead, imported from @langchain/angular.

Type inference with useStream

Pass a type parameter to useStream or injectStream for type-safe access to stream.messages, stream.toolCalls, stream.interrupt, stream.values, and other reactive state. In Python, define a TypeScript interface matching the agent's state schema and pass it as the type parameter. In JavaScript, import your agent and pass typeof myAgent as the type parameter, allowing TypeScript to infer the state schema from the compiled graph automatically.

Give your agent this brain