RAG pattern flow
In Retrieval-Augmented Generation (RAG), a user question is processed by both a retriever and a chat model in parallel. The retriever returns relevant documents, which are combined with the original question and provided to the chat model to generate an informed response.
Multi-agent system pattern flow
In a multi-agent system, a complex task is received by a supervisor agent, which delegates work to specialist agents. Each specialist agent produces results that are collected, fed back to the supervisor, which then produces a coordinated response.
Agent with tools pattern flow
In the agent with tools pattern, a user request enters an agent, which decides whether a tool is needed. If yes, it calls the tool, receives a result, and feeds it back to itself for further processing. If no tool is needed, the agent produces a final answer.
Retrieve branching history
Use stream.client.threads.getHistory(threadId) to retrieve the checkpoint history when building a separate timeline view across checkpoints for branching conversations.
Branching chat React setup example
Example of setting up branching chat in React using useStream hook:
```tsx
import { useStream } from "@langchain/react";
const AGENT_URL = "http://localhost:2024";
export function Chat() {
const stream = useStream<typeof myAgent>({
apiUrl: AGENT_URL,
assistantId: "simple_agent",
});
return (
<div>
{stream.messages.map((msg) => (
<MessageWithForkControls key={msg.id} stream={stream} message={msg} />
))}
</div>
);
}
```
Message edit handler example
Example of handling message edits with branching:
```ts
function handleEdit(
stream: ReturnType<typeof useStream>,
originalMsg: HumanMessage,
metadata: MessageMetadata | undefined,
newText: string
) {
if (!metadata?.parentCheckpointId) return;
stream.submit(
{
messages: [{ type: "human", content: newText }],
},
{ forkFrom: { checkpointId: metadata.parentCheckpointId } }
);
}
```
Message regenerate handler example
Example of handling message regeneration with branching:
```ts
function handleRegenerate(
stream: ReturnType<typeof useStream>,
metadata: MessageMetadata | undefined
) {
if (!metadata?.parentCheckpointId) return;
stream.submit(undefined, {
forkFrom: { checkpointId: metadata.parentCheckpointId },
});
}
```
Branching chat best practices
Best practices for branching chat implementation: (1) call useMessageMetadata in the component rendering message controls to keep metadata scoped, (2) show fork controls on hover to keep UI clean, (3) call client.threads.getHistory() only when rendering a timeline or after a fork settles, (4) check stream.isLoading before enabling edits or regeneration to disable controls while streaming, (5) reset textarea to original content if user cancels an edit, and (6) ensure timeline rendering remains performant for users creating many paths through frequent edits and regenerations.
Regeneration useful for non-deterministic agents
Regeneration is useful for non-deterministic agents. Since LLM outputs vary with temperature, regenerating the same prompt often produces meaningfully different responses.
Edit message implementation
To edit a user message and fork the conversation: (1) get parentCheckpointId from the message's metadata, (2) submit the edited message with forkFrom: { checkpointId: metadata.parentCheckpointId }, and (3) the agent re-runs from that point. The original path remains available in thread history.
Regenerate response implementation
To regenerate an AI response without changing the input: (1) get parentCheckpointId from the AI message's metadata, (2) submit with undefined input and forkFrom: { checkpointId: metadata.parentCheckpointId }, and (3) the agent produces a fresh response from that point. Each regeneration creates a new path for the AI message at that position.
Branching checkpoint structure
LangGraph persists every state transition as a checkpoint. When submitting with forkFrom, the backend starts a new execution path from that checkpoint instead of appending to the current conversation. The result is a tree structure where each path is persisted in the checkpoint store.
Branching chat pattern overview
Branching chat treats conversations as checkpointed timelines rather than flat lists. Each message has metadata pointing to the checkpoint before it was created. Editing a message or regenerating a response submits a new run from that checkpoint, creating a tree structure of conversation paths rather than a linear history.
Branching chat key capabilities
Branching chat supports three key capabilities: editing any user message by rewriting a previous prompt and re-running the agent from that point, regenerating any AI response to ask the agent to produce a different answer for the same input, and inspecting history using the LangGraph client to load checkpoints when building a branch timeline.
Message metadata for branching
The useMessageMetadata(stream, messageId) helper returns MessageMetadata for one message. The metadata includes parentCheckpointId, which is the checkpoint just before the message. This parentCheckpointId is used as the fork point for edits and regenerations.
When to use declarative generative UI instead
When the agent needs to compose layouts not anticipated in advance, across the long tail of secondary interactions, move to declarative generative UI rather than controlled generative UI.
Tool-call rendering pattern
Tool-call rendering turns each stage of a tool call lifecycle into purpose-built UI. The lifecycle includes pending, complete, and failed states. Instead of showing raw JSON, tool-call rendering displays a loading card while a search runs, a result card when it returns, and an error state if it fails, making the agent's actions legible.
State rendering pattern
State rendering binds UI components to durable, typed state beyond the message list, such as todos, pipeline outputs, citations, sandbox files, metrics, and custom business objects. As the agent updates state, the interface updates with it, becoming a live view of the agent's work rather than a transcript.
Reasoning rendering pattern
Rendering reasoning shows users how the agent arrived at a result when models with extended thinking produce reasoning separate from their final answer. This builds trust, aids debugging, and supports auditing. The developer controls how and when the reasoning appears, for example in a collapsible block distinct from the response.
Controlled generative UI advantages
Controlled generative UI provides the highest predictability of any generative UI approach. The developer controls branding, layout, accessibility, and behavior exactly, and can guarantee that whatever the agent surfaces has already passed review.
Controlled generative UI definition
Controlled generative UI is an author-controlled approach to generative UI where the developer writes the components and the agent decides which one to render and what data to pass into it. The agent never produces markup; it chooses from a fixed set of interfaces the developer builds and tests.
Components as tools pattern
Components as tools exposes UI components to the agent the way tools are exposed. Each component has a name, a description, and a typed set of properties. The agent selects a component and supplies its data as part of its response. The frontend maps the agent's choice to the real implementation.
Controlled generative UI tradeoff
The tradeoff of controlled generative UI is engineering cost: each new capability needs a component the developer writes in advance. The component library is the boundary; the agent can only render what was shipped.
Use cases for controlled generative UI
Use controlled generative UI on high-traffic, brand-critical surfaces where the set of outputs is known ahead of time and correctness matters more than novelty, such as forms, confirmation flows, and any surface with strict branding or accessibility requirements.
CopilotKit best practices for custom endpoints
Keep custom endpoint thin for adapting CopilotKit to graph deployment, not duplicating business logic. Send schema explicitly via useAgentContext every page mount. Register constrained component set exposing only components and props actually wanted. Treat rendering as parsing step before rendering. Keep user messages plain; only assistant messages need structured renderer.
OpenUI best practice: gate on complete statements
Avoid re-rendering the Renderer on every token; update only when a full statement (name = ComponentCall(...)) has arrived.
OpenUI best practice: verify chart data before rendering
Chart components need their Series and label arrays defined before they're included in the stable snapshot.
OpenUI best practice: keep camelCase variable names
The openui-lang parser only accepts camelCase identifiers; reinforce this in the system prompt's additionalRules.
OpenUI best practice: scope each panel to its subagent
Discover panels from stream.subagents and pass each snapshot to useMessages(stream, snapshot) so a panel renders only its own subagent's output. Memoize each Panel so the app shell's re-renders never reach the Renderer; the panel's own tokens arrive through useMessages.
OpenUI best practice: delegate Deep Agents panels in one message
When fanning out to Deep Agents specialists, emit all task() calls in a single coordinator message so the panels stream concurrently rather than one at a time.
OpenUI: generative UI library for component trees
OpenUI is a generative UI library that lets a language model produce complete, interactive UIs in a declarative format called openui-lang. Instead of returning a chat message, the agent returns a component tree with cards, charts, tables, tabs, and forms that the Renderer turns into a real React UI. This integration is well-suited for data-rich outputs like reports, dashboards, and data explorers, where the model is both the data analyst and the UI designer.
OpenUI workflow: four-step process
The OpenUI workflow consists of four steps: (1) Generate the system prompt by calling openuiLibrary.prompt() once at startup, which produces a complete openui-lang reference that the model uses to write valid component trees. (2) Inject the system prompt on first message as the opening system message when a new conversation starts. (3) The model writes openui-lang, responding with a program like 'root = Stack([header, kpis, chart])' instead of prose. (4) Render with Renderer by passing the text to OpenUI's Renderer and the component library, which parses and renders the tree.
OpenUI installation dependencies
Install OpenUI with: npm install @langchain/react @openuidev/react-ui @openuidev/react-headless @openuidev/react-lang. OpenUI requires React 19+ and zustand. The frontend code is React-only; the LangGraph agent backend can be written in TypeScript or Python.
OpenUI CSS imports
Import OpenUI's bundled styles in the CSS entry point or directly in the root component: @import "@openuidev/react-ui/components.css"; @import "@openuidev/react-ui/styles/index.css";
Generate OpenUI system prompt with openuiLibrary.prompt()
Call openuiLibrary.prompt() once at module load time (not inside a component) to generate the full openui-lang system prompt. The function accepts an options object with openuiPromptOptions spread, and can override the preamble to customize the model's persona. Use additionalRules to inject task-specific constraints. Example: const SYSTEM_PROMPT = openuiLibrary.prompt({ ...openuiPromptOptions, preamble: "You are a report generator...", additionalRules: [...(openuiPromptOptions.additionalRules ?? []), "Your custom rule here"] }).
Inject OpenUI system prompt via useStream on first message only
Send the system prompt as the first message of every new thread. Check stream.messages.length === 0 to detect a fresh thread and prepend a system message with the prompt content. Subsequent messages already have it in their persisted history, so skip injection on subsequent turns to avoid duplicating the prompt.
Render OpenUI with Renderer component
Pass the AI message's text content directly to Renderer along with openuiLibrary. The Renderer component accepts response (the text), library (openuiLibrary), and isStreaming (true during active stream for graceful handling of unresolved references as definitions arrive).
openui-lang format: assignment-based program
The model writes a program rather than JSON. Every statement is an assignment; root is the entry point. The official prompt teaches the model this format, including hoisting — writing root first so the UI shell appears immediately. Example: root = Stack([header, execSummary, kpis, marketSection]) followed by definitions of each component.
OpenUI progressive rendering utilities table
Problem | Solution
--- | ---
**Partial string literals** | truncateAtOpenString / closeOrTruncateOpenString — drop or close incomplete strings before parsing
**Mid-token churn** | useStableText — gate Renderer updates on complete statement boundaries (name = Expr(…)) rather than every token
**Chart null-data crashes** | chartDataRefsResolved — verify a chart's Series and label arrays are defined before including it in the snapshot
**No root yet / fallback** | buildProgressiveRoot — synthesise a root = Stack([…]) from top-level variables when the model hasn't written one
**Snake_case identifiers** | sanitizeIdentifiers — the parser only accepts camelCase; convert any snake_case names the model emits
stripCodeFence utility for OpenUI
Strip any markdown code fence the model may have emitted from OpenUI output: function stripCodeFence(text: string): string { return text.replace(/^```[a-z]*\r?\n?/i, "").replace(/\n?```\s*$/i, "").trim(); }
sanitizeIdentifiers utility converts snake_case to camelCase
The openui-lang parser only accepts camelCase identifiers. The sanitizeIdentifiers function converts any snake_case variable names the model emits; string content is untouched. It tracks variables defined with snake_case in assignments and replaces them throughout the text while preserving string literals.
truncateAtOpenString prevents partial string parsing errors
Walk the text tracking open strings. If the text ends mid-string, truncate to the last safe newline — this prevents a partial string literal from consuming any root = Stack(…) line that might be synthesised later.
closeOrTruncateOpenString for streaming TextContent
Like truncateAtOpenString, but synthesises a closing ")" when the partial line is a TextContent statement. This lets text render token-by-token while all other partial-string lines are still truncated, enabling progressive text rendering without waiting for the full line to complete.
chartDataRefsResolved prevents chart crashes on null data
Chart components (recharts) crash with .map() on null when their labels or series props are unresolved. Before committing a stable snapshot, verify that every chart in the text has all its data variables already defined by checking that all identifiers referenced in chart expressions are in the complete set of variables with finished assignments.
buildProgressiveRoot synthesises root when model writes it last
If the model hasn't written a root = Stack(…) yet, synthesise one from the top-level variables (those defined but not referenced inside any other expression). This enables progressive rendering even when the model writes root last. It identifies top-level variables by finding definitions not referenced elsewhere, or defaults to all definitions if none are top-level.
useStableText hook gates Renderer updates to complete statements
Gate Renderer updates to moments when at least one new complete statement has arrived. This eliminates hundreds of no-op re-parses during streaming. Special case: TextContent lines update token-by-token (via closeOrTruncate) so text renders progressively without waiting for the full line to complete.
OpenUI follow-up queries with Button continue_conversation
OpenUI's Button component supports a continue_conversation action type. When the user clicks a follow-up button, Renderer fires onAction and the AIMessageView submits the button's label as the next user message, exactly the same code path as typing in the input. Add an Explore Further section to reports via additionalRules with Button components set to type: 'continue_conversation'.
Deep Agents parallel dashboards with OpenUI
For richer apps, a Deep Agents coordinator can delegate to several specialist agents that each stream their own OpenUI panel concurrently, all over one useStream connection. Each panel subagent receives the shared OpenUI system prompt and tools for its data domain. The coordinator's only job is routing: it picks the specialists a brief needs and emits all of their task() calls in one message so the panels run concurrently.
OpenUI Deep Agents: share one library across server and client
Use the same library object on the server (to generate the panel prompt) and on the client (as the Renderer prop) so the components the model is told about always match the ones the renderer can draw. Export the library and promptOptions from a shared file and use the same library across all panel agents and renderers.
OpenUI Deep Agents coordinator delegates in one message
The coordinator only routes and emits all subagent task() calls in one message so the panels run concurrently. It never writes openui-lang itself. Each panel agent calls its tools, then returns one complete program that starts with root so its renderer can paint before the model finishes the remaining statements.
Discover and render OpenUI panels with useMessages projection
One useStream connection carries the coordinator and every panel. The panels are not hardcoded: each parallel task() call surfaces as a stream.subagents snapshot. For each snapshot, scope a useMessages(stream, snapshot) projection so a panel receives only its own subagent's messages, then feed its OpenUI program into an isolated Renderer. Each Panel should be memoized so the app shell's re-renders never reach the Renderer; the panel's tokens arrive through useMessages.
OpenUI best practice: generate system prompt at module load
Generate the system prompt at module load, not inside a React component. The prompt is several kilobytes and should be computed once to keep the prompt prefix stable for provider prompt caching.
OpenUI best practice: inject system prompt only on fresh threads
Check stream.messages.length === 0 and skip injection on subsequent turns to avoid duplicating the prompt in the thread history.
OpenUI best practice: use hoisting order
Write root = Stack([...]) first; the UI shell appears immediately and sections fill in progressively as the model defines each one.
MCP Apps extend Model Context Protocol to interfaces
MCP Apps extend the Model Context Protocol to interface: an MCP server ships interactive UI and the frontend renders it, usually in an iframe, directly in the conversation. The server owns the components, the data, and the interactions, while your application provides the frame and the connection to the agent.
Frontend pattern selection for agent UIs
LangChain recommends selecting frontend patterns based on user needs: use Tool calling and reasoning tokens for users to understand agent actions; use Human-in-the-loop for safely approving sensitive actions; use Message queues for sending work while a run is active; use Join & rejoin streams for users leaving and returning to long-running work; use Branching chat and time travel for editing or retrying from earlier turns; use Structured output, generative UI, and Deep Agents frontend patterns for rendering state as an application rather than chat.
Document class attributes in LangChain
A LangChain Document object has three attributes: page_content (a string representing the content), metadata (a dict containing arbitrary metadata), and id (optional, a string identifier for the document). In JavaScript, these are pageContent, metadata, and id respectively.
RecursiveCharacterTextSplitter parameters
RecursiveCharacterTextSplitter takes the following parameters: chunk_size (target size for each chunk), chunk_overlap (overlap between consecutive chunks), and add_start_index (boolean to add start_index metadata field for character offset in original document).
VectorStore query methods
VectorStore objects support multiple query methods: similarity_search (query by string), similarity_search_with_score (returns documents with similarity scores), similarity_search_by_vector (query by pre-computed embedding vector), and maximum marginal relevance search (balance similarity with diversity).
VectorStore async operations
VectorStore supports asynchronous queries using asimilarity_search method to retrieve documents without blocking.