@assistant-ui/mcp-docs-server 0.1.28 → 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 +18 -10
- package/.docs/organized/code-examples/with-a2a.md +12 -24
- package/.docs/organized/code-examples/with-ag-ui.md +14 -11
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +12 -12
- package/.docs/organized/code-examples/with-artifacts.md +14 -12
- package/.docs/organized/code-examples/with-assistant-transport.md +13 -14
- package/.docs/organized/code-examples/with-chain-of-thought.md +11 -11
- package/.docs/organized/code-examples/with-cloud-standalone.md +17 -14
- package/.docs/organized/code-examples/with-cloud.md +12 -13
- package/.docs/organized/code-examples/with-custom-thread-list.md +12 -12
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +19 -14
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +15 -15
- package/.docs/organized/code-examples/with-expo.md +27 -23
- package/.docs/organized/code-examples/with-external-store.md +11 -11
- package/.docs/organized/code-examples/with-ffmpeg.md +19 -14
- package/.docs/organized/code-examples/with-generative-ui.md +11 -11
- package/.docs/organized/code-examples/with-google-adk.md +10 -10
- package/.docs/organized/code-examples/with-heat-graph.md +8 -8
- package/.docs/organized/code-examples/with-interactables.md +12 -27
- package/.docs/organized/code-examples/with-langchain.md +437 -0
- package/.docs/organized/code-examples/with-langgraph.md +20 -20
- package/.docs/organized/code-examples/with-livekit.md +59 -18
- package/.docs/organized/code-examples/with-opencode.md +2392 -0
- package/.docs/organized/code-examples/with-parent-id-grouping.md +12 -12
- package/.docs/organized/code-examples/with-react-hook-form.md +223 -151
- package/.docs/organized/code-examples/with-react-ink.md +3 -3
- package/.docs/organized/code-examples/with-react-router.md +15 -15
- package/.docs/organized/code-examples/with-store.md +11 -8
- package/.docs/organized/code-examples/with-tanstack.md +14 -14
- package/.docs/organized/code-examples/with-tap-runtime.md +13 -9
- 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)/guides/voice.mdx +10 -3
- 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 +49 -3
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +39 -1
- package/.docs/raw/docs/runtimes/custom/local.mdx +65 -18
- package/.docs/raw/docs/runtimes/google-adk/index.mdx +62 -0
- 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 +288 -60
- 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 +4 -4
- package/src/utils/logger.ts +1 -1
- package/.docs/raw/docs/ui/mention.mdx +0 -168
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# Example: with-langchain
|
|
2
|
+
|
|
3
|
+
## app/globals.css
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
@import "tailwindcss";
|
|
7
|
+
@import "tw-animate-css";
|
|
8
|
+
|
|
9
|
+
@source "../../../packages/ui/src";
|
|
10
|
+
|
|
11
|
+
@custom-variant dark (&:is(.dark *));
|
|
12
|
+
|
|
13
|
+
@theme inline {
|
|
14
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
15
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
16
|
+
--radius-lg: var(--radius);
|
|
17
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
18
|
+
--color-background: var(--background);
|
|
19
|
+
--color-foreground: var(--foreground);
|
|
20
|
+
--color-card: var(--card);
|
|
21
|
+
--color-card-foreground: var(--card-foreground);
|
|
22
|
+
--color-popover: var(--popover);
|
|
23
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
24
|
+
--color-primary: var(--primary);
|
|
25
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
26
|
+
--color-secondary: var(--secondary);
|
|
27
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
28
|
+
--color-muted: var(--muted);
|
|
29
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
30
|
+
--color-accent: var(--accent);
|
|
31
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
32
|
+
--color-destructive: var(--destructive);
|
|
33
|
+
--color-border: var(--border);
|
|
34
|
+
--color-input: var(--input);
|
|
35
|
+
--color-ring: var(--ring);
|
|
36
|
+
--color-chart-1: var(--chart-1);
|
|
37
|
+
--color-chart-2: var(--chart-2);
|
|
38
|
+
--color-chart-3: var(--chart-3);
|
|
39
|
+
--color-chart-4: var(--chart-4);
|
|
40
|
+
--color-chart-5: var(--chart-5);
|
|
41
|
+
--color-sidebar: var(--sidebar);
|
|
42
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
43
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
44
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
45
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
46
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
47
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
48
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:root {
|
|
52
|
+
--radius: 0.625rem;
|
|
53
|
+
--background: oklch(1 0 0);
|
|
54
|
+
--foreground: oklch(0.141 0.005 285.823);
|
|
55
|
+
--card: oklch(1 0 0);
|
|
56
|
+
--card-foreground: oklch(0.141 0.005 285.823);
|
|
57
|
+
--popover: oklch(1 0 0);
|
|
58
|
+
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
59
|
+
--primary: oklch(0.21 0.006 285.885);
|
|
60
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
61
|
+
--secondary: oklch(0.967 0.001 286.375);
|
|
62
|
+
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
63
|
+
--muted: oklch(0.967 0.001 286.375);
|
|
64
|
+
--muted-foreground: oklch(0.552 0.016 285.938);
|
|
65
|
+
--accent: oklch(0.967 0.001 286.375);
|
|
66
|
+
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
67
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
68
|
+
--border: oklch(0.92 0.004 286.32);
|
|
69
|
+
--input: oklch(0.92 0.004 286.32);
|
|
70
|
+
--ring: oklch(0.705 0.015 286.067);
|
|
71
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
72
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
73
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
74
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
75
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
76
|
+
--sidebar: oklch(0.985 0 0);
|
|
77
|
+
--sidebar-foreground: oklch(0.141 0.005 285.823);
|
|
78
|
+
--sidebar-primary: oklch(0.21 0.006 285.885);
|
|
79
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
80
|
+
--sidebar-accent: oklch(0.967 0.001 286.375);
|
|
81
|
+
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
|
|
82
|
+
--sidebar-border: oklch(0.92 0.004 286.32);
|
|
83
|
+
--sidebar-ring: oklch(0.705 0.015 286.067);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.dark {
|
|
87
|
+
--background: oklch(0.141 0.005 285.823);
|
|
88
|
+
--foreground: oklch(0.985 0 0);
|
|
89
|
+
--card: oklch(0.21 0.006 285.885);
|
|
90
|
+
--card-foreground: oklch(0.985 0 0);
|
|
91
|
+
--popover: oklch(0.21 0.006 285.885);
|
|
92
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
93
|
+
--primary: oklch(0.92 0.004 286.32);
|
|
94
|
+
--primary-foreground: oklch(0.21 0.006 285.885);
|
|
95
|
+
--secondary: oklch(0.274 0.006 286.033);
|
|
96
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
97
|
+
--muted: oklch(0.274 0.006 286.033);
|
|
98
|
+
--muted-foreground: oklch(0.705 0.015 286.067);
|
|
99
|
+
--accent: oklch(0.274 0.006 286.033);
|
|
100
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
101
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
102
|
+
--border: oklch(1 0 0 / 10%);
|
|
103
|
+
--input: oklch(1 0 0 / 15%);
|
|
104
|
+
--ring: oklch(0.552 0.016 285.938);
|
|
105
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
106
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
107
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
108
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
109
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
110
|
+
--sidebar: oklch(0.21 0.006 285.885);
|
|
111
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
112
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
113
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
114
|
+
--sidebar-accent: oklch(0.274 0.006 286.033);
|
|
115
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
116
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
117
|
+
--sidebar-ring: oklch(0.552 0.016 285.938);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@layer base {
|
|
121
|
+
* {
|
|
122
|
+
@apply border-border outline-ring/50;
|
|
123
|
+
}
|
|
124
|
+
body {
|
|
125
|
+
@apply bg-background text-foreground;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## app/layout.tsx
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import type { Metadata } from "next";
|
|
135
|
+
import "./globals.css";
|
|
136
|
+
import { MyRuntimeProvider } from "./MyRuntimeProvider";
|
|
137
|
+
|
|
138
|
+
export const metadata: Metadata = {
|
|
139
|
+
title: "LangChain useStream Example",
|
|
140
|
+
description:
|
|
141
|
+
"Example using @assistant-ui/react-langchain with LangChain's useStream hook.",
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default function RootLayout({
|
|
145
|
+
children,
|
|
146
|
+
}: Readonly<{
|
|
147
|
+
children: React.ReactNode;
|
|
148
|
+
}>) {
|
|
149
|
+
return (
|
|
150
|
+
<MyRuntimeProvider>
|
|
151
|
+
<html lang="en">
|
|
152
|
+
<body className="h-dvh">{children}</body>
|
|
153
|
+
</html>
|
|
154
|
+
</MyRuntimeProvider>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## app/MyRuntimeProvider.tsx
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
"use client";
|
|
164
|
+
|
|
165
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
166
|
+
import { useStreamRuntime } from "@assistant-ui/react-langchain";
|
|
167
|
+
|
|
168
|
+
export function MyRuntimeProvider({
|
|
169
|
+
children,
|
|
170
|
+
}: Readonly<{
|
|
171
|
+
children: React.ReactNode;
|
|
172
|
+
}>) {
|
|
173
|
+
const runtime = useStreamRuntime({
|
|
174
|
+
assistantId: process.env.NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID!,
|
|
175
|
+
apiUrl: process.env.NEXT_PUBLIC_LANGGRAPH_API_URL,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
180
|
+
{children}
|
|
181
|
+
</AssistantRuntimeProvider>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## app/page.tsx
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
"use client";
|
|
191
|
+
|
|
192
|
+
import { Thread } from "@/components/assistant-ui/thread";
|
|
193
|
+
import { TodosPanel } from "@/components/TodosPanel";
|
|
194
|
+
|
|
195
|
+
export default function Home() {
|
|
196
|
+
return (
|
|
197
|
+
<div className="flex h-dvh">
|
|
198
|
+
<div className="flex-grow">
|
|
199
|
+
<Thread />
|
|
200
|
+
</div>
|
|
201
|
+
<aside className="w-80 overflow-y-auto border-l p-4">
|
|
202
|
+
<TodosPanel />
|
|
203
|
+
</aside>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## components.json
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
215
|
+
"style": "new-york",
|
|
216
|
+
"rsc": true,
|
|
217
|
+
"tsx": true,
|
|
218
|
+
"tailwind": {
|
|
219
|
+
"config": "",
|
|
220
|
+
"css": "app/globals.css",
|
|
221
|
+
"baseColor": "zinc",
|
|
222
|
+
"cssVariables": true,
|
|
223
|
+
"prefix": ""
|
|
224
|
+
},
|
|
225
|
+
"aliases": {
|
|
226
|
+
"components": "@/components",
|
|
227
|
+
"utils": "@/lib/utils",
|
|
228
|
+
"ui": "@/components/ui",
|
|
229
|
+
"lib": "@/lib",
|
|
230
|
+
"hooks": "@/hooks"
|
|
231
|
+
},
|
|
232
|
+
"iconLibrary": "lucide",
|
|
233
|
+
"registries": {
|
|
234
|
+
"@assistant-ui": "https://r.assistant-ui.com/{name}.json"
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## components/TodosPanel.tsx
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
"use client";
|
|
244
|
+
|
|
245
|
+
import { useLangChainState } from "@assistant-ui/react-langchain";
|
|
246
|
+
|
|
247
|
+
type Todo = {
|
|
248
|
+
id?: string;
|
|
249
|
+
content: string;
|
|
250
|
+
status?: "pending" | "in_progress" | "completed";
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const statusIcon = (status: Todo["status"]) => {
|
|
254
|
+
switch (status) {
|
|
255
|
+
case "completed":
|
|
256
|
+
return "✓";
|
|
257
|
+
case "in_progress":
|
|
258
|
+
return "◐";
|
|
259
|
+
default:
|
|
260
|
+
return "○";
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export function TodosPanel() {
|
|
265
|
+
const todos = useLangChainState<Todo[]>("todos", []);
|
|
266
|
+
|
|
267
|
+
if (todos.length === 0) {
|
|
268
|
+
return (
|
|
269
|
+
<div className="text-muted-foreground text-sm">
|
|
270
|
+
Todos from the agent will appear here. This panel reads{" "}
|
|
271
|
+
<code className="rounded bg-muted px-1">state.todos</code> via{" "}
|
|
272
|
+
<code className="rounded bg-muted px-1">useLangChainState</code>.
|
|
273
|
+
</div>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return (
|
|
278
|
+
<div className="space-y-2">
|
|
279
|
+
<h2 className="font-semibold text-muted-foreground text-sm uppercase tracking-wide">
|
|
280
|
+
Agent todos
|
|
281
|
+
</h2>
|
|
282
|
+
<ul className="space-y-1">
|
|
283
|
+
{todos.map((todo, i) => (
|
|
284
|
+
<li
|
|
285
|
+
key={todo.id ?? i}
|
|
286
|
+
className="flex items-start gap-2 text-sm leading-relaxed"
|
|
287
|
+
>
|
|
288
|
+
<span aria-hidden>{statusIcon(todo.status)}</span>
|
|
289
|
+
<span
|
|
290
|
+
className={
|
|
291
|
+
todo.status === "completed"
|
|
292
|
+
? "text-muted-foreground line-through"
|
|
293
|
+
: undefined
|
|
294
|
+
}
|
|
295
|
+
>
|
|
296
|
+
{todo.content}
|
|
297
|
+
</span>
|
|
298
|
+
</li>
|
|
299
|
+
))}
|
|
300
|
+
</ul>
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## next.config.ts
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
import type { NextConfig } from "next";
|
|
311
|
+
|
|
312
|
+
const nextConfig: NextConfig = {
|
|
313
|
+
transpilePackages: ["@assistant-ui/react", "@assistant-ui/react-langchain"],
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export default nextConfig;
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## package.json
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"name": "with-langchain",
|
|
325
|
+
"version": "0.0.0",
|
|
326
|
+
"private": true,
|
|
327
|
+
"type": "module",
|
|
328
|
+
"scripts": {
|
|
329
|
+
"dev": "next dev",
|
|
330
|
+
"build": "next build",
|
|
331
|
+
"start": "next start"
|
|
332
|
+
},
|
|
333
|
+
"dependencies": {
|
|
334
|
+
"@assistant-ui/react": "workspace:*",
|
|
335
|
+
"@assistant-ui/react-langchain": "workspace:*",
|
|
336
|
+
"@assistant-ui/react-markdown": "workspace:*",
|
|
337
|
+
"@assistant-ui/ui": "workspace:*",
|
|
338
|
+
"@langchain/langgraph-sdk": "^1.8.9",
|
|
339
|
+
"@langchain/react": "^0.3.3",
|
|
340
|
+
"class-variance-authority": "^0.7.1",
|
|
341
|
+
"clsx": "^2.1.1",
|
|
342
|
+
"lucide-react": "^1.8.0",
|
|
343
|
+
"next": "^16.2.4",
|
|
344
|
+
"react": "^19.2.5",
|
|
345
|
+
"react-dom": "^19.2.5",
|
|
346
|
+
"tailwind-merge": "^3.5.0"
|
|
347
|
+
},
|
|
348
|
+
"devDependencies": {
|
|
349
|
+
"@assistant-ui/x-buildutils": "workspace:*",
|
|
350
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
351
|
+
"@types/node": "^25.6.0",
|
|
352
|
+
"@types/react": "^19.2.14",
|
|
353
|
+
"@types/react-dom": "^19.2.3",
|
|
354
|
+
"postcss": "^8.5.10",
|
|
355
|
+
"tailwindcss": "^4.2.4",
|
|
356
|
+
"tw-animate-css": "^1.4.0",
|
|
357
|
+
"typescript": "^6.0.3"
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## README.md
|
|
364
|
+
|
|
365
|
+
```markdown
|
|
366
|
+
# LangChain `useStream` Example
|
|
367
|
+
|
|
368
|
+
Demonstrates `@assistant-ui/react-langchain`, which wraps `useStream` from `@langchain/react` and exposes it as an assistant-ui runtime.
|
|
369
|
+
|
|
370
|
+
> assistant-ui also ships `@assistant-ui/react-langgraph`, which integrates with `@langchain/langgraph-sdk` directly and currently has a broader feature set. Pick the adapter that matches your upstream choice. See [the comparison](https://www.assistant-ui.com/docs/runtimes/langchain/comparison).
|
|
371
|
+
|
|
372
|
+
## Quick Start
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
pnpm install
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Environment Variables
|
|
379
|
+
|
|
380
|
+
Create `.env.local`:
|
|
381
|
+
|
|
382
|
+
```sh
|
|
383
|
+
NEXT_PUBLIC_LANGGRAPH_API_URL=http://localhost:2024
|
|
384
|
+
NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID=your_graph_id
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Start a local LangGraph server via [LangGraph Studio](https://github.com/langchain-ai/langgraph-studio) pointing at your graph, or use [LangSmith](https://www.langchain.com/langsmith) for a hosted deployment.
|
|
388
|
+
|
|
389
|
+
### Run
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
pnpm dev
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Open [http://localhost:3000](http://localhost:3000).
|
|
396
|
+
|
|
397
|
+
## Key Features
|
|
398
|
+
|
|
399
|
+
- `useStreamRuntime` — thin wrapper around `useStream` from `@langchain/react`.
|
|
400
|
+
- `useLangChainState<T>(key)` — reads arbitrary custom state keys (demo uses `state.todos` in `TodosPanel`).
|
|
401
|
+
- No hand-written stream generator, no `create` / `load` / `getCheckpointId` glue.
|
|
402
|
+
|
|
403
|
+
## Files of interest
|
|
404
|
+
|
|
405
|
+
- `app/MyRuntimeProvider.tsx` — entire runtime setup in ~15 lines.
|
|
406
|
+
- `components/TodosPanel.tsx` — demonstrates `useLangChainState<Todo[]>("todos", [])`.
|
|
407
|
+
|
|
408
|
+
## Related Documentation
|
|
409
|
+
|
|
410
|
+
- [assistant-ui Documentation](https://www.assistant-ui.com/docs)
|
|
411
|
+
- [LangChain useStream Integration](https://www.assistant-ui.com/docs/runtimes/langchain)
|
|
412
|
+
- [react-langgraph vs react-langchain](https://www.assistant-ui.com/docs/runtimes/langchain/comparison)
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## tsconfig.json
|
|
417
|
+
|
|
418
|
+
```json
|
|
419
|
+
{
|
|
420
|
+
"extends": "@assistant-ui/x-buildutils/ts/next",
|
|
421
|
+
"compilerOptions": {
|
|
422
|
+
"paths": {
|
|
423
|
+
"@/*": ["./*"],
|
|
424
|
+
"@/components/assistant-ui/*": [
|
|
425
|
+
"../../packages/ui/src/components/assistant-ui/*"
|
|
426
|
+
],
|
|
427
|
+
"@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
|
|
428
|
+
"@/lib/utils": ["../../packages/ui/src/lib/utils"],
|
|
429
|
+
"@assistant-ui/ui/*": ["../../packages/ui/src/*"]
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
"include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
433
|
+
"exclude": ["node_modules"]
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
```
|
|
437
|
+
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## app/api/[..._path]/route.ts
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
import { NextRequest, NextResponse } from "next/server";
|
|
6
|
+
import { type NextRequest, NextResponse } from "next/server";
|
|
7
7
|
|
|
8
8
|
function getCorsHeaders() {
|
|
9
9
|
return {
|
|
@@ -27,7 +27,7 @@ async function handleRequest(req: NextRequest, method: string) {
|
|
|
27
27
|
const options: RequestInit = {
|
|
28
28
|
method,
|
|
29
29
|
headers: {
|
|
30
|
-
"x-api-key": process.env
|
|
30
|
+
"x-api-key": process.env.LANGCHAIN_API_KEY || "",
|
|
31
31
|
},
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -36,7 +36,7 @@ async function handleRequest(req: NextRequest, method: string) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const res = await fetch(
|
|
39
|
-
`${process.env
|
|
39
|
+
`${process.env.LANGGRAPH_API_URL}/${path}${queryString}`,
|
|
40
40
|
options,
|
|
41
41
|
);
|
|
42
42
|
|
|
@@ -250,7 +250,7 @@ import {
|
|
|
250
250
|
getCheckpointId,
|
|
251
251
|
sendMessage,
|
|
252
252
|
} from "@/lib/chatApi";
|
|
253
|
-
import { LangChainMessage } from "@assistant-ui/react-langgraph";
|
|
253
|
+
import type { LangChainMessage } from "@assistant-ui/react-langgraph";
|
|
254
254
|
|
|
255
255
|
export function MyRuntimeProvider({
|
|
256
256
|
children,
|
|
@@ -672,7 +672,7 @@ export function TransactionConfirmationPending(props: TransactionConfirmation) {
|
|
|
672
672
|
## components/tools/ToolFallback.tsx
|
|
673
673
|
|
|
674
674
|
```tsx
|
|
675
|
-
import { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
675
|
+
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
676
676
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
677
677
|
import { useState } from "react";
|
|
678
678
|
import { Button } from "@/components/ui/button";
|
|
@@ -721,8 +721,8 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
|
|
|
721
721
|
## lib/chatApi.ts
|
|
722
722
|
|
|
723
723
|
```typescript
|
|
724
|
-
import { ThreadState, Client } from "@langchain/langgraph-sdk";
|
|
725
|
-
import {
|
|
724
|
+
import { type ThreadState, Client } from "@langchain/langgraph-sdk";
|
|
725
|
+
import type {
|
|
726
726
|
LangChainMessage,
|
|
727
727
|
LangGraphMessagesEvent,
|
|
728
728
|
LangGraphSendMessageConfig,
|
|
@@ -730,7 +730,7 @@ import {
|
|
|
730
730
|
|
|
731
731
|
const createClient = () => {
|
|
732
732
|
const apiUrl =
|
|
733
|
-
process.env
|
|
733
|
+
process.env.NEXT_PUBLIC_LANGGRAPH_API_URL ||
|
|
734
734
|
new URL("/api", window.location.href).href;
|
|
735
735
|
return new Client({
|
|
736
736
|
apiUrl,
|
|
@@ -816,7 +816,7 @@ export const sendMessage = (params: {
|
|
|
816
816
|
|
|
817
817
|
return client.runs.stream(
|
|
818
818
|
params.threadId,
|
|
819
|
-
process.env
|
|
819
|
+
process.env.NEXT_PUBLIC_LANGGRAPH_ASSISTANT_ID!,
|
|
820
820
|
{
|
|
821
821
|
input: params.messages.length > 0 ? { messages: params.messages } : null,
|
|
822
822
|
config: {
|
|
@@ -824,7 +824,7 @@ export const sendMessage = (params: {
|
|
|
824
824
|
model_name: "openai",
|
|
825
825
|
},
|
|
826
826
|
},
|
|
827
|
-
streamMode: ["messages-tuple", "values"],
|
|
827
|
+
streamMode: ["messages-tuple", "values", "custom"],
|
|
828
828
|
...(checkpointId && { checkpoint_id: checkpointId }),
|
|
829
829
|
...restConfig,
|
|
830
830
|
},
|
|
@@ -871,25 +871,25 @@ export default nextConfig;
|
|
|
871
871
|
"@assistant-ui/react-langgraph": "workspace:*",
|
|
872
872
|
"@assistant-ui/react-markdown": "workspace:*",
|
|
873
873
|
"@assistant-ui/ui": "workspace:*",
|
|
874
|
-
"@langchain/langgraph-sdk": "^1.8.
|
|
874
|
+
"@langchain/langgraph-sdk": "^1.8.9",
|
|
875
875
|
"class-variance-authority": "^0.7.1",
|
|
876
876
|
"clsx": "^2.1.1",
|
|
877
|
-
"lucide-react": "^1.
|
|
878
|
-
"next": "^16.2.
|
|
879
|
-
"react": "^19.2.
|
|
880
|
-
"react-dom": "^19.2.
|
|
877
|
+
"lucide-react": "^1.8.0",
|
|
878
|
+
"next": "^16.2.4",
|
|
879
|
+
"react": "^19.2.5",
|
|
880
|
+
"react-dom": "^19.2.5",
|
|
881
881
|
"tailwind-merge": "^3.5.0"
|
|
882
882
|
},
|
|
883
883
|
"devDependencies": {
|
|
884
884
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
885
|
-
"@tailwindcss/postcss": "^4.2.
|
|
886
|
-
"@types/node": "^25.
|
|
885
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
886
|
+
"@types/node": "^25.6.0",
|
|
887
887
|
"@types/react": "^19.2.14",
|
|
888
888
|
"@types/react-dom": "^19.2.3",
|
|
889
|
-
"postcss": "^8.5.
|
|
890
|
-
"tailwindcss": "^4.2.
|
|
889
|
+
"postcss": "^8.5.10",
|
|
890
|
+
"tailwindcss": "^4.2.4",
|
|
891
891
|
"tw-animate-css": "^1.4.0",
|
|
892
|
-
"typescript": "
|
|
892
|
+
"typescript": "^6.0.3"
|
|
893
893
|
}
|
|
894
894
|
}
|
|
895
895
|
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { openai } from "@ai-sdk/openai";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
streamText,
|
|
9
|
+
type UIMessage,
|
|
10
|
+
convertToModelMessages,
|
|
11
|
+
stepCountIs,
|
|
12
|
+
} from "ai";
|
|
8
13
|
|
|
9
14
|
export const maxDuration = 30;
|
|
10
15
|
|
|
@@ -388,7 +393,13 @@ const UserMessage: FC = () => {
|
|
|
388
393
|
```typescript
|
|
389
394
|
import type { RealtimeVoiceAdapter } from "@assistant-ui/react";
|
|
390
395
|
import { createVoiceSession } from "@assistant-ui/react";
|
|
391
|
-
import {
|
|
396
|
+
import {
|
|
397
|
+
Room,
|
|
398
|
+
RoomEvent,
|
|
399
|
+
Track,
|
|
400
|
+
type RemoteTrack,
|
|
401
|
+
type RoomOptions,
|
|
402
|
+
} from "livekit-client";
|
|
392
403
|
|
|
393
404
|
export type LiveKitVoiceAdapterOptions = {
|
|
394
405
|
url: string;
|
|
@@ -414,6 +425,31 @@ export class LiveKitVoiceAdapter implements RealtimeVoiceAdapter {
|
|
|
414
425
|
|
|
415
426
|
return createVoiceSession(options, async (session) => {
|
|
416
427
|
let volumeInterval: ReturnType<typeof setInterval> | null = null;
|
|
428
|
+
const attachedAudioElements = new Set<HTMLMediaElement>();
|
|
429
|
+
|
|
430
|
+
const attachRemoteAudio = (track: RemoteTrack) => {
|
|
431
|
+
if (track.kind !== Track.Kind.Audio) return;
|
|
432
|
+
const element = track.attach();
|
|
433
|
+
element.style.display = "none";
|
|
434
|
+
document.body.appendChild(element);
|
|
435
|
+
attachedAudioElements.add(element);
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
const detachRemoteAudio = (track: RemoteTrack) => {
|
|
439
|
+
if (track.kind !== Track.Kind.Audio) return;
|
|
440
|
+
for (const element of track.detach()) {
|
|
441
|
+
element.remove();
|
|
442
|
+
attachedAudioElements.delete(element);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const cleanupAudioElements = () => {
|
|
447
|
+
for (const element of attachedAudioElements) element.remove();
|
|
448
|
+
attachedAudioElements.clear();
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
room.on(RoomEvent.TrackSubscribed, attachRemoteAudio);
|
|
452
|
+
room.on(RoomEvent.TrackUnsubscribed, detachRemoteAudio);
|
|
417
453
|
|
|
418
454
|
room.on(RoomEvent.Connected, () => {
|
|
419
455
|
session.setStatus({ type: "running" });
|
|
@@ -464,18 +500,23 @@ export class LiveKitVoiceAdapter implements RealtimeVoiceAdapter {
|
|
|
464
500
|
|
|
465
501
|
const token =
|
|
466
502
|
typeof this._token === "function" ? await this._token() : this._token;
|
|
467
|
-
if (session.isDisposed())
|
|
503
|
+
if (session.isDisposed()) {
|
|
504
|
+
cleanupAudioElements();
|
|
468
505
|
return { disconnect: () => {}, mute: () => {}, unmute: () => {} };
|
|
506
|
+
}
|
|
469
507
|
|
|
470
508
|
await room.connect(this._url, token);
|
|
471
|
-
if (session.isDisposed())
|
|
509
|
+
if (session.isDisposed()) {
|
|
510
|
+
cleanupAudioElements();
|
|
472
511
|
return { disconnect: () => {}, mute: () => {}, unmute: () => {} };
|
|
512
|
+
}
|
|
473
513
|
|
|
474
514
|
await room.localParticipant.setMicrophoneEnabled(true);
|
|
475
515
|
|
|
476
516
|
return {
|
|
477
517
|
disconnect: () => {
|
|
478
518
|
if (volumeInterval) clearInterval(volumeInterval);
|
|
519
|
+
cleanupAudioElements();
|
|
479
520
|
room.disconnect();
|
|
480
521
|
},
|
|
481
522
|
mute: () => {
|
|
@@ -512,35 +553,35 @@ export default nextConfig;
|
|
|
512
553
|
"version": "0.0.0",
|
|
513
554
|
"type": "module",
|
|
514
555
|
"dependencies": {
|
|
515
|
-
"@ai-sdk/openai": "^3.0.
|
|
516
|
-
"@ai-sdk/react": "^3.0.
|
|
556
|
+
"@ai-sdk/openai": "^3.0.53",
|
|
557
|
+
"@ai-sdk/react": "^3.0.170",
|
|
517
558
|
"@assistant-ui/react": "workspace:^",
|
|
518
559
|
"@assistant-ui/react-ai-sdk": "workspace:*",
|
|
519
560
|
"@assistant-ui/react-markdown": "workspace:^",
|
|
520
561
|
"@assistant-ui/ui": "workspace:*",
|
|
521
|
-
"@tailwindcss/postcss": "^4.2.
|
|
522
|
-
"ai": "^6.0.
|
|
562
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
563
|
+
"ai": "^6.0.168",
|
|
523
564
|
"class-variance-authority": "^0.7.1",
|
|
524
565
|
"clsx": "^2.1.1",
|
|
525
|
-
"livekit-client": "^2.18.
|
|
526
|
-
"livekit-server-sdk": "^2.15.
|
|
527
|
-
"lucide-react": "^1.
|
|
566
|
+
"livekit-client": "^2.18.4",
|
|
567
|
+
"livekit-server-sdk": "^2.15.1",
|
|
568
|
+
"lucide-react": "^1.8.0",
|
|
528
569
|
"motion": "^12.38.0",
|
|
529
|
-
"next": "^16.2.
|
|
530
|
-
"postcss": "^8.5.
|
|
531
|
-
"react": "^19.2.
|
|
532
|
-
"react-dom": "^19.2.
|
|
570
|
+
"next": "^16.2.4",
|
|
571
|
+
"postcss": "^8.5.10",
|
|
572
|
+
"react": "^19.2.5",
|
|
573
|
+
"react-dom": "^19.2.5",
|
|
533
574
|
"tailwind-merge": "^3.5.0",
|
|
534
|
-
"tailwindcss": "^4.2.
|
|
575
|
+
"tailwindcss": "^4.2.4",
|
|
535
576
|
"zod": "^4.3.6"
|
|
536
577
|
},
|
|
537
578
|
"devDependencies": {
|
|
538
579
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
539
|
-
"@types/node": "^25.
|
|
580
|
+
"@types/node": "^25.6.0",
|
|
540
581
|
"@types/react": "^19.2.14",
|
|
541
582
|
"@types/react-dom": "^19.2.3",
|
|
542
583
|
"tw-animate-css": "^1.4.0",
|
|
543
|
-
"typescript": "
|
|
584
|
+
"typescript": "^6.0.3"
|
|
544
585
|
},
|
|
545
586
|
"scripts": {
|
|
546
587
|
"dev": "next dev",
|