@assistant-ui/mcp-docs-server 0.1.1
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/local-ollama.md +1135 -0
- package/.docs/organized/code-examples/search-agent-for-e-commerce.md +1721 -0
- package/.docs/organized/code-examples/with-ai-sdk.md +1081 -0
- package/.docs/organized/code-examples/with-cloud.md +1164 -0
- package/.docs/organized/code-examples/with-external-store.md +1064 -0
- package/.docs/organized/code-examples/with-ffmpeg.md +1305 -0
- package/.docs/organized/code-examples/with-langgraph.md +1819 -0
- package/.docs/organized/code-examples/with-openai-assistants.md +1175 -0
- package/.docs/organized/code-examples/with-react-hook-form.md +1727 -0
- package/.docs/organized/code-examples/with-vercel-ai-rsc.md +1157 -0
- package/.docs/raw/blog/2024-07-29-hello/index.mdx +65 -0
- package/.docs/raw/blog/2024-09-11/index.mdx +10 -0
- package/.docs/raw/blog/2024-12-15/index.mdx +10 -0
- package/.docs/raw/blog/2025-01-31-changelog/index.mdx +129 -0
- package/.docs/raw/docs/about-assistantui.mdx +44 -0
- package/.docs/raw/docs/api-reference/context-providers/AssistantRuntimeProvider.mdx +30 -0
- package/.docs/raw/docs/api-reference/context-providers/TextContentPartProvider.mdx +26 -0
- package/.docs/raw/docs/api-reference/integrations/react-hook-form.mdx +103 -0
- package/.docs/raw/docs/api-reference/integrations/vercel-ai-sdk.mdx +145 -0
- package/.docs/raw/docs/api-reference/overview.mdx +583 -0
- package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +264 -0
- package/.docs/raw/docs/api-reference/primitives/AssistantModal.mdx +129 -0
- package/.docs/raw/docs/api-reference/primitives/Attachment.mdx +96 -0
- package/.docs/raw/docs/api-reference/primitives/BranchPicker.mdx +87 -0
- package/.docs/raw/docs/api-reference/primitives/Composer.mdx +204 -0
- package/.docs/raw/docs/api-reference/primitives/ContentPart.mdx +173 -0
- package/.docs/raw/docs/api-reference/primitives/Error.mdx +70 -0
- package/.docs/raw/docs/api-reference/primitives/Message.mdx +181 -0
- package/.docs/raw/docs/api-reference/primitives/Thread.mdx +197 -0
- package/.docs/raw/docs/api-reference/primitives/composition.mdx +21 -0
- package/.docs/raw/docs/api-reference/runtimes/AssistantRuntime.mdx +33 -0
- package/.docs/raw/docs/api-reference/runtimes/AttachmentRuntime.mdx +46 -0
- package/.docs/raw/docs/api-reference/runtimes/ComposerRuntime.mdx +69 -0
- package/.docs/raw/docs/api-reference/runtimes/ContentPartRuntime.mdx +22 -0
- package/.docs/raw/docs/api-reference/runtimes/MessageRuntime.mdx +49 -0
- package/.docs/raw/docs/api-reference/runtimes/ThreadListItemRuntime.mdx +32 -0
- package/.docs/raw/docs/api-reference/runtimes/ThreadListRuntime.mdx +31 -0
- package/.docs/raw/docs/api-reference/runtimes/ThreadRuntime.mdx +48 -0
- package/.docs/raw/docs/architecture.mdx +92 -0
- package/.docs/raw/docs/cloud/authorization.mdx +152 -0
- package/.docs/raw/docs/cloud/overview.mdx +55 -0
- package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +54 -0
- package/.docs/raw/docs/cloud/persistence/langgraph.mdx +123 -0
- package/.docs/raw/docs/concepts/architecture.mdx +19 -0
- package/.docs/raw/docs/concepts/runtime-layer.mdx +163 -0
- package/.docs/raw/docs/concepts/why.mdx +9 -0
- package/.docs/raw/docs/copilots/make-assistant-readable.mdx +71 -0
- package/.docs/raw/docs/copilots/make-assistant-tool-ui.mdx +76 -0
- package/.docs/raw/docs/copilots/make-assistant-tool.mdx +117 -0
- package/.docs/raw/docs/copilots/model-context.mdx +135 -0
- package/.docs/raw/docs/copilots/motivation.mdx +191 -0
- package/.docs/raw/docs/copilots/use-assistant-instructions.mdx +62 -0
- package/.docs/raw/docs/getting-started.mdx +1133 -0
- package/.docs/raw/docs/guides/Attachments.mdx +640 -0
- package/.docs/raw/docs/guides/Branching.mdx +59 -0
- package/.docs/raw/docs/guides/Editing.mdx +56 -0
- package/.docs/raw/docs/guides/Speech.mdx +43 -0
- package/.docs/raw/docs/guides/ToolUI.mdx +663 -0
- package/.docs/raw/docs/guides/Tools.mdx +496 -0
- package/.docs/raw/docs/index.mdx +7 -0
- package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +85 -0
- package/.docs/raw/docs/legacy/styled/Decomposition.mdx +633 -0
- package/.docs/raw/docs/legacy/styled/Markdown.mdx +86 -0
- package/.docs/raw/docs/legacy/styled/Scrollbar.mdx +71 -0
- package/.docs/raw/docs/legacy/styled/Thread.mdx +84 -0
- package/.docs/raw/docs/legacy/styled/ThreadWidth.mdx +21 -0
- package/.docs/raw/docs/mcp-docs-server.mdx +324 -0
- package/.docs/raw/docs/migrations/deprecation-policy.mdx +41 -0
- package/.docs/raw/docs/migrations/v0-7.mdx +188 -0
- package/.docs/raw/docs/migrations/v0-8.mdx +160 -0
- package/.docs/raw/docs/migrations/v0-9.mdx +75 -0
- package/.docs/raw/docs/react-compatibility.mdx +208 -0
- package/.docs/raw/docs/runtimes/ai-sdk/rsc.mdx +226 -0
- package/.docs/raw/docs/runtimes/ai-sdk/use-assistant-hook.mdx +195 -0
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat-hook.mdx +138 -0
- package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +136 -0
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +1624 -0
- package/.docs/raw/docs/runtimes/custom/local.mdx +1185 -0
- package/.docs/raw/docs/runtimes/helicone.mdx +60 -0
- package/.docs/raw/docs/runtimes/langgraph/index.mdx +320 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/index.mdx +11 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +28 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +120 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +336 -0
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +385 -0
- package/.docs/raw/docs/runtimes/langserve.mdx +126 -0
- package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +218 -0
- package/.docs/raw/docs/runtimes/mastra/overview.mdx +17 -0
- package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +196 -0
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +222 -0
- package/.docs/raw/docs/ui/AssistantModal.mdx +46 -0
- package/.docs/raw/docs/ui/AssistantSidebar.mdx +42 -0
- package/.docs/raw/docs/ui/Attachment.mdx +82 -0
- package/.docs/raw/docs/ui/Markdown.mdx +72 -0
- package/.docs/raw/docs/ui/Mermaid.mdx +79 -0
- package/.docs/raw/docs/ui/Scrollbar.mdx +59 -0
- package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +253 -0
- package/.docs/raw/docs/ui/Thread.mdx +47 -0
- package/.docs/raw/docs/ui/ThreadList.mdx +49 -0
- package/.docs/raw/docs/ui/ToolFallback.mdx +64 -0
- package/.docs/raw/docs/ui/primitives/Thread.mdx +197 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/chunk-C7O7EFKU.js +38 -0
- package/dist/chunk-CZCDQ3YH.js +420 -0
- package/dist/index.js +1 -0
- package/dist/prepare-docs/prepare.js +199 -0
- package/dist/stdio.js +8 -0
- package/package.json +43 -0
|
@@ -0,0 +1,1133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import { Step, Steps } from "fumadocs-ui/components/steps";
|
|
6
|
+
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
|
7
|
+
import { Callout } from "fumadocs-ui/components/callout";
|
|
8
|
+
import { Card, Cards } from "fumadocs-ui/components/card";
|
|
9
|
+
|
|
10
|
+
## Start with a new project
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
<Steps>
|
|
15
|
+
<Step>
|
|
16
|
+
|
|
17
|
+
### Initialize assistant-ui
|
|
18
|
+
**Create a new project:**
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
# Create a new project with the default template
|
|
22
|
+
npx assistant-ui@latest create
|
|
23
|
+
|
|
24
|
+
# Or start with a template:
|
|
25
|
+
# LangGraph
|
|
26
|
+
npx assistant-ui@latest create -t langgraph
|
|
27
|
+
|
|
28
|
+
# MCP support
|
|
29
|
+
npx assistant-ui@latest create -t mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Add assistant-ui to an existing React project:**
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
# Add assistant-ui to an existing React project
|
|
36
|
+
npx assistant-ui@latest init
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
</Step>
|
|
40
|
+
<Step>
|
|
41
|
+
|
|
42
|
+
### Add API key
|
|
43
|
+
|
|
44
|
+
Add a new `.env` file to your project with your OpenAI API key:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
48
|
+
|
|
49
|
+
# chat history -- sign up for free on https://cloud.assistant-ui.com
|
|
50
|
+
# NEXT_PUBLIC_ASSISTANT_BASE_URL="https://..."
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
</Step>
|
|
54
|
+
<Step>
|
|
55
|
+
|
|
56
|
+
### Start the app
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npm run dev
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
</Step>
|
|
63
|
+
</Steps>
|
|
64
|
+
|
|
65
|
+
## Manual installation
|
|
66
|
+
|
|
67
|
+
<Callout>
|
|
68
|
+
We recommend `npx assistant-ui init` to setup existing projects.
|
|
69
|
+
</Callout>
|
|
70
|
+
|
|
71
|
+
<Steps>
|
|
72
|
+
<Step>
|
|
73
|
+
|
|
74
|
+
### Add assistant-ui
|
|
75
|
+
|
|
76
|
+
<Tabs items={["With Tailwind (Recommended)", "Without Tailwind"]}>
|
|
77
|
+
<Tab>
|
|
78
|
+
|
|
79
|
+
```sh npm2yarn
|
|
80
|
+
npx assistant-ui add thread thread-list
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
</Tab>
|
|
84
|
+
<Tab>
|
|
85
|
+
<Steps>
|
|
86
|
+
<Step>
|
|
87
|
+
|
|
88
|
+
Add the following packages:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npm install \
|
|
92
|
+
@assistant-ui/react \
|
|
93
|
+
@assistant-ui/react-markdown \
|
|
94
|
+
@assistant-ui/styles \
|
|
95
|
+
@radix-ui/react-tooltip \
|
|
96
|
+
@radix-ui/react-slot \
|
|
97
|
+
lucide-react \
|
|
98
|
+
remark-gfm \
|
|
99
|
+
class-variance-authority \
|
|
100
|
+
clsx
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
</Step>
|
|
104
|
+
|
|
105
|
+
<Step>
|
|
106
|
+
|
|
107
|
+
Copy the following components into your project:
|
|
108
|
+
|
|
109
|
+
```tsx title="components/ui/button.tsx"
|
|
110
|
+
import * as React from "react";
|
|
111
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
112
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
113
|
+
|
|
114
|
+
import { cn } from "@/lib/utils";
|
|
115
|
+
|
|
116
|
+
const buttonVariants = cva("aui-button", {
|
|
117
|
+
variants: {
|
|
118
|
+
variant: {
|
|
119
|
+
default: "aui-button-primary",
|
|
120
|
+
outline: "aui-button-outline",
|
|
121
|
+
ghost: "aui-button-ghost",
|
|
122
|
+
},
|
|
123
|
+
size: {
|
|
124
|
+
default: "aui-button-medium",
|
|
125
|
+
icon: "aui-button-icon",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
defaultVariants: {
|
|
129
|
+
variant: "default",
|
|
130
|
+
size: "default",
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
function Button({
|
|
135
|
+
className,
|
|
136
|
+
variant,
|
|
137
|
+
size,
|
|
138
|
+
asChild = false,
|
|
139
|
+
...props
|
|
140
|
+
}: React.ComponentProps<"button"> &
|
|
141
|
+
VariantProps<typeof buttonVariants> & {
|
|
142
|
+
asChild?: boolean;
|
|
143
|
+
}) {
|
|
144
|
+
const Comp = asChild ? Slot : "button";
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<Comp
|
|
148
|
+
data-slot="button"
|
|
149
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
150
|
+
{...props}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export { Button, buttonVariants };
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```tsx title="components/ui/tooltip.tsx"
|
|
159
|
+
"use client";
|
|
160
|
+
|
|
161
|
+
import * as React from "react";
|
|
162
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
163
|
+
|
|
164
|
+
import { cn } from "@/lib/utils";
|
|
165
|
+
|
|
166
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
167
|
+
|
|
168
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
169
|
+
|
|
170
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
171
|
+
|
|
172
|
+
const TooltipContent = React.forwardRef<
|
|
173
|
+
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
174
|
+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
175
|
+
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
176
|
+
<TooltipPrimitive.Portal>
|
|
177
|
+
<TooltipPrimitive.Content
|
|
178
|
+
ref={ref}
|
|
179
|
+
sideOffset={sideOffset}
|
|
180
|
+
className={cn("aui-tooltip-content", className)}
|
|
181
|
+
{...props}
|
|
182
|
+
/>
|
|
183
|
+
</TooltipPrimitive.Portal>
|
|
184
|
+
));
|
|
185
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
186
|
+
|
|
187
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```tsx title="components/assistant-ui/thread.tsx"
|
|
191
|
+
import {
|
|
192
|
+
ActionBarPrimitive,
|
|
193
|
+
BranchPickerPrimitive,
|
|
194
|
+
ComposerPrimitive,
|
|
195
|
+
MessagePrimitive,
|
|
196
|
+
ThreadPrimitive,
|
|
197
|
+
} from "@assistant-ui/react";
|
|
198
|
+
import type { FC } from "react";
|
|
199
|
+
import {
|
|
200
|
+
ArrowDownIcon,
|
|
201
|
+
CheckIcon,
|
|
202
|
+
ChevronLeftIcon,
|
|
203
|
+
ChevronRightIcon,
|
|
204
|
+
CopyIcon,
|
|
205
|
+
PencilIcon,
|
|
206
|
+
RefreshCwIcon,
|
|
207
|
+
SendHorizontalIcon,
|
|
208
|
+
} from "lucide-react";
|
|
209
|
+
import { cn } from "@/lib/utils";
|
|
210
|
+
|
|
211
|
+
import { Button } from "@/components/ui/button";
|
|
212
|
+
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
213
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
214
|
+
|
|
215
|
+
export const Thread: FC = () => {
|
|
216
|
+
return (
|
|
217
|
+
<ThreadPrimitive.Root
|
|
218
|
+
className="aui-root aui-thread-root"
|
|
219
|
+
style={{
|
|
220
|
+
["--thread-max-width" as string]: "42rem",
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
223
|
+
<ThreadPrimitive.Viewport className="aui-thread-viewport">
|
|
224
|
+
<ThreadWelcome />
|
|
225
|
+
|
|
226
|
+
<ThreadPrimitive.Messages
|
|
227
|
+
components={{
|
|
228
|
+
UserMessage: UserMessage,
|
|
229
|
+
EditComposer: EditComposer,
|
|
230
|
+
AssistantMessage: AssistantMessage,
|
|
231
|
+
}}
|
|
232
|
+
/>
|
|
233
|
+
|
|
234
|
+
<ThreadPrimitive.If empty={false}>
|
|
235
|
+
<div className="aui-thread-viewport-spacer" />
|
|
236
|
+
</ThreadPrimitive.If>
|
|
237
|
+
|
|
238
|
+
<div className="aui-thread-viewport-footer">
|
|
239
|
+
<ThreadScrollToBottom />
|
|
240
|
+
<Composer />
|
|
241
|
+
</div>
|
|
242
|
+
</ThreadPrimitive.Viewport>
|
|
243
|
+
</ThreadPrimitive.Root>
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const ThreadScrollToBottom: FC = () => {
|
|
248
|
+
return (
|
|
249
|
+
<ThreadPrimitive.ScrollToBottom asChild>
|
|
250
|
+
<TooltipIconButton
|
|
251
|
+
tooltip="Scroll to bottom"
|
|
252
|
+
variant="outline"
|
|
253
|
+
className="aui-thread-scroll-to-bottom"
|
|
254
|
+
>
|
|
255
|
+
<ArrowDownIcon />
|
|
256
|
+
</TooltipIconButton>
|
|
257
|
+
</ThreadPrimitive.ScrollToBottom>
|
|
258
|
+
);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const ThreadWelcome: FC = () => {
|
|
262
|
+
return (
|
|
263
|
+
<ThreadPrimitive.Empty>
|
|
264
|
+
<div className="aui-thread-welcome-root">
|
|
265
|
+
<div className="aui-thread-welcome-center">
|
|
266
|
+
<p className="aui-thread-welcome-message">
|
|
267
|
+
How can I help you today?
|
|
268
|
+
</p>
|
|
269
|
+
</div>
|
|
270
|
+
<ThreadWelcomeSuggestions />
|
|
271
|
+
</div>
|
|
272
|
+
</ThreadPrimitive.Empty>
|
|
273
|
+
);
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const ThreadWelcomeSuggestions: FC = () => {
|
|
277
|
+
return (
|
|
278
|
+
<div className="aui-thread-welcome-suggestions">
|
|
279
|
+
<ThreadPrimitive.Suggestion
|
|
280
|
+
className="aui-thread-welcome-suggestion"
|
|
281
|
+
prompt="What is the weather in Tokyo?"
|
|
282
|
+
method="replace"
|
|
283
|
+
autoSend
|
|
284
|
+
>
|
|
285
|
+
<span className="aui-thread-welcome-suggestion-text">
|
|
286
|
+
What is the weather in Tokyo?
|
|
287
|
+
</span>
|
|
288
|
+
</ThreadPrimitive.Suggestion>
|
|
289
|
+
<ThreadPrimitive.Suggestion
|
|
290
|
+
className="aui-thread-welcome-suggestion"
|
|
291
|
+
prompt="What is assistant-ui?"
|
|
292
|
+
method="replace"
|
|
293
|
+
autoSend
|
|
294
|
+
>
|
|
295
|
+
<span className="aui-thread-welcome-suggestion-text">
|
|
296
|
+
What is assistant-ui?
|
|
297
|
+
</span>
|
|
298
|
+
</ThreadPrimitive.Suggestion>
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const Composer: FC = () => {
|
|
304
|
+
return (
|
|
305
|
+
<ComposerPrimitive.Root className="aui-composer-root">
|
|
306
|
+
<ComposerPrimitive.Input
|
|
307
|
+
rows={1}
|
|
308
|
+
autoFocus
|
|
309
|
+
placeholder="Write a message..."
|
|
310
|
+
className="aui-composer-input"
|
|
311
|
+
/>
|
|
312
|
+
<ComposerAction />
|
|
313
|
+
</ComposerPrimitive.Root>
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const ComposerAction: FC = () => {
|
|
318
|
+
return (
|
|
319
|
+
<>
|
|
320
|
+
<ThreadPrimitive.If running={false}>
|
|
321
|
+
<ComposerPrimitive.Send asChild>
|
|
322
|
+
<TooltipIconButton
|
|
323
|
+
tooltip="Send"
|
|
324
|
+
variant="default"
|
|
325
|
+
className="aui-composer-send"
|
|
326
|
+
>
|
|
327
|
+
<SendHorizontalIcon />
|
|
328
|
+
</TooltipIconButton>
|
|
329
|
+
</ComposerPrimitive.Send>
|
|
330
|
+
</ThreadPrimitive.If>
|
|
331
|
+
<ThreadPrimitive.If running>
|
|
332
|
+
<ComposerPrimitive.Cancel asChild>
|
|
333
|
+
<TooltipIconButton
|
|
334
|
+
tooltip="Cancel"
|
|
335
|
+
variant="default"
|
|
336
|
+
className="aui-composer-cancel"
|
|
337
|
+
>
|
|
338
|
+
<CircleStopIcon />
|
|
339
|
+
</TooltipIconButton>
|
|
340
|
+
</ComposerPrimitive.Cancel>
|
|
341
|
+
</ThreadPrimitive.If>
|
|
342
|
+
</>
|
|
343
|
+
);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const UserMessage: FC = () => {
|
|
347
|
+
return (
|
|
348
|
+
<MessagePrimitive.Root className="aui-user-message-root">
|
|
349
|
+
<UserActionBar />
|
|
350
|
+
|
|
351
|
+
<div className="aui-user-message-content">
|
|
352
|
+
<MessagePrimitive.Content />
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
<BranchPicker className="aui-user-branch-picker" />
|
|
356
|
+
</MessagePrimitive.Root>
|
|
357
|
+
);
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const UserActionBar: FC = () => {
|
|
361
|
+
return (
|
|
362
|
+
<ActionBarPrimitive.Root
|
|
363
|
+
hideWhenRunning
|
|
364
|
+
autohide="not-last"
|
|
365
|
+
className="aui-user-action-bar-root"
|
|
366
|
+
>
|
|
367
|
+
<ActionBarPrimitive.Edit asChild>
|
|
368
|
+
<TooltipIconButton tooltip="Edit">
|
|
369
|
+
<PencilIcon />
|
|
370
|
+
</TooltipIconButton>
|
|
371
|
+
</ActionBarPrimitive.Edit>
|
|
372
|
+
</ActionBarPrimitive.Root>
|
|
373
|
+
);
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const EditComposer: FC = () => {
|
|
377
|
+
return (
|
|
378
|
+
<ComposerPrimitive.Root className="aui-edit-composer-root">
|
|
379
|
+
<ComposerPrimitive.Input className="aui-edit-composer-input" />
|
|
380
|
+
|
|
381
|
+
<div className="aui-edit-composer-footer">
|
|
382
|
+
<ComposerPrimitive.Cancel asChild>
|
|
383
|
+
<Button variant="ghost">Cancel</Button>
|
|
384
|
+
</ComposerPrimitive.Cancel>
|
|
385
|
+
<ComposerPrimitive.Send asChild>
|
|
386
|
+
<Button>Send</Button>
|
|
387
|
+
</ComposerPrimitive.Send>
|
|
388
|
+
</div>
|
|
389
|
+
</ComposerPrimitive.Root>
|
|
390
|
+
);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const AssistantMessage: FC = () => {
|
|
394
|
+
return (
|
|
395
|
+
<MessagePrimitive.Root className="aui-assistant-message-root">
|
|
396
|
+
<div className="aui-assistant-message-content">
|
|
397
|
+
<MessagePrimitive.Content components={{ Text: MarkdownText }} />
|
|
398
|
+
</div>
|
|
399
|
+
|
|
400
|
+
<AssistantActionBar />
|
|
401
|
+
|
|
402
|
+
<BranchPicker className="aui-assistant-branch-picker" />
|
|
403
|
+
</MessagePrimitive.Root>
|
|
404
|
+
);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const AssistantActionBar: FC = () => {
|
|
408
|
+
return (
|
|
409
|
+
<ActionBarPrimitive.Root
|
|
410
|
+
hideWhenRunning
|
|
411
|
+
autohide="not-last"
|
|
412
|
+
autohideFloat="single-branch"
|
|
413
|
+
className="aui-assistant-action-bar-root"
|
|
414
|
+
>
|
|
415
|
+
<ActionBarPrimitive.Copy asChild>
|
|
416
|
+
<TooltipIconButton tooltip="Copy">
|
|
417
|
+
<MessagePrimitive.If copied>
|
|
418
|
+
<CheckIcon />
|
|
419
|
+
</MessagePrimitive.If>
|
|
420
|
+
<MessagePrimitive.If copied={false}>
|
|
421
|
+
<CopyIcon />
|
|
422
|
+
</MessagePrimitive.If>
|
|
423
|
+
</TooltipIconButton>
|
|
424
|
+
</ActionBarPrimitive.Copy>
|
|
425
|
+
<ActionBarPrimitive.Reload asChild>
|
|
426
|
+
<TooltipIconButton tooltip="Refresh">
|
|
427
|
+
<RefreshCwIcon />
|
|
428
|
+
</TooltipIconButton>
|
|
429
|
+
</ActionBarPrimitive.Reload>
|
|
430
|
+
</ActionBarPrimitive.Root>
|
|
431
|
+
);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
435
|
+
className,
|
|
436
|
+
...rest
|
|
437
|
+
}) => {
|
|
438
|
+
return (
|
|
439
|
+
<BranchPickerPrimitive.Root
|
|
440
|
+
hideWhenSingleBranch
|
|
441
|
+
className={cn("aui-branch-picker-root", className)}
|
|
442
|
+
{...rest}
|
|
443
|
+
>
|
|
444
|
+
<BranchPickerPrimitive.Previous asChild>
|
|
445
|
+
<TooltipIconButton tooltip="Previous">
|
|
446
|
+
<ChevronLeftIcon />
|
|
447
|
+
</TooltipIconButton>
|
|
448
|
+
</BranchPickerPrimitive.Previous>
|
|
449
|
+
<span className="aui-branch-picker-state">
|
|
450
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
451
|
+
</span>
|
|
452
|
+
<BranchPickerPrimitive.Next asChild>
|
|
453
|
+
<TooltipIconButton tooltip="Next">
|
|
454
|
+
<ChevronRightIcon />
|
|
455
|
+
</TooltipIconButton>
|
|
456
|
+
</BranchPickerPrimitive.Next>
|
|
457
|
+
</BranchPickerPrimitive.Root>
|
|
458
|
+
);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const CircleStopIcon = () => {
|
|
462
|
+
return (
|
|
463
|
+
<svg
|
|
464
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
465
|
+
viewBox="0 0 16 16"
|
|
466
|
+
fill="currentColor"
|
|
467
|
+
width="16"
|
|
468
|
+
height="16"
|
|
469
|
+
>
|
|
470
|
+
<rect width="10" height="10" x="3" y="3" rx="2" />
|
|
471
|
+
</svg>
|
|
472
|
+
);
|
|
473
|
+
};
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
```tsx title="components/assistant-ui/thread-list.tsx"
|
|
477
|
+
import type { FC } from "react";
|
|
478
|
+
import {
|
|
479
|
+
ThreadListItemPrimitive,
|
|
480
|
+
ThreadListPrimitive,
|
|
481
|
+
} from "@assistant-ui/react";
|
|
482
|
+
import { ArchiveIcon, PlusIcon } from "lucide-react";
|
|
483
|
+
|
|
484
|
+
import { Button } from "@/components/ui/button";
|
|
485
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
486
|
+
|
|
487
|
+
export const ThreadList: FC = () => {
|
|
488
|
+
return (
|
|
489
|
+
<ThreadListPrimitive.Root className="aui-root aui-thread-list-root">
|
|
490
|
+
<ThreadListNew />
|
|
491
|
+
<ThreadListItems />
|
|
492
|
+
</ThreadListPrimitive.Root>
|
|
493
|
+
);
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
const ThreadListNew: FC = () => {
|
|
497
|
+
return (
|
|
498
|
+
<ThreadListPrimitive.New asChild>
|
|
499
|
+
<Button className="aui-thread-list-new" variant="ghost">
|
|
500
|
+
<PlusIcon />
|
|
501
|
+
New Thread
|
|
502
|
+
</Button>
|
|
503
|
+
</ThreadListPrimitive.New>
|
|
504
|
+
);
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
const ThreadListItems: FC = () => {
|
|
508
|
+
return <ThreadListPrimitive.Items components={{ ThreadListItem }} />;
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
const ThreadListItem: FC = () => {
|
|
512
|
+
return (
|
|
513
|
+
<ThreadListItemPrimitive.Root className="aui-thread-list-item">
|
|
514
|
+
<ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger">
|
|
515
|
+
<ThreadListItemTitle />
|
|
516
|
+
</ThreadListItemPrimitive.Trigger>
|
|
517
|
+
<ThreadListItemArchive />
|
|
518
|
+
</ThreadListItemPrimitive.Root>
|
|
519
|
+
);
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
const ThreadListItemTitle: FC = () => {
|
|
523
|
+
return (
|
|
524
|
+
<p className="aui-thread-list-item-title">
|
|
525
|
+
<ThreadListItemPrimitive.Title fallback="New Chat" />
|
|
526
|
+
</p>
|
|
527
|
+
);
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
const ThreadListItemArchive: FC = () => {
|
|
531
|
+
return (
|
|
532
|
+
<ThreadListItemPrimitive.Archive asChild>
|
|
533
|
+
<TooltipIconButton
|
|
534
|
+
className="aui-thread-list-item-archive"
|
|
535
|
+
variant="ghost"
|
|
536
|
+
tooltip="Archive thread"
|
|
537
|
+
>
|
|
538
|
+
<ArchiveIcon />
|
|
539
|
+
</TooltipIconButton>
|
|
540
|
+
</ThreadListItemPrimitive.Archive>
|
|
541
|
+
);
|
|
542
|
+
};
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
```tsx title="components/assistant-ui/markdown-text.tsx"
|
|
546
|
+
"use client";
|
|
547
|
+
|
|
548
|
+
import "@assistant-ui/react-markdown/styles/dot.css";
|
|
549
|
+
|
|
550
|
+
import {
|
|
551
|
+
CodeHeaderProps,
|
|
552
|
+
MarkdownTextPrimitive,
|
|
553
|
+
unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
|
|
554
|
+
useIsMarkdownCodeBlock,
|
|
555
|
+
} from "@assistant-ui/react-markdown";
|
|
556
|
+
import remarkGfm from "remark-gfm";
|
|
557
|
+
import { FC, memo, useState } from "react";
|
|
558
|
+
import { CheckIcon, CopyIcon } from "lucide-react";
|
|
559
|
+
|
|
560
|
+
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
561
|
+
import { cn } from "@/lib/utils";
|
|
562
|
+
|
|
563
|
+
const MarkdownTextImpl = () => {
|
|
564
|
+
return (
|
|
565
|
+
<MarkdownTextPrimitive
|
|
566
|
+
remarkPlugins={[remarkGfm]}
|
|
567
|
+
className="aui-md"
|
|
568
|
+
components={defaultComponents}
|
|
569
|
+
/>
|
|
570
|
+
);
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
export const MarkdownText = memo(MarkdownTextImpl);
|
|
574
|
+
|
|
575
|
+
const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
|
|
576
|
+
const { isCopied, copyToClipboard } = useCopyToClipboard();
|
|
577
|
+
const onCopy = () => {
|
|
578
|
+
if (!code || isCopied) return;
|
|
579
|
+
copyToClipboard(code);
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
return (
|
|
583
|
+
<div className="aui-code-header-root">
|
|
584
|
+
<span className="aui-code-header-language">{language}</span>
|
|
585
|
+
<TooltipIconButton tooltip="Copy" onClick={onCopy}>
|
|
586
|
+
{!isCopied && <CopyIcon />}
|
|
587
|
+
{isCopied && <CheckIcon />}
|
|
588
|
+
</TooltipIconButton>
|
|
589
|
+
</div>
|
|
590
|
+
);
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
const useCopyToClipboard = ({
|
|
594
|
+
copiedDuration = 3000,
|
|
595
|
+
}: {
|
|
596
|
+
copiedDuration?: number;
|
|
597
|
+
} = {}) => {
|
|
598
|
+
const [isCopied, setIsCopied] = useState<boolean>(false);
|
|
599
|
+
|
|
600
|
+
const copyToClipboard = (value: string) => {
|
|
601
|
+
if (!value) return;
|
|
602
|
+
|
|
603
|
+
navigator.clipboard.writeText(value).then(() => {
|
|
604
|
+
setIsCopied(true);
|
|
605
|
+
setTimeout(() => setIsCopied(false), copiedDuration);
|
|
606
|
+
});
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
return { isCopied, copyToClipboard };
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
const defaultComponents = memoizeMarkdownComponents({
|
|
613
|
+
h1: ({ className, ...props }) => (
|
|
614
|
+
<h1 className={cn("aui-md-h1", className)} {...props} />
|
|
615
|
+
),
|
|
616
|
+
h2: ({ className, ...props }) => (
|
|
617
|
+
<h2 className={cn("aui-md-h2", className)} {...props} />
|
|
618
|
+
),
|
|
619
|
+
h3: ({ className, ...props }) => (
|
|
620
|
+
<h3 className={cn("aui-md-h3", className)} {...props} />
|
|
621
|
+
),
|
|
622
|
+
h4: ({ className, ...props }) => (
|
|
623
|
+
<h4 className={cn("aui-md-h4", className)} {...props} />
|
|
624
|
+
),
|
|
625
|
+
h5: ({ className, ...props }) => (
|
|
626
|
+
<h5 className={cn("aui-md-h5", className)} {...props} />
|
|
627
|
+
),
|
|
628
|
+
h6: ({ className, ...props }) => (
|
|
629
|
+
<h6 className={cn("aui-md-h6", className)} {...props} />
|
|
630
|
+
),
|
|
631
|
+
p: ({ className, ...props }) => (
|
|
632
|
+
<p className={cn("aui-md-p", className)} {...props} />
|
|
633
|
+
),
|
|
634
|
+
a: ({ className, ...props }) => (
|
|
635
|
+
<a className={cn("aui-md-a", className)} {...props} />
|
|
636
|
+
),
|
|
637
|
+
blockquote: ({ className, ...props }) => (
|
|
638
|
+
<blockquote className={cn("aui-md-blockquote", className)} {...props} />
|
|
639
|
+
),
|
|
640
|
+
ul: ({ className, ...props }) => (
|
|
641
|
+
<ul className={cn("aui-md-ul", className)} {...props} />
|
|
642
|
+
),
|
|
643
|
+
ol: ({ className, ...props }) => (
|
|
644
|
+
<ol className={cn("aui-md-ol", className)} {...props} />
|
|
645
|
+
),
|
|
646
|
+
hr: ({ className, ...props }) => (
|
|
647
|
+
<hr className={cn("aui-md-hr", className)} {...props} />
|
|
648
|
+
),
|
|
649
|
+
table: ({ className, ...props }) => (
|
|
650
|
+
<table className={cn("aui-md-table", className)} {...props} />
|
|
651
|
+
),
|
|
652
|
+
th: ({ className, ...props }) => (
|
|
653
|
+
<th className={cn("aui-md-th", className)} {...props} />
|
|
654
|
+
),
|
|
655
|
+
td: ({ className, ...props }) => (
|
|
656
|
+
<td className={cn("aui-md-td", className)} {...props} />
|
|
657
|
+
),
|
|
658
|
+
tr: ({ className, ...props }) => (
|
|
659
|
+
<tr className={cn("aui-md-tr", className)} {...props} />
|
|
660
|
+
),
|
|
661
|
+
sup: ({ className, ...props }) => (
|
|
662
|
+
<sup className={cn("aui-md-sup", className)} {...props} />
|
|
663
|
+
),
|
|
664
|
+
pre: ({ className, ...props }) => (
|
|
665
|
+
<pre className={cn("aui-md-pre", className)} {...props} />
|
|
666
|
+
),
|
|
667
|
+
code: function Code({ className, ...props }) {
|
|
668
|
+
const isCodeBlock = useIsMarkdownCodeBlock();
|
|
669
|
+
return (
|
|
670
|
+
<code
|
|
671
|
+
className={cn(!isCodeBlock && "aui-md-inline-code", className)}
|
|
672
|
+
{...props}
|
|
673
|
+
/>
|
|
674
|
+
);
|
|
675
|
+
},
|
|
676
|
+
CodeHeader,
|
|
677
|
+
});
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
```tsx title="components/assistant-ui/tooltip-icon-button.tsx"
|
|
681
|
+
"use client";
|
|
682
|
+
|
|
683
|
+
import { ComponentPropsWithoutRef, forwardRef } from "react";
|
|
684
|
+
|
|
685
|
+
import {
|
|
686
|
+
Tooltip,
|
|
687
|
+
TooltipContent,
|
|
688
|
+
TooltipProvider,
|
|
689
|
+
TooltipTrigger,
|
|
690
|
+
} from "@/components/ui/tooltip";
|
|
691
|
+
import { Button } from "@/components/ui/button";
|
|
692
|
+
import { cn } from "@/lib/utils";
|
|
693
|
+
|
|
694
|
+
export type TooltipIconButtonProps = ComponentPropsWithoutRef<typeof Button> & {
|
|
695
|
+
tooltip: string;
|
|
696
|
+
side?: "top" | "bottom" | "left" | "right";
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
export const TooltipIconButton = forwardRef<
|
|
700
|
+
HTMLButtonElement,
|
|
701
|
+
TooltipIconButtonProps
|
|
702
|
+
>(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
|
|
703
|
+
return (
|
|
704
|
+
<TooltipProvider>
|
|
705
|
+
<Tooltip>
|
|
706
|
+
<TooltipTrigger asChild>
|
|
707
|
+
<Button
|
|
708
|
+
variant="ghost"
|
|
709
|
+
size="icon"
|
|
710
|
+
{...rest}
|
|
711
|
+
className={cn("", className)}
|
|
712
|
+
ref={ref}
|
|
713
|
+
>
|
|
714
|
+
{children}
|
|
715
|
+
<span className="aui-sr-only">{tooltip}</span>
|
|
716
|
+
</Button>
|
|
717
|
+
</TooltipTrigger>
|
|
718
|
+
<TooltipContent side={side}>{tooltip}</TooltipContent>
|
|
719
|
+
</Tooltip>
|
|
720
|
+
</TooltipProvider>
|
|
721
|
+
);
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
TooltipIconButton.displayName = "TooltipIconButton";
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
```ts title="lib/utils.ts"
|
|
728
|
+
import { type ClassValue, clsx } from "clsx";
|
|
729
|
+
|
|
730
|
+
export function cn(...inputs: ClassValue[]) {
|
|
731
|
+
return clsx(inputs);
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
</Step>
|
|
736
|
+
|
|
737
|
+
<Step>
|
|
738
|
+
The components above reference CSS class names like `aui-thread-root`, `aui-composer-input`, etc. These are normally replaced by our CLI with Tailwind class names, but in this case you'll use our pre-compiled CSS files without a need for Tailwind:
|
|
739
|
+
|
|
740
|
+
```ts
|
|
741
|
+
import "@assistant-ui/styles/index.css";
|
|
742
|
+
import "@assistant-ui/styles/markdown.css";
|
|
743
|
+
// import "@assistant-ui/styles/modal.css"; // for future reference, only if you use our modal component
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
</Step>
|
|
747
|
+
</Steps>
|
|
748
|
+
|
|
749
|
+
</Tab>
|
|
750
|
+
</Tabs>
|
|
751
|
+
|
|
752
|
+
</Step>
|
|
753
|
+
<Step>
|
|
754
|
+
|
|
755
|
+
### Setup Backend Endpoint
|
|
756
|
+
|
|
757
|
+
Install provider SDK:
|
|
758
|
+
|
|
759
|
+
<Tabs id="provider" items={["OpenAI", "Anthropic", "Azure", "AWS", "Gemini", "GCP", "Groq", "Fireworks", "Cohere", "Ollama", "Chrome AI"]}>
|
|
760
|
+
|
|
761
|
+
```sh title="Terminal" tab="OpenAI"
|
|
762
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/openai
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
```sh title="Terminal" tab="Anthropic"
|
|
766
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/anthropic
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
```sh title="Terminal" tab="Azure"
|
|
770
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/azure
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
```sh title="Terminal" tab="AWS"
|
|
774
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/amazon-bedrock
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
```sh title="Terminal" tab="Gemini"
|
|
778
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/google
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
```sh title="Terminal" tab="GCP"
|
|
782
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/google-vertex
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
```sh title="Terminal" tab="Groq"
|
|
786
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/openai
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
```sh title="Terminal" tab="Fireworks"
|
|
790
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/openai
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
```sh title="Terminal" tab="Cohere"
|
|
794
|
+
npm install ai @assistant-ui/react-ai-sdk @ai-sdk/cohere
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
```sh title="Terminal" tab="Ollama"
|
|
798
|
+
npm install ai @assistant-ui/react-ai-sdk ollama-ai-provider
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
```sh title="Terminal" tab="Chrome AI"
|
|
802
|
+
npm install ai @assistant-ui/react-ai-sdk chrome-ai
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
</Tabs>
|
|
806
|
+
|
|
807
|
+
Add an API endpoint:
|
|
808
|
+
|
|
809
|
+
<Tabs id="provider" items={["OpenAI", "Anthropic", "Azure", "AWS", "Gemini", "GCP", "Groq", "Fireworks", "Cohere", "Ollama", "Chrome AI"]}>
|
|
810
|
+
```ts title="/app/api/chat/route.ts" tab="OpenAI"
|
|
811
|
+
import { openai } from "@ai-sdk/openai";
|
|
812
|
+
import { streamText } from "ai";
|
|
813
|
+
|
|
814
|
+
export const maxDuration = 30;
|
|
815
|
+
|
|
816
|
+
export async function POST(req: Request) {
|
|
817
|
+
const { messages } = await req.json();
|
|
818
|
+
const result = streamText({
|
|
819
|
+
model: openai("gpt-4o-mini"),
|
|
820
|
+
messages,
|
|
821
|
+
});
|
|
822
|
+
return result.toDataStreamResponse();
|
|
823
|
+
}
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
```ts title="/app/api/chat/route.ts" tab="Anthropic"
|
|
827
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
828
|
+
import { streamText } from "ai";
|
|
829
|
+
|
|
830
|
+
export const maxDuration = 30;
|
|
831
|
+
|
|
832
|
+
export async function POST(req: Request) {
|
|
833
|
+
const { messages } = await req.json();
|
|
834
|
+
const result = streamText({
|
|
835
|
+
model: anthropic("claude-3-5-sonnet-20240620"),
|
|
836
|
+
messages,
|
|
837
|
+
});
|
|
838
|
+
return result.toDataStreamResponse();
|
|
839
|
+
}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
```ts title="/app/api/chat/route.ts" tab="Azure"
|
|
843
|
+
import { azure } from "@ai-sdk/azure";
|
|
844
|
+
import { streamText } from "ai";
|
|
845
|
+
|
|
846
|
+
export const maxDuration = 30;
|
|
847
|
+
|
|
848
|
+
export async function POST(req: Request) {
|
|
849
|
+
const { messages } = await req.json();
|
|
850
|
+
const result = streamText({
|
|
851
|
+
model: azure("your-deployment-name"),
|
|
852
|
+
messages,
|
|
853
|
+
});
|
|
854
|
+
return result.toDataStreamResponse();
|
|
855
|
+
}
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
```ts title="/app/api/chat/route.ts" tab="AWS"
|
|
859
|
+
import { bedrock } from "@ai-sdk/amazon-bedrock";
|
|
860
|
+
import { streamText } from "ai";
|
|
861
|
+
|
|
862
|
+
export const maxDuration = 30;
|
|
863
|
+
|
|
864
|
+
export async function POST(req: Request) {
|
|
865
|
+
const { messages } = await req.json();
|
|
866
|
+
const result = streamText({
|
|
867
|
+
model: bedrock("anthropic.claude-3-5-sonnet-20240620-v1:0"),
|
|
868
|
+
messages,
|
|
869
|
+
});
|
|
870
|
+
return result.toDataStreamResponse();
|
|
871
|
+
}
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
```ts title="/app/api/chat/route.ts" tab="Gemini"
|
|
875
|
+
import { google } from "@ai-sdk/google";
|
|
876
|
+
import { streamText } from "ai";
|
|
877
|
+
|
|
878
|
+
export const maxDuration = 30;
|
|
879
|
+
|
|
880
|
+
export async function POST(req: Request) {
|
|
881
|
+
const { messages } = await req.json();
|
|
882
|
+
const result = streamText({
|
|
883
|
+
model: google("gemini-2.0-flash"),
|
|
884
|
+
messages,
|
|
885
|
+
});
|
|
886
|
+
return result.toDataStreamResponse();
|
|
887
|
+
}
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
```ts title="/app/api/chat/route.ts" tab="GCP"
|
|
891
|
+
import { vertex } from "@ai-sdk/google-vertex";
|
|
892
|
+
import { streamText } from "ai";
|
|
893
|
+
|
|
894
|
+
export const maxDuration = 30;
|
|
895
|
+
|
|
896
|
+
export async function POST(req: Request) {
|
|
897
|
+
const { messages } = await req.json();
|
|
898
|
+
const result = streamText({
|
|
899
|
+
model: vertex("gemini-1.5-pro"),
|
|
900
|
+
messages,
|
|
901
|
+
});
|
|
902
|
+
return result.toDataStreamResponse();
|
|
903
|
+
}
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
```ts title="/app/api/chat/route.ts" tab="Groq"
|
|
907
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
908
|
+
import { streamText } from "ai";
|
|
909
|
+
|
|
910
|
+
export const maxDuration = 30;
|
|
911
|
+
|
|
912
|
+
const groq = createOpenAI({
|
|
913
|
+
apiKey: process.env.GROQ_API_KEY ?? "",
|
|
914
|
+
baseURL: "https://api.groq.com/openai/v1",
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
export async function POST(req: Request) {
|
|
918
|
+
const { messages } = await req.json();
|
|
919
|
+
const result = streamText({
|
|
920
|
+
model: groq("llama3-70b-8192"),
|
|
921
|
+
messages,
|
|
922
|
+
});
|
|
923
|
+
return result.toDataStreamResponse();
|
|
924
|
+
}
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
```ts title="/app/api/chat/route.ts" tab="Fireworks"
|
|
928
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
929
|
+
import { streamText } from "ai";
|
|
930
|
+
|
|
931
|
+
export const maxDuration = 30;
|
|
932
|
+
|
|
933
|
+
const fireworks = createOpenAI({
|
|
934
|
+
apiKey: process.env.FIREWORKS_API_KEY ?? "",
|
|
935
|
+
baseURL: "https://api.fireworks.ai/inference/v1",
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
export async function POST(req: Request) {
|
|
939
|
+
const { messages } = await req.json();
|
|
940
|
+
const result = streamText({
|
|
941
|
+
model: fireworks("accounts/fireworks/models/firefunction-v2"),
|
|
942
|
+
messages,
|
|
943
|
+
});
|
|
944
|
+
return result.toDataStreamResponse();
|
|
945
|
+
}
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
```ts title="/app/api/chat/route.ts" tab="Cohere"
|
|
949
|
+
import { cohere } from "@ai-sdk/cohere";
|
|
950
|
+
import { streamText } from "ai";
|
|
951
|
+
|
|
952
|
+
export const maxDuration = 30;
|
|
953
|
+
|
|
954
|
+
export async function POST(req: Request) {
|
|
955
|
+
const { messages } = await req.json();
|
|
956
|
+
const result = streamText({
|
|
957
|
+
model: cohere("command-r-plus"),
|
|
958
|
+
messages,
|
|
959
|
+
});
|
|
960
|
+
return result.toDataStreamResponse();
|
|
961
|
+
}
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
```ts title="/app/api/chat/route.ts" tab="Ollama"
|
|
965
|
+
import { ollama } from "ollama-ai-provider";
|
|
966
|
+
import { streamText } from "ai";
|
|
967
|
+
|
|
968
|
+
export const maxDuration = 30;
|
|
969
|
+
|
|
970
|
+
export async function POST(req: Request) {
|
|
971
|
+
const { messages } = await req.json();
|
|
972
|
+
const result = streamText({
|
|
973
|
+
model: ollama("llama3"),
|
|
974
|
+
messages,
|
|
975
|
+
});
|
|
976
|
+
return result.toDataStreamResponse();
|
|
977
|
+
}
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
```ts title="/app/api/chat/route.ts" tab="Chrome AI"
|
|
981
|
+
import { chromeai } from "chrome-ai";
|
|
982
|
+
import { streamText } from "ai";
|
|
983
|
+
|
|
984
|
+
export const maxDuration = 30;
|
|
985
|
+
|
|
986
|
+
export async function POST(req: Request) {
|
|
987
|
+
const { messages } = await req.json();
|
|
988
|
+
const result = streamText({
|
|
989
|
+
model: chromeai(),
|
|
990
|
+
messages,
|
|
991
|
+
});
|
|
992
|
+
return result.toDataStreamResponse();
|
|
993
|
+
}
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
</Tabs>
|
|
997
|
+
|
|
998
|
+
Define environment variables:
|
|
999
|
+
|
|
1000
|
+
<Tabs id="provider" items={["OpenAI", "Anthropic", "Azure", "AWS", "Gemini", "GCP", "Groq", "Fireworks", "Cohere", "Ollama", "Chrome AI"]}>
|
|
1001
|
+
|
|
1002
|
+
```sh title="/.env.local" tab="OpenAI"
|
|
1003
|
+
OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
```sh title="/.env.local" tab="Anthropic"
|
|
1007
|
+
ANTHROPIC_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
```sh title="/.env.local" tab="Azure"
|
|
1011
|
+
AZURE_RESOURCE_NAME="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1012
|
+
AZURE_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
```sh title="/.env.local" tab="AWS"
|
|
1016
|
+
AWS_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1017
|
+
AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1018
|
+
AWS_REGION="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
```sh title="/.env.local" tab="Gemini"
|
|
1022
|
+
GOOGLE_GENERATIVE_AI_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
```sh title="/.env.local" tab="GCP"
|
|
1026
|
+
GOOGLE_VERTEX_PROJECT="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1027
|
+
GOOGLE_VERTEX_LOCATION="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1028
|
+
GOOGLE_APPLICATION_CREDENTIALS="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
```sh title="/.env.local" tab="Groq"
|
|
1032
|
+
GROQ_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
```sh title="/.env.local" tab="Fireworks"
|
|
1036
|
+
FIREWORKS_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
```sh title="/.env.local" tab="Cohere"
|
|
1040
|
+
COHERE_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
```sh tab="Ollama"
|
|
1044
|
+
<none>
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
```sh tab="Chrome AI"
|
|
1048
|
+
<none>
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
</Tabs>
|
|
1052
|
+
|
|
1053
|
+
If you aren't using Next.js, you can also deploy this endpoint to Cloudflare Workers, or any other serverless platform.
|
|
1054
|
+
|
|
1055
|
+
</Step>
|
|
1056
|
+
|
|
1057
|
+
<Step>
|
|
1058
|
+
|
|
1059
|
+
### Use it in your app
|
|
1060
|
+
|
|
1061
|
+
<Tabs items={["Thread", "AssistantModal"]}>
|
|
1062
|
+
|
|
1063
|
+
```tsx title="/app/page.tsx" tab="Thread"
|
|
1064
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
1065
|
+
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
1066
|
+
import { ThreadList } from "@/components/assistant-ui/thread-list";
|
|
1067
|
+
import { Thread } from "@/components/assistant-ui/thread";
|
|
1068
|
+
|
|
1069
|
+
const MyApp = () => {
|
|
1070
|
+
const runtime = useChatRuntime({
|
|
1071
|
+
api: "/api/chat",
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
return (
|
|
1075
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
1076
|
+
<div className="grid h-dvh grid-cols-[200px_1fr] gap-x-2 px-4 py-4">
|
|
1077
|
+
<ThreadList />
|
|
1078
|
+
<Thread />
|
|
1079
|
+
</div>
|
|
1080
|
+
</AssistantRuntimeProvider>
|
|
1081
|
+
);
|
|
1082
|
+
};
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
```tsx title="/app/page.tsx" tab="AssistantModal"
|
|
1086
|
+
// run `npx shadcn@latest add "https://r.assistant-ui.com/assistant-modal"`
|
|
1087
|
+
|
|
1088
|
+
import { AssistantRuntimeProvider } from "@assistant-ui/react";
|
|
1089
|
+
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
1090
|
+
import { AssistantModal } from "@/components/assistant-ui/assistant-modal";
|
|
1091
|
+
|
|
1092
|
+
const MyApp = () => {
|
|
1093
|
+
const runtime = useChatRuntime({
|
|
1094
|
+
api: "/api/chat",
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
return (
|
|
1098
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
1099
|
+
<AssistantModal />
|
|
1100
|
+
</AssistantRuntimeProvider>
|
|
1101
|
+
);
|
|
1102
|
+
};
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
</Tabs>
|
|
1106
|
+
|
|
1107
|
+
</Step>
|
|
1108
|
+
</Steps>
|
|
1109
|
+
|
|
1110
|
+
## What's Next?
|
|
1111
|
+
|
|
1112
|
+
<Cards>
|
|
1113
|
+
<Card
|
|
1114
|
+
title="Pick a Runtime"
|
|
1115
|
+
description="Choose the right runtime for your needs"
|
|
1116
|
+
href="/docs/runtimes/pick-a-runtime"
|
|
1117
|
+
/>
|
|
1118
|
+
<Card
|
|
1119
|
+
title="Generative UI"
|
|
1120
|
+
description="Create rich UI components for tool executions"
|
|
1121
|
+
href="/docs/guides/ToolUI"
|
|
1122
|
+
/>
|
|
1123
|
+
<Card
|
|
1124
|
+
title="Add Persistence"
|
|
1125
|
+
description="Save and restore chat conversations"
|
|
1126
|
+
href="/docs/cloud/overview"
|
|
1127
|
+
/>
|
|
1128
|
+
<Card
|
|
1129
|
+
title="Examples"
|
|
1130
|
+
description="Explore full implementations and demos"
|
|
1131
|
+
href="https://github.com/assistant-ui/assistant-ui/tree/main/examples"
|
|
1132
|
+
/>
|
|
1133
|
+
</Cards>
|