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

common patterns

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

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.

Give your agent this brain