@assistant-ui/mcp-docs-server 0.1.21 → 0.1.23
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 +801 -0
- package/.docs/organized/code-examples/with-ag-ui.md +38 -26
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +38 -28
- package/.docs/organized/code-examples/with-artifacts.md +467 -0
- package/.docs/organized/code-examples/with-assistant-transport.md +31 -24
- package/.docs/organized/code-examples/with-chain-of-thought.md +607 -0
- package/.docs/organized/code-examples/with-cloud-standalone.md +675 -0
- package/.docs/organized/code-examples/with-cloud.md +34 -27
- package/.docs/organized/code-examples/with-custom-thread-list.md +34 -27
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +41 -30
- package/.docs/organized/code-examples/with-expo.md +2031 -0
- package/.docs/organized/code-examples/with-external-store.md +32 -25
- package/.docs/organized/code-examples/with-ffmpeg.md +31 -27
- package/.docs/organized/code-examples/with-langgraph.md +96 -38
- package/.docs/organized/code-examples/with-parent-id-grouping.md +32 -25
- package/.docs/organized/code-examples/with-react-hook-form.md +63 -58
- package/.docs/organized/code-examples/with-react-router.md +38 -30
- package/.docs/organized/code-examples/with-store.md +16 -24
- package/.docs/organized/code-examples/with-tanstack.md +36 -26
- package/.docs/organized/code-examples/with-tap-runtime.md +10 -24
- package/.docs/raw/docs/(docs)/cli.mdx +13 -6
- package/.docs/raw/docs/(docs)/guides/attachments.mdx +26 -3
- package/.docs/raw/docs/(docs)/guides/chain-of-thought.mdx +162 -0
- package/.docs/raw/docs/(docs)/guides/context-api.mdx +53 -52
- package/.docs/raw/docs/(docs)/guides/dictation.mdx +0 -2
- package/.docs/raw/docs/(docs)/guides/message-timing.mdx +169 -0
- package/.docs/raw/docs/(docs)/guides/quoting.mdx +327 -0
- package/.docs/raw/docs/(docs)/guides/speech.mdx +0 -1
- package/.docs/raw/docs/(docs)/index.mdx +13 -3
- package/.docs/raw/docs/(docs)/installation.mdx +8 -2
- package/.docs/raw/docs/(docs)/llm.mdx +10 -8
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +2 -2
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +27 -27
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +60 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +78 -4
- package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +32 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +61 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +1 -1
- package/.docs/raw/docs/(reference)/legacy/styled/assistant-modal.mdx +1 -6
- package/.docs/raw/docs/(reference)/legacy/styled/decomposition.mdx +2 -2
- package/.docs/raw/docs/(reference)/legacy/styled/markdown.mdx +1 -6
- package/.docs/raw/docs/(reference)/legacy/styled/thread.mdx +1 -5
- package/.docs/raw/docs/(reference)/migrations/v0-12.mdx +17 -17
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +205 -0
- package/.docs/raw/docs/cloud/ai-sdk.mdx +292 -0
- package/.docs/raw/docs/cloud/authorization.mdx +178 -79
- package/.docs/raw/docs/cloud/{persistence/langgraph.mdx → langgraph.mdx} +2 -2
- package/.docs/raw/docs/cloud/overview.mdx +29 -39
- package/.docs/raw/docs/react-native/adapters.mdx +118 -0
- package/.docs/raw/docs/react-native/custom-backend.mdx +210 -0
- package/.docs/raw/docs/react-native/hooks.mdx +364 -0
- package/.docs/raw/docs/react-native/index.mdx +332 -0
- package/.docs/raw/docs/react-native/primitives.mdx +653 -0
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +7 -15
- package/.docs/raw/docs/runtimes/assistant-transport.mdx +103 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +25 -2
- package/.docs/raw/docs/runtimes/data-stream.mdx +1 -3
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +113 -9
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +1 -4
- package/.docs/raw/docs/ui/attachment.mdx +4 -2
- package/.docs/raw/docs/ui/message-timing.mdx +92 -0
- package/.docs/raw/docs/ui/part-grouping.mdx +1 -1
- package/.docs/raw/docs/ui/reasoning.mdx +4 -4
- package/.docs/raw/docs/ui/scrollbar.mdx +2 -2
- package/.docs/raw/docs/ui/syntax-highlighting.mdx +55 -50
- package/.docs/raw/docs/ui/thread.mdx +16 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/tools/tests/integration.test.ts +2 -2
- package/src/tools/tests/json-parsing.test.ts +1 -1
- package/src/tools/tests/mcp-protocol.test.ts +1 -3
- package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +0 -108
|
@@ -314,13 +314,36 @@ export function MyRuntimeProvider({ children }: MyRuntimeProviderProps) {
|
|
|
314
314
|
"use client";
|
|
315
315
|
|
|
316
316
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
317
|
+
import { useAui, AuiProvider, Suggestions } from "@assistant-ui/react";
|
|
317
318
|
import { MyRuntimeProvider } from "./MyRuntimeProvider";
|
|
318
319
|
|
|
320
|
+
function ThreadWithSuggestions() {
|
|
321
|
+
const aui = useAui({
|
|
322
|
+
suggestions: Suggestions([
|
|
323
|
+
{
|
|
324
|
+
title: "What's the weather",
|
|
325
|
+
label: "in San Francisco?",
|
|
326
|
+
prompt: "What's the weather like in San Francisco today?",
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
title: "Tell me about yourself",
|
|
330
|
+
label: "and your capabilities",
|
|
331
|
+
prompt: "What can you help me with?",
|
|
332
|
+
},
|
|
333
|
+
]),
|
|
334
|
+
});
|
|
335
|
+
return (
|
|
336
|
+
<AuiProvider value={aui}>
|
|
337
|
+
<Thread />
|
|
338
|
+
</AuiProvider>
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
319
342
|
export default function Home() {
|
|
320
343
|
return (
|
|
321
344
|
<MyRuntimeProvider>
|
|
322
345
|
<div className="h-full">
|
|
323
|
-
<
|
|
346
|
+
<ThreadWithSuggestions />
|
|
324
347
|
</div>
|
|
325
348
|
</MyRuntimeProvider>
|
|
326
349
|
);
|
|
@@ -358,18 +381,6 @@ export default function Home() {
|
|
|
358
381
|
|
|
359
382
|
```
|
|
360
383
|
|
|
361
|
-
## lib/utils.ts
|
|
362
|
-
|
|
363
|
-
```typescript
|
|
364
|
-
import { clsx, type ClassValue } from "clsx";
|
|
365
|
-
import { twMerge } from "tailwind-merge";
|
|
366
|
-
|
|
367
|
-
export function cn(...inputs: ClassValue[]) {
|
|
368
|
-
return twMerge(clsx(inputs));
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
```
|
|
372
|
-
|
|
373
384
|
## next.config.js
|
|
374
385
|
|
|
375
386
|
```javascript
|
|
@@ -410,28 +421,23 @@ export default nextConfig;
|
|
|
410
421
|
"@assistant-ui/react-langgraph": "workspace:*",
|
|
411
422
|
"@assistant-ui/react-markdown": "workspace:*",
|
|
412
423
|
"@assistant-ui/ui": "workspace:*",
|
|
413
|
-
"@radix-ui/react-avatar": "^1.1.11",
|
|
414
|
-
"@radix-ui/react-collapsible": "^1.1.12",
|
|
415
|
-
"@radix-ui/react-dialog": "^1.1.15",
|
|
416
|
-
"@radix-ui/react-slot": "^1.2.4",
|
|
417
|
-
"@radix-ui/react-tooltip": "^1.2.8",
|
|
418
424
|
"class-variance-authority": "^0.7.1",
|
|
419
425
|
"clsx": "^2.1.1",
|
|
420
|
-
"lucide-react": "^0.
|
|
426
|
+
"lucide-react": "^0.575.0",
|
|
421
427
|
"next": "^16.1.6",
|
|
422
428
|
"react": "^19.2.4",
|
|
423
429
|
"react-dom": "^19.2.4",
|
|
424
|
-
"tailwind-merge": "^3.
|
|
430
|
+
"tailwind-merge": "^3.5.0",
|
|
425
431
|
"zod": "^4.3.6"
|
|
426
432
|
},
|
|
427
433
|
"devDependencies": {
|
|
428
434
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
429
|
-
"@tailwindcss/postcss": "^4.1
|
|
430
|
-
"@types/node": "^25.
|
|
431
|
-
"@types/react": "^19.2.
|
|
435
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
436
|
+
"@types/node": "^25.3.0",
|
|
437
|
+
"@types/react": "^19.2.14",
|
|
432
438
|
"@types/react-dom": "^19.2.3",
|
|
433
439
|
"postcss": "^8.5.6",
|
|
434
|
-
"tailwindcss": "^4.1
|
|
440
|
+
"tailwindcss": "^4.2.1",
|
|
435
441
|
"tw-animate-css": "^1.4.0",
|
|
436
442
|
"typescript": "^5.9.3"
|
|
437
443
|
}
|
|
@@ -531,6 +537,7 @@ Your backend server should:
|
|
|
531
537
|
"../../packages/ui/src/components/assistant-ui/*"
|
|
532
538
|
],
|
|
533
539
|
"@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
|
|
540
|
+
"@/lib/utils": ["../../packages/ui/src/lib/utils"],
|
|
534
541
|
"@assistant-ui/ui/*": ["../../packages/ui/src/*"]
|
|
535
542
|
}
|
|
536
543
|
},
|
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
# Example: with-chain-of-thought
|
|
2
|
+
|
|
3
|
+
## app/api/chat/route.ts
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { openai } from "@ai-sdk/openai";
|
|
7
|
+
import {
|
|
8
|
+
streamText,
|
|
9
|
+
convertToModelMessages,
|
|
10
|
+
tool,
|
|
11
|
+
stepCountIs,
|
|
12
|
+
zodSchema,
|
|
13
|
+
} from "ai";
|
|
14
|
+
import type { UIMessage } from "ai";
|
|
15
|
+
import { frontendTools } from "@assistant-ui/react-ai-sdk";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
|
|
18
|
+
export const maxDuration = 30;
|
|
19
|
+
|
|
20
|
+
export async function POST(req: Request) {
|
|
21
|
+
const {
|
|
22
|
+
messages,
|
|
23
|
+
tools,
|
|
24
|
+
}: { messages: UIMessage[]; tools: Record<string, any> } = await req.json();
|
|
25
|
+
|
|
26
|
+
const result = streamText({
|
|
27
|
+
// Use a reasoning model to showcase chain of thought
|
|
28
|
+
model: openai("o4-mini"),
|
|
29
|
+
messages: await convertToModelMessages(messages),
|
|
30
|
+
stopWhen: stepCountIs(10),
|
|
31
|
+
tools: {
|
|
32
|
+
// Frontend tools registered via makeAssistantTool (e.g. execute_js)
|
|
33
|
+
...frontendTools(tools),
|
|
34
|
+
|
|
35
|
+
// Backend-only tools
|
|
36
|
+
get_current_weather: tool({
|
|
37
|
+
description: "Get the current weather for a city",
|
|
38
|
+
inputSchema: zodSchema(
|
|
39
|
+
z.object({
|
|
40
|
+
city: z.string(),
|
|
41
|
+
}),
|
|
42
|
+
),
|
|
43
|
+
execute: async ({ city }) => {
|
|
44
|
+
return `The weather in ${city} is sunny, 72°F`;
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return result.toUIMessageStreamResponse();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## app/globals.css
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
@import "tailwindcss";
|
|
59
|
+
@import "tw-animate-css";
|
|
60
|
+
|
|
61
|
+
@source "../../../packages/ui/src";
|
|
62
|
+
|
|
63
|
+
@custom-variant dark (&:is(.dark *));
|
|
64
|
+
|
|
65
|
+
@theme inline {
|
|
66
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
67
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
68
|
+
--radius-lg: var(--radius);
|
|
69
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
70
|
+
--color-background: var(--background);
|
|
71
|
+
--color-foreground: var(--foreground);
|
|
72
|
+
--color-card: var(--card);
|
|
73
|
+
--color-card-foreground: var(--card-foreground);
|
|
74
|
+
--color-popover: var(--popover);
|
|
75
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
76
|
+
--color-primary: var(--primary);
|
|
77
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
78
|
+
--color-secondary: var(--secondary);
|
|
79
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
80
|
+
--color-muted: var(--muted);
|
|
81
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
82
|
+
--color-accent: var(--accent);
|
|
83
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
84
|
+
--color-destructive: var(--destructive);
|
|
85
|
+
--color-border: var(--border);
|
|
86
|
+
--color-input: var(--input);
|
|
87
|
+
--color-ring: var(--ring);
|
|
88
|
+
--color-chart-1: var(--chart-1);
|
|
89
|
+
--color-chart-2: var(--chart-2);
|
|
90
|
+
--color-chart-3: var(--chart-3);
|
|
91
|
+
--color-chart-4: var(--chart-4);
|
|
92
|
+
--color-chart-5: var(--chart-5);
|
|
93
|
+
--color-sidebar: var(--sidebar);
|
|
94
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
95
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
96
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
97
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
98
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
99
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
100
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
:root {
|
|
104
|
+
--radius: 0.625rem;
|
|
105
|
+
--background: oklch(1 0 0);
|
|
106
|
+
--foreground: oklch(0.141 0.005 285.823);
|
|
107
|
+
--card: oklch(1 0 0);
|
|
108
|
+
--card-foreground: oklch(0.141 0.005 285.823);
|
|
109
|
+
--popover: oklch(1 0 0);
|
|
110
|
+
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
111
|
+
--primary: oklch(0.21 0.006 285.885);
|
|
112
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
113
|
+
--secondary: oklch(0.967 0.001 286.375);
|
|
114
|
+
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
115
|
+
--muted: oklch(0.967 0.001 286.375);
|
|
116
|
+
--muted-foreground: oklch(0.552 0.016 285.938);
|
|
117
|
+
--accent: oklch(0.967 0.001 286.375);
|
|
118
|
+
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
119
|
+
--destructive: oklch(0.577 0.245 27.325);
|
|
120
|
+
--border: oklch(0.92 0.004 286.32);
|
|
121
|
+
--input: oklch(0.92 0.004 286.32);
|
|
122
|
+
--ring: oklch(0.705 0.015 286.067);
|
|
123
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
124
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
125
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
126
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
127
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
128
|
+
--sidebar: oklch(0.985 0 0);
|
|
129
|
+
--sidebar-foreground: oklch(0.141 0.005 285.823);
|
|
130
|
+
--sidebar-primary: oklch(0.21 0.006 285.885);
|
|
131
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
132
|
+
--sidebar-accent: oklch(0.967 0.001 286.375);
|
|
133
|
+
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
|
|
134
|
+
--sidebar-border: oklch(0.92 0.004 286.32);
|
|
135
|
+
--sidebar-ring: oklch(0.705 0.015 286.067);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.dark {
|
|
139
|
+
--background: oklch(0.141 0.005 285.823);
|
|
140
|
+
--foreground: oklch(0.985 0 0);
|
|
141
|
+
--card: oklch(0.21 0.006 285.885);
|
|
142
|
+
--card-foreground: oklch(0.985 0 0);
|
|
143
|
+
--popover: oklch(0.21 0.006 285.885);
|
|
144
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
145
|
+
--primary: oklch(0.92 0.004 286.32);
|
|
146
|
+
--primary-foreground: oklch(0.21 0.006 285.885);
|
|
147
|
+
--secondary: oklch(0.274 0.006 286.033);
|
|
148
|
+
--secondary-foreground: oklch(0.985 0 0);
|
|
149
|
+
--muted: oklch(0.274 0.006 286.033);
|
|
150
|
+
--muted-foreground: oklch(0.705 0.015 286.067);
|
|
151
|
+
--accent: oklch(0.274 0.006 286.033);
|
|
152
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
153
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
154
|
+
--border: oklch(1 0 0 / 10%);
|
|
155
|
+
--input: oklch(1 0 0 / 15%);
|
|
156
|
+
--ring: oklch(0.552 0.016 285.938);
|
|
157
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
158
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
159
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
160
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
161
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
162
|
+
--sidebar: oklch(0.21 0.006 285.885);
|
|
163
|
+
--sidebar-foreground: oklch(0.985 0 0);
|
|
164
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
165
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
166
|
+
--sidebar-accent: oklch(0.274 0.006 286.033);
|
|
167
|
+
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
168
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
169
|
+
--sidebar-ring: oklch(0.552 0.016 285.938);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@layer base {
|
|
173
|
+
* {
|
|
174
|
+
@apply border-border outline-ring/50;
|
|
175
|
+
}
|
|
176
|
+
body {
|
|
177
|
+
@apply bg-background text-foreground;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## app/layout.tsx
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
import type { Metadata } from "next";
|
|
187
|
+
import "./globals.css";
|
|
188
|
+
|
|
189
|
+
export const metadata: Metadata = {
|
|
190
|
+
title: "Chain of Thought Example",
|
|
191
|
+
description: "Example using ChainOfThoughtPrimitive with AI SDK",
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export default function RootLayout({
|
|
195
|
+
children,
|
|
196
|
+
}: Readonly<{
|
|
197
|
+
children: React.ReactNode;
|
|
198
|
+
}>) {
|
|
199
|
+
return (
|
|
200
|
+
<html lang="en">
|
|
201
|
+
<body className="h-dvh">{children}</body>
|
|
202
|
+
</html>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## app/MyThread.tsx
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
"use client";
|
|
212
|
+
|
|
213
|
+
import { type FC, type PropsWithChildren, useState } from "react";
|
|
214
|
+
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
215
|
+
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
216
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
217
|
+
import { Button } from "@/components/ui/button";
|
|
218
|
+
import {
|
|
219
|
+
AuiIf,
|
|
220
|
+
ChainOfThoughtPrimitive,
|
|
221
|
+
ComposerPrimitive,
|
|
222
|
+
MessagePrimitive,
|
|
223
|
+
ThreadPrimitive,
|
|
224
|
+
useAuiState,
|
|
225
|
+
} from "@assistant-ui/react";
|
|
226
|
+
import {
|
|
227
|
+
ArrowDownIcon,
|
|
228
|
+
ArrowUpIcon,
|
|
229
|
+
ChevronDownIcon,
|
|
230
|
+
ChevronRightIcon,
|
|
231
|
+
SquareIcon,
|
|
232
|
+
} from "lucide-react";
|
|
233
|
+
|
|
234
|
+
export const MyThread: FC = () => {
|
|
235
|
+
return (
|
|
236
|
+
<ThreadPrimitive.Root
|
|
237
|
+
className="flex h-full flex-col bg-background"
|
|
238
|
+
style={{ ["--thread-max-width" as string]: "44rem" }}
|
|
239
|
+
>
|
|
240
|
+
<ThreadPrimitive.Viewport className="flex flex-1 flex-col overflow-y-scroll scroll-smooth px-4 pt-8">
|
|
241
|
+
<ThreadPrimitive.Messages
|
|
242
|
+
components={{ UserMessage, AssistantMessage }}
|
|
243
|
+
/>
|
|
244
|
+
|
|
245
|
+
<ThreadPrimitive.ViewportFooter className="sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 pb-4">
|
|
246
|
+
<ThreadPrimitive.ScrollToBottom asChild>
|
|
247
|
+
<TooltipIconButton
|
|
248
|
+
tooltip="Scroll to bottom"
|
|
249
|
+
variant="outline"
|
|
250
|
+
className="absolute -top-12 self-center rounded-full p-4 disabled:invisible"
|
|
251
|
+
>
|
|
252
|
+
<ArrowDownIcon />
|
|
253
|
+
</TooltipIconButton>
|
|
254
|
+
</ThreadPrimitive.ScrollToBottom>
|
|
255
|
+
<Composer />
|
|
256
|
+
</ThreadPrimitive.ViewportFooter>
|
|
257
|
+
</ThreadPrimitive.Viewport>
|
|
258
|
+
</ThreadPrimitive.Root>
|
|
259
|
+
);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const Text: FC<{ text: string }> = ({ text }) => {
|
|
263
|
+
return <p>{text}</p>;
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const UserMessage: FC = () => {
|
|
267
|
+
return (
|
|
268
|
+
<MessagePrimitive.Root className="mx-auto w-full max-w-(--thread-max-width) py-3">
|
|
269
|
+
<div className="flex justify-end">
|
|
270
|
+
<div className="max-w-[80%] rounded-2xl bg-primary px-4 py-2 text-primary-foreground">
|
|
271
|
+
<MessagePrimitive.Parts components={{ Text }} />
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
</MessagePrimitive.Root>
|
|
275
|
+
);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const AssistantMessage: FC = () => {
|
|
279
|
+
return (
|
|
280
|
+
<MessagePrimitive.Root className="mx-auto w-full max-w-(--thread-max-width) py-3">
|
|
281
|
+
<div className="flex flex-col gap-2 px-2 leading-relaxed">
|
|
282
|
+
{/*
|
|
283
|
+
The ChainOfThought component is passed to MessagePrimitive.Parts.
|
|
284
|
+
When set, consecutive reasoning + tool-call parts are grouped together
|
|
285
|
+
and rendered through this component instead of individually.
|
|
286
|
+
*/}
|
|
287
|
+
<MessagePrimitive.Parts
|
|
288
|
+
components={{
|
|
289
|
+
Text: MarkdownText,
|
|
290
|
+
ChainOfThought,
|
|
291
|
+
}}
|
|
292
|
+
/>
|
|
293
|
+
</div>
|
|
294
|
+
</MessagePrimitive.Root>
|
|
295
|
+
);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* ChainOfThought component — rendered by MessagePrimitive.Parts when it
|
|
300
|
+
* encounters consecutive reasoning + tool-call parts.
|
|
301
|
+
*
|
|
302
|
+
* Uses ChainOfThoughtPrimitive.Root, AccordionTrigger, and Parts to create
|
|
303
|
+
* a collapsible accordion that groups all "thinking" steps together.
|
|
304
|
+
*/
|
|
305
|
+
const ChainOfThought: FC = () => {
|
|
306
|
+
return (
|
|
307
|
+
<ChainOfThoughtPrimitive.Root className="my-2 rounded-lg border">
|
|
308
|
+
<ChainOfThoughtPrimitive.AccordionTrigger className="flex w-full cursor-pointer items-center gap-2 px-4 py-2 font-medium text-sm hover:bg-muted/50">
|
|
309
|
+
<AuiIf condition={(s) => s.chainOfThought.collapsed}>
|
|
310
|
+
<ChevronRightIcon className="size-4 shrink-0" />
|
|
311
|
+
</AuiIf>
|
|
312
|
+
<AuiIf condition={(s) => !s.chainOfThought.collapsed}>
|
|
313
|
+
<ChevronDownIcon className="size-4 shrink-0" />
|
|
314
|
+
</AuiIf>
|
|
315
|
+
Thinking
|
|
316
|
+
</ChainOfThoughtPrimitive.AccordionTrigger>
|
|
317
|
+
<AuiIf condition={(s) => !s.chainOfThought.collapsed}>
|
|
318
|
+
<ChainOfThoughtPrimitive.Parts
|
|
319
|
+
components={{
|
|
320
|
+
Reasoning,
|
|
321
|
+
tools: { Fallback: ToolFallback },
|
|
322
|
+
Layout: PartLayout,
|
|
323
|
+
}}
|
|
324
|
+
/>
|
|
325
|
+
</AuiIf>
|
|
326
|
+
</ChainOfThoughtPrimitive.Root>
|
|
327
|
+
);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
const PartLayout: FC<PropsWithChildren> = ({ children }) => {
|
|
331
|
+
const partType = useAuiState((s) => s.part.type);
|
|
332
|
+
const [open, setOpen] = useState(true);
|
|
333
|
+
|
|
334
|
+
const label = partType === "reasoning" ? "Thinking" : "Taking action";
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<div className="border-t">
|
|
338
|
+
<button
|
|
339
|
+
type="button"
|
|
340
|
+
className="flex w-full cursor-pointer items-center gap-2 px-4 py-1.5 text-muted-foreground text-xs hover:bg-muted/50"
|
|
341
|
+
onClick={() => setOpen((o) => !o)}
|
|
342
|
+
>
|
|
343
|
+
{open ? (
|
|
344
|
+
<ChevronDownIcon className="size-3" />
|
|
345
|
+
) : (
|
|
346
|
+
<ChevronRightIcon className="size-3" />
|
|
347
|
+
)}
|
|
348
|
+
{label}
|
|
349
|
+
</button>
|
|
350
|
+
{open && children}
|
|
351
|
+
</div>
|
|
352
|
+
);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const Reasoning: FC<{ text: string }> = ({ text }) => {
|
|
356
|
+
return (
|
|
357
|
+
<p className="whitespace-pre-wrap px-4 py-2 text-muted-foreground text-sm italic">
|
|
358
|
+
{text}
|
|
359
|
+
</p>
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const Composer: FC = () => {
|
|
364
|
+
return (
|
|
365
|
+
<ComposerPrimitive.Root className="flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[textarea:focus-visible]:border-ring has-[textarea:focus-visible]:ring-2 has-[textarea:focus-visible]:ring-ring/20">
|
|
366
|
+
<ComposerPrimitive.Input
|
|
367
|
+
placeholder="Send a message..."
|
|
368
|
+
className="mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none placeholder:text-muted-foreground"
|
|
369
|
+
rows={1}
|
|
370
|
+
autoFocus
|
|
371
|
+
/>
|
|
372
|
+
<div className="relative mx-2 mb-2 flex items-center justify-end">
|
|
373
|
+
<AuiIf condition={(s) => !s.thread.isRunning}>
|
|
374
|
+
<ComposerPrimitive.Send asChild>
|
|
375
|
+
<TooltipIconButton
|
|
376
|
+
tooltip="Send"
|
|
377
|
+
side="bottom"
|
|
378
|
+
variant="default"
|
|
379
|
+
size="icon"
|
|
380
|
+
className="size-8 rounded-full"
|
|
381
|
+
>
|
|
382
|
+
<ArrowUpIcon className="size-4" />
|
|
383
|
+
</TooltipIconButton>
|
|
384
|
+
</ComposerPrimitive.Send>
|
|
385
|
+
</AuiIf>
|
|
386
|
+
<AuiIf condition={(s) => s.thread.isRunning}>
|
|
387
|
+
<ComposerPrimitive.Cancel asChild>
|
|
388
|
+
<Button
|
|
389
|
+
type="button"
|
|
390
|
+
variant="default"
|
|
391
|
+
size="icon"
|
|
392
|
+
className="size-8 rounded-full"
|
|
393
|
+
>
|
|
394
|
+
<SquareIcon className="size-3 fill-current" />
|
|
395
|
+
</Button>
|
|
396
|
+
</ComposerPrimitive.Cancel>
|
|
397
|
+
</AuiIf>
|
|
398
|
+
</div>
|
|
399
|
+
</ComposerPrimitive.Root>
|
|
400
|
+
);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## app/page.tsx
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
"use client";
|
|
409
|
+
|
|
410
|
+
import {
|
|
411
|
+
AssistantRuntimeProvider,
|
|
412
|
+
makeAssistantTool,
|
|
413
|
+
useAui,
|
|
414
|
+
AuiProvider,
|
|
415
|
+
Suggestions,
|
|
416
|
+
} from "@assistant-ui/react";
|
|
417
|
+
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
418
|
+
import { z } from "zod";
|
|
419
|
+
import { MyThread } from "./MyThread";
|
|
420
|
+
import { lastAssistantMessageIsCompleteWithApprovalResponses } from "ai";
|
|
421
|
+
|
|
422
|
+
const ExecuteJsTool = makeAssistantTool({
|
|
423
|
+
toolName: "execute_js",
|
|
424
|
+
description: "Execute JavaScript code and return the result",
|
|
425
|
+
parameters: z.object({
|
|
426
|
+
code: z.string().describe("The JavaScript code to execute"),
|
|
427
|
+
}),
|
|
428
|
+
execute: async ({ code }) => {
|
|
429
|
+
try {
|
|
430
|
+
// biome-ignore lint/security/noGlobalEval: example code
|
|
431
|
+
const result = eval(code);
|
|
432
|
+
return { success: true, result: String(result) };
|
|
433
|
+
} catch (e) {
|
|
434
|
+
return { success: false, error: String(e) };
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
render: ({ args, result, status }) => (
|
|
438
|
+
<div className="my-2 rounded-lg border bg-muted/30 p-4 text-sm">
|
|
439
|
+
<p className="mb-1 font-semibold">execute_js</p>
|
|
440
|
+
<pre className="whitespace-pre-wrap rounded bg-background p-2 font-mono text-xs">
|
|
441
|
+
{args.code}
|
|
442
|
+
</pre>
|
|
443
|
+
{status.type !== "running" && result && (
|
|
444
|
+
<div className="mt-2 border-t pt-2">
|
|
445
|
+
<p className="font-semibold text-muted-foreground">
|
|
446
|
+
{result.success ? "Result:" : "Error:"}
|
|
447
|
+
</p>
|
|
448
|
+
<pre className="whitespace-pre-wrap font-mono text-xs">
|
|
449
|
+
{result.success ? result.result : result.error}
|
|
450
|
+
</pre>
|
|
451
|
+
</div>
|
|
452
|
+
)}
|
|
453
|
+
</div>
|
|
454
|
+
),
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
function MyThreadWithSuggestions() {
|
|
458
|
+
const aui = useAui({
|
|
459
|
+
suggestions: Suggestions([
|
|
460
|
+
{
|
|
461
|
+
title: "Calculate Fibonacci(20)",
|
|
462
|
+
label: "step by step with code",
|
|
463
|
+
prompt: "Calculate the 20th Fibonacci number using JavaScript.",
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
title: "What is 2^16?",
|
|
467
|
+
label: "show your reasoning",
|
|
468
|
+
prompt: "What is 2 to the power of 16? Show your work step by step.",
|
|
469
|
+
},
|
|
470
|
+
]),
|
|
471
|
+
});
|
|
472
|
+
return (
|
|
473
|
+
<AuiProvider value={aui}>
|
|
474
|
+
<MyThread />
|
|
475
|
+
</AuiProvider>
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export default function Home() {
|
|
480
|
+
const runtime = useChatRuntime({
|
|
481
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
return (
|
|
485
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
486
|
+
<ExecuteJsTool />
|
|
487
|
+
<div className="h-full">
|
|
488
|
+
<MyThreadWithSuggestions />
|
|
489
|
+
</div>
|
|
490
|
+
</AssistantRuntimeProvider>
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
## components.json
|
|
497
|
+
|
|
498
|
+
```json
|
|
499
|
+
{
|
|
500
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
501
|
+
"style": "new-york",
|
|
502
|
+
"rsc": true,
|
|
503
|
+
"tsx": true,
|
|
504
|
+
"tailwind": {
|
|
505
|
+
"config": "",
|
|
506
|
+
"css": "app/globals.css",
|
|
507
|
+
"baseColor": "zinc",
|
|
508
|
+
"cssVariables": true,
|
|
509
|
+
"prefix": ""
|
|
510
|
+
},
|
|
511
|
+
"aliases": {
|
|
512
|
+
"components": "@/components",
|
|
513
|
+
"utils": "@/lib/utils",
|
|
514
|
+
"ui": "@/components/ui",
|
|
515
|
+
"lib": "@/lib",
|
|
516
|
+
"hooks": "@/hooks"
|
|
517
|
+
},
|
|
518
|
+
"iconLibrary": "lucide",
|
|
519
|
+
"registries": {
|
|
520
|
+
"@assistant-ui": "https://r.assistant-ui.com/{name}.json"
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## next.config.js
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
/** @type {import('next').NextConfig} */
|
|
530
|
+
const nextConfig = {
|
|
531
|
+
transpilePackages: ["@assistant-ui/react", "@assistant-ui/react-ai-sdk"],
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
export default nextConfig;
|
|
535
|
+
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## package.json
|
|
539
|
+
|
|
540
|
+
```json
|
|
541
|
+
{
|
|
542
|
+
"name": "with-chain-of-thought",
|
|
543
|
+
"version": "0.0.0",
|
|
544
|
+
"private": true,
|
|
545
|
+
"type": "module",
|
|
546
|
+
"scripts": {
|
|
547
|
+
"dev": "next dev",
|
|
548
|
+
"build": "next build",
|
|
549
|
+
"start": "next start"
|
|
550
|
+
},
|
|
551
|
+
"dependencies": {
|
|
552
|
+
"@ai-sdk/openai": "^3.0.33",
|
|
553
|
+
"@assistant-ui/react": "workspace:*",
|
|
554
|
+
"@assistant-ui/react-ai-sdk": "workspace:*",
|
|
555
|
+
"@assistant-ui/react-markdown": "workspace:*",
|
|
556
|
+
"@assistant-ui/ui": "workspace:*",
|
|
557
|
+
"ai": "^6.0.98",
|
|
558
|
+
"class-variance-authority": "^0.7.1",
|
|
559
|
+
"clsx": "^2.1.1",
|
|
560
|
+
"lucide-react": "^0.575.0",
|
|
561
|
+
"next": "^16.1.6",
|
|
562
|
+
"react": "^19.2.4",
|
|
563
|
+
"react-dom": "^19.2.4",
|
|
564
|
+
"tailwind-merge": "^3.5.0",
|
|
565
|
+
"zod": "^4.3.6"
|
|
566
|
+
},
|
|
567
|
+
"devDependencies": {
|
|
568
|
+
"@assistant-ui/x-buildutils": "workspace:*",
|
|
569
|
+
"@tailwindcss/postcss": "^4.2.1",
|
|
570
|
+
"@types/node": "^25.3.0",
|
|
571
|
+
"@types/react": "^19.2.14",
|
|
572
|
+
"@types/react-dom": "^19.2.3",
|
|
573
|
+
"postcss": "^8.5.6",
|
|
574
|
+
"tailwindcss": "^4.2.1",
|
|
575
|
+
"tw-animate-css": "^1.4.0",
|
|
576
|
+
"typescript": "^5.9.3"
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
## tsconfig.json
|
|
583
|
+
|
|
584
|
+
```json
|
|
585
|
+
{
|
|
586
|
+
"extends": "@assistant-ui/x-buildutils/ts/next",
|
|
587
|
+
"compilerOptions": {
|
|
588
|
+
"paths": {
|
|
589
|
+
"@/*": ["./*"],
|
|
590
|
+
"@/components/assistant-ui/*": [
|
|
591
|
+
"../../packages/ui/src/components/assistant-ui/*"
|
|
592
|
+
],
|
|
593
|
+
"@/components/ui/*": ["../../packages/ui/src/components/ui/*"],
|
|
594
|
+
"@/lib/utils": ["../../packages/ui/src/lib/utils"],
|
|
595
|
+
"@assistant-ui/ui/*": ["../../packages/ui/src/*"],
|
|
596
|
+
"@assistant-ui/*": ["../../packages/*/src"],
|
|
597
|
+
"@assistant-ui/react/*": ["../../packages/react/src/*"],
|
|
598
|
+
"@assistant-ui/tap/*": ["../../packages/tap/src/*"],
|
|
599
|
+
"assistant-stream": ["../../packages/assistant-stream/src"]
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
"include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
603
|
+
"exclude": ["node_modules"]
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
```
|
|
607
|
+
|