@assistant-ui/mcp-docs-server 0.1.29 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/code-examples/waterfall.md +15 -7
- package/.docs/organized/code-examples/with-a2a.md +8 -20
- package/.docs/organized/code-examples/with-ag-ui.md +9 -6
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +8 -8
- package/.docs/organized/code-examples/with-artifacts.md +10 -8
- package/.docs/organized/code-examples/with-assistant-transport.md +9 -10
- package/.docs/organized/code-examples/with-chain-of-thought.md +7 -7
- package/.docs/organized/code-examples/with-cloud-standalone.md +13 -10
- package/.docs/organized/code-examples/with-cloud.md +8 -9
- package/.docs/organized/code-examples/with-custom-thread-list.md +8 -8
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +15 -10
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +11 -11
- package/.docs/organized/code-examples/with-expo.md +20 -16
- package/.docs/organized/code-examples/with-external-store.md +7 -7
- package/.docs/organized/code-examples/with-ffmpeg.md +15 -10
- package/.docs/organized/code-examples/with-generative-ui.md +7 -7
- package/.docs/organized/code-examples/with-google-adk.md +6 -6
- package/.docs/organized/code-examples/with-heat-graph.md +5 -5
- package/.docs/organized/code-examples/with-interactables.md +8 -23
- package/.docs/organized/code-examples/with-langchain.md +437 -0
- package/.docs/organized/code-examples/with-langgraph.md +15 -15
- package/.docs/organized/code-examples/with-livekit.md +15 -10
- package/.docs/organized/code-examples/with-opencode.md +8 -10
- package/.docs/organized/code-examples/with-parent-id-grouping.md +8 -8
- package/.docs/organized/code-examples/with-react-hook-form.md +219 -147
- package/.docs/organized/code-examples/with-react-ink.md +2 -2
- package/.docs/organized/code-examples/with-react-router.md +10 -10
- package/.docs/organized/code-examples/with-store.md +8 -5
- package/.docs/organized/code-examples/with-tanstack.md +8 -8
- package/.docs/organized/code-examples/with-tap-runtime.md +9 -5
- package/.docs/raw/docs/(docs)/guides/mentions.mdx +248 -109
- package/.docs/raw/docs/(docs)/guides/slash-commands.mdx +112 -92
- package/.docs/raw/docs/(docs)/rtl.mdx +79 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +149 -40
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +2 -0
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +4 -0
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +1 -1
- package/.docs/raw/docs/primitives/composer.mdx +94 -62
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +57 -0
- package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +47 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +1 -1
- package/.docs/raw/docs/runtimes/langchain/comparison.mdx +60 -0
- package/.docs/raw/docs/runtimes/langchain/index.mdx +210 -0
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +155 -63
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +12 -4
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +199 -0
- package/.docs/raw/docs/ui/directive-text.mdx +113 -0
- package/.docs/raw/docs/ui/reasoning.mdx +13 -9
- package/dist/utils/logger.js +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/package.json +3 -3
- package/src/utils/logger.ts +1 -1
- package/.docs/raw/docs/ui/mention.mdx +0 -168
|
@@ -1447,7 +1447,7 @@ The main interface for connecting your state to assistant-ui.
|
|
|
1447
1447
|
name: "isRunning",
|
|
1448
1448
|
type: "boolean",
|
|
1449
1449
|
description:
|
|
1450
|
-
"Whether the assistant is currently generating a response. When true, shows optimistic assistant message",
|
|
1450
|
+
"Whether the assistant is currently generating a response. When true, shows an optimistic assistant message and flows directly to `thread.isRunning`, so the thread stays in a running state even after the last assistant message has completed (e.g. while suggestions or metadata chunks are still arriving). When omitted, `thread.isRunning` falls back to the last-message-status heuristic.",
|
|
1451
1451
|
default: "false",
|
|
1452
1452
|
},
|
|
1453
1453
|
{
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Comparison with `react-langgraph`
|
|
3
|
+
description: How `@assistant-ui/react-langchain` differs from `@assistant-ui/react-langgraph`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Both packages connect assistant-ui to LangGraph backends. They are **independent adapters for different upstream libraries** — one is not a successor to the other.
|
|
7
|
+
|
|
8
|
+
| Aspect | `@assistant-ui/react-langgraph` | `@assistant-ui/react-langchain` |
|
|
9
|
+
| ------------------------------ | ------------------------------------------------------------ | ----------------------------------------------------- |
|
|
10
|
+
| Wraps | `@langchain/langgraph-sdk` (raw SDK) | `@langchain/react` (`useStream` hook) |
|
|
11
|
+
| Age | Sept 2024 onward | April 2026 onward |
|
|
12
|
+
| Version | `0.13.x` | `0.0.x` |
|
|
13
|
+
| Lines of source | ~7,500 | ~600 |
|
|
14
|
+
| Built on | `useExternalStoreRuntime` | `useExternalStoreRuntime` |
|
|
15
|
+
| `create-assistant-ui` template | `-t langgraph` ships this package | No template yet |
|
|
16
|
+
|
|
17
|
+
## Feature coverage
|
|
18
|
+
|
|
19
|
+
| Feature | `react-langgraph` | `react-langchain` |
|
|
20
|
+
| --------------------------------------- | -------------------------------- | ----------------------------------- |
|
|
21
|
+
| Stream messages | ✅ `useLangGraphRuntime` | ✅ `useStreamRuntime` |
|
|
22
|
+
| Interrupt state | ✅ `useLangGraphInterruptState` | ✅ `useLangChainInterruptState` |
|
|
23
|
+
| Send raw state update / resume command | ✅ `useLangGraphSendCommand` | ✅ `useLangChainSubmit` |
|
|
24
|
+
| Read arbitrary custom state key | ❌ | ✅ `useLangChainState<T>(key)` |
|
|
25
|
+
| Per-message metadata (`messages-tuple`) | ✅ `useLangGraphMessageMetadata` | ❌ not exposed |
|
|
26
|
+
| Generative UI messages (LangSmith) | ✅ `useLangGraphUIMessages` | ❌ not exposed |
|
|
27
|
+
| Subgraph / namespaced stream events | ✅ via `eventHandlers` | ❌ not exposed |
|
|
28
|
+
| End-to-end cancellation primitive | ✅ `unstable_createLangGraphStream` | ❌ not exposed |
|
|
29
|
+
| Message accumulator utility | ✅ `LangGraphMessageAccumulator` | ❌ not exposed |
|
|
30
|
+
| Cloud thread persistence | ✅ `cloud` option | ✅ `cloud` option |
|
|
31
|
+
|
|
32
|
+
`react-langchain` is the newer, thinner wrapper — it delegates to the upstream `useStream` hook rather than re-implementing the stream plumbing. That is why its footprint is smaller and its surface area is narrower today. Features that exist in `react-langgraph` but not `react-langchain` are absent because they have not yet been ported, not because they are deprecated.
|
|
33
|
+
|
|
34
|
+
## Choosing between them
|
|
35
|
+
|
|
36
|
+
Use `@assistant-ui/react-langgraph` when:
|
|
37
|
+
|
|
38
|
+
- You are scaffolding via `npx create-assistant-ui -t langgraph`.
|
|
39
|
+
- You want the broader feature set today (subgraph events, UI messages, message metadata, cancellation).
|
|
40
|
+
- You prefer integrating with `@langchain/langgraph-sdk` directly.
|
|
41
|
+
|
|
42
|
+
Use `@assistant-ui/react-langchain` when:
|
|
43
|
+
|
|
44
|
+
- Your app already depends on `@langchain/react` and uses `useStream` elsewhere.
|
|
45
|
+
- You want to read custom state keys (`todos`, `files`, plans, ...) with `useLangChainState<T>(key)` without reconstructing them from tool-call streams.
|
|
46
|
+
- You prefer a thin wrapper that stays pinned to upstream behavior.
|
|
47
|
+
|
|
48
|
+
## Hook name mapping
|
|
49
|
+
|
|
50
|
+
If you are moving code between the two adapters, most hooks have a counterpart — but note the feature gaps above.
|
|
51
|
+
|
|
52
|
+
| `react-langgraph` | `react-langchain` | Notes |
|
|
53
|
+
| ---------------------------------- | ----------------------------------- | ----------------------------------------------------------- |
|
|
54
|
+
| `useLangGraphRuntime` | `useStreamRuntime` | Options extend upstream `UseStreamOptions`; no `stream` / `create` / `load` to write. |
|
|
55
|
+
| `useLangGraphInterruptState` | `useLangChainInterruptState` | Same return shape: `{ value?: unknown } \| undefined`. |
|
|
56
|
+
| `useLangGraphSendCommand` | `useLangChainSubmit` | `submit(values, { command })` replaces the dedicated hook. |
|
|
57
|
+
| `useLangGraphSend` | _(use `runtime.thread.append`)_ | No direct equivalent; send turns through the runtime. |
|
|
58
|
+
| `useLangGraphMessageMetadata` | _(not available)_ | Open an issue if you rely on this. |
|
|
59
|
+
| `useLangGraphUIMessages` | _(not available)_ | Open an issue if you rely on this. |
|
|
60
|
+
| _(none)_ | `useLangChainState<T>(key)` | New — reads any custom state key reactively. |
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
description: Adapter for LangChain's `useStream` hook, exposed as an assistant-ui runtime.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`@assistant-ui/react-langchain` wraps [`useStream`](https://docs.langchain.com/oss/javascript/langgraph-sdk/react-stream) from `@langchain/react` and exposes it as an assistant-ui runtime. Use this package if you are already integrating your app with `@langchain/react` and want assistant-ui on top of the upstream hook.
|
|
7
|
+
|
|
8
|
+
<Callout type="info">
|
|
9
|
+
assistant-ui ships two adapters for LangGraph backends:
|
|
10
|
+
- **[`@assistant-ui/react-langgraph`](/docs/runtimes/langgraph)** integrates with `@langchain/langgraph-sdk` directly and exposes features like subgraph events, UI messages, message metadata, and end-to-end cancellation.
|
|
11
|
+
- **`@assistant-ui/react-langchain`** (this page) wraps `@langchain/react`'s `useStream`. It is lighter-weight and stays aligned with upstream, but currently does not expose every `react-langgraph` feature.
|
|
12
|
+
|
|
13
|
+
See [the comparison doc](/docs/runtimes/langchain/comparison) for a feature gap table.
|
|
14
|
+
</Callout>
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
You need a LangGraph Cloud API server. You can start a server locally via [LangGraph Studio](https://github.com/langchain-ai/langgraph-studio) or use [LangSmith](https://www.langchain.com/langsmith) for a hosted version.
|
|
19
|
+
|
|
20
|
+
The state of the graph you are using must have a `messages` key with a list of LangChain-alike messages (or pass a custom `messagesKey`).
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
<Steps>
|
|
25
|
+
<Step>
|
|
26
|
+
|
|
27
|
+
### Install dependencies
|
|
28
|
+
|
|
29
|
+
<InstallCommand npm={["@assistant-ui/react", "@assistant-ui/react-langchain", "@langchain/react", "@langchain/langgraph-sdk"]} />
|
|
30
|
+
|
|
31
|
+
</Step>
|
|
32
|
+
<Step>
|
|
33
|
+
|
|
34
|
+
### Define a `MyAssistant` component
|
|
35
|
+
|
|
36
|
+
```tsx title="@/components/MyAssistant.tsx"
|
|
37
|
+
"use client";
|
|
38
|
+
|
|
39
|
+
import { Thread } from "@/components/assistant-ui/thread";
|
|
40
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
41
|
+
import { useStreamRuntime } from "@assistant-ui/react-langchain";
|
|
42
|
+
|
|
43
|
+
export function MyAssistant() {
|
|
44
|
+
const runtime = useStreamRuntime({
|
|
45
|
+
assistantId: process.env["NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID"]!,
|
|
46
|
+
apiUrl: process.env["NEXT_PUBLIC_LANGGRAPH_API_URL"],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
51
|
+
<Thread />
|
|
52
|
+
</AssistantRuntimeProvider>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
</Step>
|
|
58
|
+
<Step>
|
|
59
|
+
|
|
60
|
+
### Use the `MyAssistant` component
|
|
61
|
+
|
|
62
|
+
```tsx title="@/app/page.tsx"
|
|
63
|
+
import { MyAssistant } from "@/components/MyAssistant";
|
|
64
|
+
|
|
65
|
+
export default function Home() {
|
|
66
|
+
return (
|
|
67
|
+
<main className="h-dvh">
|
|
68
|
+
<MyAssistant />
|
|
69
|
+
</main>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
</Step>
|
|
75
|
+
<Step>
|
|
76
|
+
|
|
77
|
+
### Set environment variables
|
|
78
|
+
|
|
79
|
+
Create a `.env.local` file in your project with the following variables:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
NEXT_PUBLIC_LANGGRAPH_API_URL=http://localhost:2024
|
|
83
|
+
NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID=your_graph_id
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
</Step>
|
|
87
|
+
<Step>
|
|
88
|
+
|
|
89
|
+
### Set up UI components
|
|
90
|
+
|
|
91
|
+
Follow the [UI Components](/docs/ui/thread) guide to set up the UI components.
|
|
92
|
+
|
|
93
|
+
</Step>
|
|
94
|
+
</Steps>
|
|
95
|
+
|
|
96
|
+
## `useStreamRuntime` options
|
|
97
|
+
|
|
98
|
+
`useStreamRuntime` accepts every option [`useStream`](https://docs.langchain.com/oss/javascript/langgraph-sdk/react-stream) from `@langchain/react` does, plus three assistant-ui-specific fields:
|
|
99
|
+
|
|
100
|
+
| Option | Type | Description |
|
|
101
|
+
| ------------- | ---------------------------------------------- | ------------------------------------------------------------------------ |
|
|
102
|
+
| `cloud` | `AssistantCloud` | Optional — persists threads via assistant-cloud. |
|
|
103
|
+
| `adapters` | `{ attachments?, speech?, feedback? }` | Optional — attachment, speech, and feedback adapters. |
|
|
104
|
+
| `messagesKey` | `string` | The state key that holds messages. Defaults to `"messages"`. |
|
|
105
|
+
|
|
106
|
+
## Reading custom state keys
|
|
107
|
+
|
|
108
|
+
LangGraph agents often expose structured state beyond messages (plans, todos, scratch files, generative-UI artifacts). Read them directly with `useLangChainState`. It mirrors `useStream().values[key]` upstream and updates when the stream emits new state.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { useLangChainState } from "@assistant-ui/react-langchain";
|
|
112
|
+
|
|
113
|
+
type Todo = { id: string; title: string; done: boolean };
|
|
114
|
+
|
|
115
|
+
function TodoList() {
|
|
116
|
+
const todos = useLangChainState<Todo[]>("todos", []);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<ul>
|
|
120
|
+
{todos.map((t) => (
|
|
121
|
+
<li key={t.id}>
|
|
122
|
+
{t.done ? "✓" : "○"} {t.title}
|
|
123
|
+
</li>
|
|
124
|
+
))}
|
|
125
|
+
</ul>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Signatures:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
useLangChainState<T>(key: string): T | undefined;
|
|
134
|
+
useLangChainState<T>(key: string, defaultValue: T): T;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This hook is especially useful with the [`deepagents`](https://docs.langchain.com/oss/python/deepagents) middleware, whose `write_todos` step updates `state.todos` alongside the tool-call stream. Reading the state key directly avoids reconstructing the list from partial tool-call args.
|
|
138
|
+
|
|
139
|
+
<Callout type="info">
|
|
140
|
+
Added in v0.0.2 — see issue [#3862](https://github.com/assistant-ui/assistant-ui/issues/3862) for motivation.
|
|
141
|
+
</Callout>
|
|
142
|
+
|
|
143
|
+
## Interrupts
|
|
144
|
+
|
|
145
|
+
LangGraph interrupts pause the graph and wait for client input. `useLangChainInterruptState` exposes the current interrupt; `useLangChainSubmit` resumes the graph with a raw state update.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import {
|
|
149
|
+
useLangChainInterruptState,
|
|
150
|
+
useLangChainSubmit,
|
|
151
|
+
} from "@assistant-ui/react-langchain";
|
|
152
|
+
import { Command } from "@langchain/langgraph-sdk";
|
|
153
|
+
|
|
154
|
+
function InterruptPrompt() {
|
|
155
|
+
const interrupt = useLangChainInterruptState();
|
|
156
|
+
const submit = useLangChainSubmit();
|
|
157
|
+
|
|
158
|
+
if (!interrupt) return null;
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<pre>{JSON.stringify(interrupt.value, null, 2)}</pre>
|
|
163
|
+
<button
|
|
164
|
+
onClick={() =>
|
|
165
|
+
submit(null, { command: new Command({ resume: "approved" }) })
|
|
166
|
+
}
|
|
167
|
+
>
|
|
168
|
+
Approve
|
|
169
|
+
</button>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Message conversion
|
|
176
|
+
|
|
177
|
+
`convertLangChainBaseMessage` transforms a LangChain `BaseMessage` into an assistant-ui message. Use it when building a custom `ExternalStoreAdapter` that needs to consume LangChain messages outside of `useStreamRuntime`.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { convertLangChainBaseMessage } from "@assistant-ui/react-langchain";
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Cloud persistence
|
|
184
|
+
|
|
185
|
+
Pass an `AssistantCloud` instance to persist threads across sessions. The runtime automatically wires thread list management and resumes state from the cloud.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { AssistantCloud } from "assistant-cloud";
|
|
189
|
+
import { useStreamRuntime } from "@assistant-ui/react-langchain";
|
|
190
|
+
|
|
191
|
+
const cloud = new AssistantCloud({ baseUrl: "/api/cloud" });
|
|
192
|
+
|
|
193
|
+
const runtime = useStreamRuntime({
|
|
194
|
+
cloud,
|
|
195
|
+
assistantId: "agent",
|
|
196
|
+
apiUrl: "http://localhost:2024",
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Custom `messagesKey`
|
|
201
|
+
|
|
202
|
+
If your graph stores messages under a non-default key, pass `messagesKey` so the runtime submits tool results and human turns to the correct state slot:
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
const runtime = useStreamRuntime({
|
|
206
|
+
assistantId: "agent",
|
|
207
|
+
apiUrl: "http://localhost:2024",
|
|
208
|
+
messagesKey: "chat_messages",
|
|
209
|
+
});
|
|
210
|
+
```
|
|
@@ -3,6 +3,10 @@ title: Getting Started
|
|
|
3
3
|
description: Connect to LangGraph Cloud API for agent workflows with streaming.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
<Callout type="info">
|
|
7
|
+
If you are already using `@langchain/react`'s `useStream` hook, the alternative [`@assistant-ui/react-langchain`](/docs/runtimes/langchain) adapter may fit better. `@assistant-ui/react-langgraph` (this page) integrates with `@langchain/langgraph-sdk` directly and has the broader feature set — subgraph events, UI messages, message metadata, end-to-end cancellation. See the [comparison](/docs/runtimes/langchain/comparison).
|
|
8
|
+
</Callout>
|
|
9
|
+
|
|
6
10
|
## Requirements
|
|
7
11
|
|
|
8
12
|
You need a LangGraph Cloud API server. You can start a server locally via [LangGraph Studio](https://github.com/langchain-ai/langgraph-studio) or use [LangSmith](https://www.langchain.com/langsmith) for a hosted version.
|
|
@@ -60,6 +64,8 @@ NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID=your_graph_id
|
|
|
60
64
|
```tsx twoslash title="@/app/api/[...path]/route.ts"
|
|
61
65
|
import { NextRequest, NextResponse } from "next/server";
|
|
62
66
|
|
|
67
|
+
export const runtime = "edge";
|
|
68
|
+
|
|
63
69
|
function getCorsHeaders() {
|
|
64
70
|
return {
|
|
65
71
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -84,6 +90,7 @@ async function handleRequest(req: NextRequest, method: string) {
|
|
|
84
90
|
headers: {
|
|
85
91
|
"x-api-key": process.env["LANGCHAIN_API_KEY"] || "",
|
|
86
92
|
},
|
|
93
|
+
signal: req.signal,
|
|
87
94
|
};
|
|
88
95
|
|
|
89
96
|
if (["POST", "PUT", "PATCH"].includes(method)) {
|
|
@@ -142,48 +149,15 @@ export const OPTIONS = () =>
|
|
|
142
149
|
// @filename: /lib/chatApi.ts
|
|
143
150
|
|
|
144
151
|
// ---cut---
|
|
145
|
-
import { Client
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
export const createThread = async () => {
|
|
156
|
-
const client = createClient();
|
|
157
|
-
return client.threads.create();
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
export const getThreadState = async (
|
|
161
|
-
threadId: string,
|
|
162
|
-
): Promise<ThreadState<{ messages: LangChainMessage[] }>> => {
|
|
163
|
-
const client = createClient();
|
|
164
|
-
return client.threads.getState(threadId);
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
export const sendMessage = async (params: {
|
|
168
|
-
threadId: string;
|
|
169
|
-
messages?: LangChainMessage[];
|
|
170
|
-
command?: LangGraphCommand;
|
|
171
|
-
}) => {
|
|
172
|
-
const client = createClient();
|
|
173
|
-
return client.runs.stream(
|
|
174
|
-
params.threadId,
|
|
175
|
-
process.env["NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID"]!,
|
|
176
|
-
{
|
|
177
|
-
input: params.messages?.length
|
|
178
|
-
? { messages: params.messages }
|
|
179
|
-
: null,
|
|
180
|
-
command: params.command,
|
|
181
|
-
// Include "custom" if you use LangSmith Generative UI
|
|
182
|
-
// (`push_ui_message` / `typedUi().push()`). See the Generative UI
|
|
183
|
-
// section below for details.
|
|
184
|
-
streamMode: ["messages", "updates", "custom"],
|
|
185
|
-
},
|
|
186
|
-
);
|
|
152
|
+
import { Client } from "@langchain/langgraph-sdk";
|
|
153
|
+
|
|
154
|
+
export const createClient = () => {
|
|
155
|
+
const apiUrl =
|
|
156
|
+
process.env["NEXT_PUBLIC_LANGGRAPH_API_URL"] ||
|
|
157
|
+
(typeof window !== "undefined"
|
|
158
|
+
? new URL("/api", window.location.href).href
|
|
159
|
+
: "/api");
|
|
160
|
+
return new Client({ apiUrl });
|
|
187
161
|
};
|
|
188
162
|
```
|
|
189
163
|
|
|
@@ -199,32 +173,41 @@ export const sendMessage = async (params: {
|
|
|
199
173
|
// ---cut---
|
|
200
174
|
"use client";
|
|
201
175
|
|
|
176
|
+
import { useMemo } from "react";
|
|
202
177
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
203
178
|
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
204
|
-
import {
|
|
179
|
+
import {
|
|
180
|
+
unstable_createLangGraphStream,
|
|
181
|
+
useLangGraphRuntime,
|
|
182
|
+
type LangChainMessage,
|
|
183
|
+
} from "@assistant-ui/react-langgraph";
|
|
205
184
|
|
|
206
|
-
import {
|
|
185
|
+
import { createClient } from "@/lib/chatApi";
|
|
207
186
|
|
|
208
|
-
|
|
209
|
-
const runtime = useLangGraphRuntime({
|
|
210
|
-
stream: async function* (messages, { initialize, command }) {
|
|
211
|
-
const { externalId } = await initialize();
|
|
212
|
-
if (!externalId) throw new Error("Thread not found");
|
|
187
|
+
const ASSISTANT_ID = process.env["NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID"]!;
|
|
213
188
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
189
|
+
export function MyAssistant() {
|
|
190
|
+
const client = useMemo(() => createClient(), []);
|
|
191
|
+
const stream = useMemo(
|
|
192
|
+
() =>
|
|
193
|
+
unstable_createLangGraphStream({
|
|
194
|
+
client,
|
|
195
|
+
assistantId: ASSISTANT_ID,
|
|
196
|
+
}),
|
|
197
|
+
[client],
|
|
198
|
+
);
|
|
219
199
|
|
|
220
|
-
|
|
221
|
-
|
|
200
|
+
const runtime = useLangGraphRuntime({
|
|
201
|
+
unstable_allowCancellation: true,
|
|
202
|
+
stream,
|
|
222
203
|
create: async () => {
|
|
223
|
-
const { thread_id } = await
|
|
204
|
+
const { thread_id } = await client.threads.create();
|
|
224
205
|
return { externalId: thread_id };
|
|
225
206
|
},
|
|
226
207
|
load: async (externalId) => {
|
|
227
|
-
const state = await
|
|
208
|
+
const state = await client.threads.getState<{
|
|
209
|
+
messages: LangChainMessage[];
|
|
210
|
+
}>(externalId);
|
|
228
211
|
return {
|
|
229
212
|
messages: state.values.messages,
|
|
230
213
|
interrupts: state.tasks[0]?.interrupts,
|
|
@@ -323,18 +306,38 @@ const runtime = useLangGraphRuntime({
|
|
|
323
306
|
stream: async (messages, { initialize, ...config }) => { /* ... */ },
|
|
324
307
|
eventHandlers: {
|
|
325
308
|
onMessageChunk: (chunk, metadata) => {
|
|
326
|
-
// Fired for each chunk in messages-tuple mode
|
|
327
|
-
// metadata contains langgraph_step, langgraph_node, ls_model_name, etc.
|
|
309
|
+
// Fired for each chunk in messages-tuple mode.
|
|
310
|
+
// `metadata` contains langgraph_step, langgraph_node, ls_model_name, etc.
|
|
311
|
+
// For pipe-namespaced events emitted by subgraphs (e.g. `messages|tools:call_abc`),
|
|
312
|
+
// `metadata.namespace` holds the suffix ("tools:call_abc"). Use it to attribute
|
|
313
|
+
// a chunk to a specific subgraph.
|
|
328
314
|
},
|
|
329
315
|
onValues: (values) => {
|
|
330
|
-
// Fired when a
|
|
316
|
+
// Fired when a top-level `values` event is received.
|
|
317
|
+
// Subgraph `values` events are routed to `onSubgraphValues` instead.
|
|
331
318
|
},
|
|
332
319
|
onUpdates: (updates) => {
|
|
333
|
-
// Fired when
|
|
320
|
+
// Fired when a top-level `updates` event is received.
|
|
321
|
+
// Subgraph `updates` events are routed to `onSubgraphUpdates` instead.
|
|
322
|
+
},
|
|
323
|
+
onSubgraphValues: (namespace, values) => {
|
|
324
|
+
// Fired when a subgraph `values|<namespace>` event is received
|
|
325
|
+
// (e.g. `namespace === "tools:call_abc"`). Use this to observe
|
|
326
|
+
// subgraph-internal state without mixing it into `onValues`.
|
|
327
|
+
},
|
|
328
|
+
onSubgraphUpdates: (namespace, updates) => {
|
|
329
|
+
// Fired when a subgraph `updates|<namespace>` event is received.
|
|
334
330
|
},
|
|
335
331
|
onMetadata: (metadata) => { /* thread metadata */ },
|
|
336
332
|
onInfo: (info) => { /* informational messages */ },
|
|
337
|
-
onError: (error) => {
|
|
333
|
+
onError: (error) => {
|
|
334
|
+
// Fired for both top-level and subgraph errors.
|
|
335
|
+
},
|
|
336
|
+
onSubgraphError: (namespace, error) => {
|
|
337
|
+
// Additionally fired for subgraph errors with the namespace.
|
|
338
|
+
// Use to attribute a subgraph failure to its source without marking
|
|
339
|
+
// the parent message as incomplete (that only happens for top-level errors).
|
|
340
|
+
},
|
|
338
341
|
onCustomEvent: (type, data) => { /* custom events */ },
|
|
339
342
|
},
|
|
340
343
|
});
|
|
@@ -399,6 +402,51 @@ const runtime = useLangGraphRuntime({
|
|
|
399
402
|
|
|
400
403
|
See the [Cloud Persistence guide](/docs/cloud/langgraph) for detailed setup instructions.
|
|
401
404
|
|
|
405
|
+
### Custom Thread List
|
|
406
|
+
|
|
407
|
+
To surface pre-existing LangGraph `thread_id`s in the thread picker without running assistant-cloud, pass a `RemoteThreadListAdapter` via `unstable_threadListAdapter`. A common implementation backs `list()` with `client.threads.search()` and `initialize()` with `client.threads.create()`.
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
import type { RemoteThreadListAdapter } from "@assistant-ui/react";
|
|
411
|
+
import { Client } from "@langchain/langgraph-sdk";
|
|
412
|
+
|
|
413
|
+
const client = new Client({ apiUrl: process.env.NEXT_PUBLIC_LANGGRAPH_API_URL });
|
|
414
|
+
|
|
415
|
+
const threadListAdapter: RemoteThreadListAdapter = {
|
|
416
|
+
async list() {
|
|
417
|
+
const threads = await client.threads.search({ limit: 50 });
|
|
418
|
+
return {
|
|
419
|
+
threads: threads.map((t) => ({
|
|
420
|
+
status: "regular",
|
|
421
|
+
remoteId: t.thread_id,
|
|
422
|
+
externalId: t.thread_id,
|
|
423
|
+
title: (t.metadata as { title?: string } | undefined)?.title,
|
|
424
|
+
})),
|
|
425
|
+
};
|
|
426
|
+
},
|
|
427
|
+
async initialize() {
|
|
428
|
+
const t = await client.threads.create();
|
|
429
|
+
return { remoteId: t.thread_id, externalId: t.thread_id };
|
|
430
|
+
},
|
|
431
|
+
async delete(remoteId) {
|
|
432
|
+
await client.threads.delete(remoteId);
|
|
433
|
+
},
|
|
434
|
+
// rename, archive, unarchive, fetch, generateTitle — see link below
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const runtime = useLangGraphRuntime({
|
|
438
|
+
stream: async function* (messages, { initialize }) { /* ... */ },
|
|
439
|
+
load: async (externalId) => { /* ... */ },
|
|
440
|
+
unstable_threadListAdapter: threadListAdapter,
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Setting `remoteId === externalId` keeps the ids assistant-ui stores aligned with the LangGraph thread ids your `load` and `stream` callbacks receive. See the [Custom Thread List guide](/docs/runtimes/custom/custom-thread-list) for the full adapter contract.
|
|
445
|
+
|
|
446
|
+
<Callout type="info">
|
|
447
|
+
When `unstable_threadListAdapter` is provided, the `cloud`, `create`, and `delete` options are ignored — the adapter owns the full thread-list lifecycle.
|
|
448
|
+
</Callout>
|
|
449
|
+
|
|
402
450
|
## Message Editing & Regeneration
|
|
403
451
|
|
|
404
452
|
LangGraph uses server-side checkpoints for state management. To support message editing (branching) and regeneration, you need to provide a `getCheckpointId` callback that resolves the appropriate checkpoint for server-side forking.
|
|
@@ -565,6 +613,50 @@ Mount the component once somewhere inside the `AssistantRuntimeProvider` tree. I
|
|
|
565
613
|
|
|
566
614
|
When a matching UI message arrives, the adapter appends a `{ type: "data", name: "chart", data: { series, title } }` part to the parent assistant message and the registered component renders inline.
|
|
567
615
|
|
|
616
|
+
### Register renderers via `uiComponents`
|
|
617
|
+
|
|
618
|
+
Instead of mounting separate `makeAssistantDataUI` components, you can register renderers directly on the runtime hook via the `uiComponents` option:
|
|
619
|
+
|
|
620
|
+
```tsx title="@/components/MyAssistant.tsx"
|
|
621
|
+
const runtime = useLangGraphRuntime({
|
|
622
|
+
stream: async function* (messages, { initialize }) { /* ... */ },
|
|
623
|
+
uiComponents: {
|
|
624
|
+
renderers: {
|
|
625
|
+
chart: ({ data }) => <Chart series={data.series} title={data.title} />,
|
|
626
|
+
table: ({ data }) => <DataTable rows={data.rows} />,
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Static `renderers` are matched by `ui_message` name. If no match is found, the part renders nothing unless a `fallback` is provided.
|
|
633
|
+
|
|
634
|
+
### Dynamic loading with `fallback`
|
|
635
|
+
|
|
636
|
+
LangSmith's [Generative UI](https://docs.langchain.com/langsmith/generative-ui-react) supports colocating UI code with your graph and loading it at runtime via `LoadExternalComponent`. The `fallback` option handles any `ui_message` name that has no static renderer:
|
|
637
|
+
|
|
638
|
+
```tsx title="@/components/MyAssistant.tsx"
|
|
639
|
+
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui";
|
|
640
|
+
|
|
641
|
+
const runtime = useLangGraphRuntime({
|
|
642
|
+
stream: async function* (messages, { initialize }) { /* ... */ },
|
|
643
|
+
uiComponents: {
|
|
644
|
+
fallback: ({ name, data }) => (
|
|
645
|
+
<LoadExternalComponent name={name} props={data} />
|
|
646
|
+
),
|
|
647
|
+
renderers: {
|
|
648
|
+
chart: ({ data }) => <Chart {...data} />,
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
});
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
With this setup:
|
|
655
|
+
- A `ui_message` with `name: "chart"` renders the static `Chart` component
|
|
656
|
+
- Any other name (e.g. `"dashboard"`, `"form"`) is handled by `fallback`, which fetches the component from LangSmith at runtime
|
|
657
|
+
|
|
658
|
+
The `fallback` component receives the same props as any data renderer: `name`, `data`, and part state metadata. This lets you pass the component name and props straight through to `LoadExternalComponent`.
|
|
659
|
+
|
|
568
660
|
### Semantics
|
|
569
661
|
|
|
570
662
|
The adapter mirrors the reducer in `@langchain/langgraph-sdk/react-ui` exactly:
|
|
@@ -11,7 +11,8 @@ Choosing the right runtime is crucial for your assistant-ui implementation. This
|
|
|
11
11
|
graph TD
|
|
12
12
|
A[What's your starting point?] --> B{Existing Framework?}
|
|
13
13
|
B -->|Vercel AI SDK| C[Use AI SDK Integration]
|
|
14
|
-
B -->|LangGraph|
|
|
14
|
+
B -->|LangGraph via langgraph-sdk| D1[Use react-langgraph]
|
|
15
|
+
B -->|LangChain via @langchain/react useStream| D2[Use react-langchain]
|
|
15
16
|
B -->|LangServe| E[Use LangServe Runtime]
|
|
16
17
|
B -->|Mastra| F[Use Mastra Runtime]
|
|
17
18
|
B -->|AG-UI Protocol| J[Use AG-UI Runtime]
|
|
@@ -55,9 +56,14 @@ For popular frameworks, we provide ready-to-use integrations built on top of our
|
|
|
55
56
|
/>
|
|
56
57
|
<Card
|
|
57
58
|
title="LangGraph"
|
|
58
|
-
description="
|
|
59
|
+
description="Integrates with `@langchain/langgraph-sdk` directly. Broader feature set: subgraph events, UI messages, message metadata, cancellation."
|
|
59
60
|
href="/docs/runtimes/langgraph"
|
|
60
61
|
/>
|
|
62
|
+
<Card
|
|
63
|
+
title="LangChain useStream"
|
|
64
|
+
description="Wraps `useStream` from `@langchain/react`. Lighter-weight, stays aligned with upstream. Fewer features today."
|
|
65
|
+
href="/docs/runtimes/langchain"
|
|
66
|
+
/>
|
|
61
67
|
<Card
|
|
62
68
|
title="LangServe"
|
|
63
69
|
description="For LangChain applications deployed with LangServe"
|
|
@@ -87,13 +93,14 @@ For popular frameworks, we provide ready-to-use integrations built on top of our
|
|
|
87
93
|
The pre-built integrations (AI SDK, LangGraph, etc.) are **not separate runtime types**. They're convenient wrappers built on top of our core runtimes:
|
|
88
94
|
|
|
89
95
|
- **AI SDK Integration** → Built on `LocalRuntime` with streaming adapter
|
|
90
|
-
- **LangGraph Runtime** → Built on `
|
|
96
|
+
- **LangGraph Runtime** → Built on `ExternalStoreRuntime`, integrates with `@langchain/langgraph-sdk`
|
|
97
|
+
- **LangChain useStream Runtime** → Built on `ExternalStoreRuntime`, wraps `useStream` from `@langchain/react`
|
|
91
98
|
- **LangServe Runtime** → Built on `LocalRuntime` with LangServe client adapter
|
|
92
99
|
- **Mastra Runtime** → Built on `LocalRuntime` with workflow adapter
|
|
93
100
|
- **AG-UI Runtime** → Built on `LocalRuntime` with AG-UI protocol adapter
|
|
94
101
|
- **A2A Runtime** → Built on `LocalRuntime` with Agent-to-Agent protocol adapter
|
|
95
102
|
|
|
96
|
-
This means
|
|
103
|
+
This means pre-built integrations give you assistant-ui's features — state management, streaming, UI primitives — with zero configuration for your specific framework, regardless of whether the adapter happens to build on `LocalRuntime` or `ExternalStoreRuntime` internally. The list above tells you which core runtime each adapter uses.
|
|
97
104
|
|
|
98
105
|
### When to Use Pre-Built vs Core Runtimes
|
|
99
106
|
|
|
@@ -228,6 +235,7 @@ Explore our implementation examples:
|
|
|
228
235
|
- [`LocalRuntime` Guide](/docs/runtimes/custom/local)
|
|
229
236
|
- [`ExternalStoreRuntime` Guide](/docs/runtimes/custom/external-store)
|
|
230
237
|
- [LangGraph Integration](/docs/runtimes/langgraph)
|
|
238
|
+
- [LangChain useStream Integration](/docs/runtimes/langchain)
|
|
231
239
|
3. **Start with an example** from our [examples repository](https://github.com/assistant-ui/assistant-ui/tree/main/examples)
|
|
232
240
|
4. **Add features progressively** using adapters
|
|
233
241
|
5. **Consider Assistant Cloud** for production persistence
|