diff --git a/src/oss/javascript/integrations/providers/all_providers.mdx b/src/oss/javascript/integrations/providers/all_providers.mdx
index b37e72f984..703a426c72 100644
--- a/src/oss/javascript/integrations/providers/all_providers.mdx
+++ b/src/oss/javascript/integrations/providers/all_providers.mdx
@@ -70,6 +70,14 @@ Connect LangGraph agents to front ends.
>
React stack and Python middleware for Deep Agents, LangGraph agents, FastAPI, and generative UI.
+
+
+ Render adaptive, agent-generated interfaces from LangGraph and Deep Agents using OpenUI.
+
## Chat models
diff --git a/src/oss/langchain/frontend/integrations/openui.mdx b/src/oss/langchain/frontend/integrations/openui.mdx
index fce537ce7a..79a5c7b227 100644
--- a/src/oss/langchain/frontend/integrations/openui.mdx
+++ b/src/oss/langchain/frontend/integrations/openui.mdx
@@ -103,7 +103,7 @@ const SYSTEM_PROMPT = openuiLibrary.prompt({ ... });
export function App() {
const stream = useStream({
- apiUrl: import.meta.env.VITE_LANGGRAPH_API_URL ?? "/api/langgraph",
+ apiUrl: import.meta.env.VITE_LANGGRAPH_API_URL ?? "http://localhost:2024",
assistantId: "openui",
});
@@ -497,6 +497,189 @@ followUpCard = Card([CardHeader("Explore Further"), followUpBtns], "sunk")
root = Stack([..., followUpCard])
```
+## Build a parallel dashboard with Deep Agents
+
+The flow above renders one OpenUI program into one surface. For richer apps, a [Deep Agents](/oss/deepagents/overview) coordinator can delegate to several specialist agents that each stream their own OpenUI panel concurrently, all over one @[`useStream`] connection. The [OpenUI parallel dashboard example](https://github.com/langchain-ai/streaming-cookbook/tree/main/typescript/openui) turns one dashboard brief into independently streaming Stripe, PostHog, GitHub, and Calendar panels, with no custom graph or stream-demultiplexing code.
+
+```mermaid
+%%{
+ init: {
+ "fontFamily": "monospace",
+ "flowchart": {
+ "curve": "curve"
+ }
+ }
+}%%
+graph LR
+ BRIEF["User brief"]
+ COORD["Deep Agents coordinator"]
+ PANELS["Stripe / PostHog / GitHub / Calendar panel agents"]
+ SUBAGENTS["stream.subagents"]
+ RENDERER["Renderer per panel"]
+
+ BRIEF --> COORD
+ COORD --"parallel task() calls"--> PANELS
+ PANELS --"namespaced events"--> SUBAGENTS
+ SUBAGENTS --"useMessages(stream, snapshot)"--> RENDERER
+```
+
+### Share one OpenUI library
+
+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:
+
+```ts library.ts
+import { openuiChatLibrary, openuiChatPromptOptions } from "@openuidev/react-ui";
+
+export const library = openuiChatLibrary;
+export const promptOptions = openuiChatPromptOptions;
+```
+
+### Define the coordinator and panel agents
+
+@[`createDeepAgent`] builds a coordinator whose 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. Each panel subagent shares one pre-generated OpenUI system prompt and receives only the tools for its data domain.
+
+```ts expandable agent.ts
+import { createDeepAgent, type SubAgent } from "deepagents";
+
+import { library, promptOptions } from "./library.js";
+import { calendarTools, githubTools, posthogTools, stripeTools } from "./tools.js";
+
+// The coordinator only routes, so a fast model handles it; panels generate
+// strict openui-lang and stay on the frontier model.
+const COORDINATOR_MODEL = "openai:gpt-5.4-mini";
+const PANEL_MODEL = "openai:gpt-5.5";
+
+// Generate the shared panel prompt once at module load so the model prefix
+// stays stable for provider prompt caching.
+const PANEL_SYSTEM_PROMPT = library.prompt({
+ ...promptOptions,
+ preamble:
+ "Build one panel of a live executive dashboard. Follow the coordinator's " +
+ "task exactly and stay within the data available from your tools.",
+ additionalRules: [
+ ...(promptOptions.additionalRules ?? []),
+ "Use your available data tools before writing the panel.",
+ "Return the complete openui-lang program and nothing else.",
+ "Emit the `root` statement on the first line so rendering can start immediately.",
+ ],
+});
+
+const subagents: SubAgent[] = [
+ {
+ name: "stripe-panel",
+ model: PANEL_MODEL,
+ description: "Builds the revenue and payments panel from Stripe data.",
+ systemPrompt: PANEL_SYSTEM_PROMPT,
+ tools: stripeTools,
+ },
+ // posthog-panel, github-panel, and calendar-panel follow the same shape.
+];
+
+const COORDINATOR_PROMPT = `You orchestrate a live executive dashboard.
+
+1. Delegate immediately. Never write openui-lang yourself.
+2. Launch all selected specialists in a SINGLE message, one task call per
+ panel, so they run concurrently.
+3. Give each task a distinct, self-contained description.
+4. After the tasks complete, reply with one short plain-text summary.`;
+
+export const dashboard = createDeepAgent({
+ model: COORDINATOR_MODEL,
+ systemPrompt: COORDINATOR_PROMPT,
+ subagents,
+});
+```
+
+The coordinator never writes openui-lang. 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.
+
+### Register the graph
+
+Point `langgraph.json` at the exported coordinator:
+
+```json langgraph.json
+{
+ "node_version": "22",
+ "graphs": {
+ "dashboard": "./src/agent.ts:dashboard"
+ },
+ "env": "../../.env"
+}
+```
+
+### Discover and render panels on the frontend
+
+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`:
+
+```tsx expandable App.tsx
+import { memo } from "react";
+
+import type { SubagentDiscoverySnapshot } from "@langchain/langgraph-sdk/stream";
+import { useMessages, useStream } from "@langchain/react";
+import { Renderer, type ActionEvent } from "@openuidev/react-lang";
+
+import { library } from "./library";
+
+// One panel, scoped to one subagent. Memoized so the app shell's re-renders
+// never reach this Renderer; the panel's own tokens arrive through useMessages.
+const Panel = memo(function Panel({
+ stream,
+ snapshot,
+ isStreaming,
+ onAction,
+}: {
+ stream: ReturnType;
+ snapshot: SubagentDiscoverySnapshot;
+ isStreaming: boolean;
+ onAction: (event: ActionEvent) => void;
+}) {
+ const messages = useMessages(stream, snapshot);
+ // The program is the last AI message whose text starts with `root =`.
+ const program = programFromMessages(messages);
+
+ if (program === "") return ;
+
+ return (
+
+ );
+});
+
+export function Dashboard() {
+ const stream = useStream({
+ assistantId: "dashboard",
+ apiUrl: import.meta.env.VITE_LANGGRAPH_API_URL ?? "http://localhost:2024",
+ });
+
+ // Discover top-level panels from the stream; the layout adapts to whichever
+ // specialists the coordinator delegated.
+ const panels = [...stream.subagents.values()].filter(
+ (snapshot) => snapshot.parentId === null,
+ );
+
+ return (
+
+ {panels.map((snapshot) => (
+ {
+ // Handle continue_conversation and open_url actions.
+ }}
+ />
+ ))}
+
+ );
+}
+```
+
+Because the SDK keeps subagent token events out of the root store and each `Panel` is memoized on its snapshot identity, tokens from one panel never re-render another.
+
## Best practices
- **Generate the system prompt at module load:** not inside a React component; the prompt is several kilobytes and should be computed once
@@ -505,3 +688,5 @@ root = Stack([..., followUpCard])
- **Gate on complete statements:** avoid re-rendering the Renderer on every token; update only when a full statement (`name = ComponentCall(...)`) has arrived
- **Verify chart data before rendering:** chart components need their `Series` and label arrays defined before they're included in the stable snapshot
- **Keep camelCase variable names:** the openui-lang parser only accepts camelCase identifiers; reinforce this in the system prompt's `additionalRules`
+- **Delegate 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
+- **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