@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.
Files changed (109) hide show
  1. package/.docs/organized/code-examples/local-ollama.md +1135 -0
  2. package/.docs/organized/code-examples/search-agent-for-e-commerce.md +1721 -0
  3. package/.docs/organized/code-examples/with-ai-sdk.md +1081 -0
  4. package/.docs/organized/code-examples/with-cloud.md +1164 -0
  5. package/.docs/organized/code-examples/with-external-store.md +1064 -0
  6. package/.docs/organized/code-examples/with-ffmpeg.md +1305 -0
  7. package/.docs/organized/code-examples/with-langgraph.md +1819 -0
  8. package/.docs/organized/code-examples/with-openai-assistants.md +1175 -0
  9. package/.docs/organized/code-examples/with-react-hook-form.md +1727 -0
  10. package/.docs/organized/code-examples/with-vercel-ai-rsc.md +1157 -0
  11. package/.docs/raw/blog/2024-07-29-hello/index.mdx +65 -0
  12. package/.docs/raw/blog/2024-09-11/index.mdx +10 -0
  13. package/.docs/raw/blog/2024-12-15/index.mdx +10 -0
  14. package/.docs/raw/blog/2025-01-31-changelog/index.mdx +129 -0
  15. package/.docs/raw/docs/about-assistantui.mdx +44 -0
  16. package/.docs/raw/docs/api-reference/context-providers/AssistantRuntimeProvider.mdx +30 -0
  17. package/.docs/raw/docs/api-reference/context-providers/TextContentPartProvider.mdx +26 -0
  18. package/.docs/raw/docs/api-reference/integrations/react-hook-form.mdx +103 -0
  19. package/.docs/raw/docs/api-reference/integrations/vercel-ai-sdk.mdx +145 -0
  20. package/.docs/raw/docs/api-reference/overview.mdx +583 -0
  21. package/.docs/raw/docs/api-reference/primitives/ActionBar.mdx +264 -0
  22. package/.docs/raw/docs/api-reference/primitives/AssistantModal.mdx +129 -0
  23. package/.docs/raw/docs/api-reference/primitives/Attachment.mdx +96 -0
  24. package/.docs/raw/docs/api-reference/primitives/BranchPicker.mdx +87 -0
  25. package/.docs/raw/docs/api-reference/primitives/Composer.mdx +204 -0
  26. package/.docs/raw/docs/api-reference/primitives/ContentPart.mdx +173 -0
  27. package/.docs/raw/docs/api-reference/primitives/Error.mdx +70 -0
  28. package/.docs/raw/docs/api-reference/primitives/Message.mdx +181 -0
  29. package/.docs/raw/docs/api-reference/primitives/Thread.mdx +197 -0
  30. package/.docs/raw/docs/api-reference/primitives/composition.mdx +21 -0
  31. package/.docs/raw/docs/api-reference/runtimes/AssistantRuntime.mdx +33 -0
  32. package/.docs/raw/docs/api-reference/runtimes/AttachmentRuntime.mdx +46 -0
  33. package/.docs/raw/docs/api-reference/runtimes/ComposerRuntime.mdx +69 -0
  34. package/.docs/raw/docs/api-reference/runtimes/ContentPartRuntime.mdx +22 -0
  35. package/.docs/raw/docs/api-reference/runtimes/MessageRuntime.mdx +49 -0
  36. package/.docs/raw/docs/api-reference/runtimes/ThreadListItemRuntime.mdx +32 -0
  37. package/.docs/raw/docs/api-reference/runtimes/ThreadListRuntime.mdx +31 -0
  38. package/.docs/raw/docs/api-reference/runtimes/ThreadRuntime.mdx +48 -0
  39. package/.docs/raw/docs/architecture.mdx +92 -0
  40. package/.docs/raw/docs/cloud/authorization.mdx +152 -0
  41. package/.docs/raw/docs/cloud/overview.mdx +55 -0
  42. package/.docs/raw/docs/cloud/persistence/ai-sdk.mdx +54 -0
  43. package/.docs/raw/docs/cloud/persistence/langgraph.mdx +123 -0
  44. package/.docs/raw/docs/concepts/architecture.mdx +19 -0
  45. package/.docs/raw/docs/concepts/runtime-layer.mdx +163 -0
  46. package/.docs/raw/docs/concepts/why.mdx +9 -0
  47. package/.docs/raw/docs/copilots/make-assistant-readable.mdx +71 -0
  48. package/.docs/raw/docs/copilots/make-assistant-tool-ui.mdx +76 -0
  49. package/.docs/raw/docs/copilots/make-assistant-tool.mdx +117 -0
  50. package/.docs/raw/docs/copilots/model-context.mdx +135 -0
  51. package/.docs/raw/docs/copilots/motivation.mdx +191 -0
  52. package/.docs/raw/docs/copilots/use-assistant-instructions.mdx +62 -0
  53. package/.docs/raw/docs/getting-started.mdx +1133 -0
  54. package/.docs/raw/docs/guides/Attachments.mdx +640 -0
  55. package/.docs/raw/docs/guides/Branching.mdx +59 -0
  56. package/.docs/raw/docs/guides/Editing.mdx +56 -0
  57. package/.docs/raw/docs/guides/Speech.mdx +43 -0
  58. package/.docs/raw/docs/guides/ToolUI.mdx +663 -0
  59. package/.docs/raw/docs/guides/Tools.mdx +496 -0
  60. package/.docs/raw/docs/index.mdx +7 -0
  61. package/.docs/raw/docs/legacy/styled/AssistantModal.mdx +85 -0
  62. package/.docs/raw/docs/legacy/styled/Decomposition.mdx +633 -0
  63. package/.docs/raw/docs/legacy/styled/Markdown.mdx +86 -0
  64. package/.docs/raw/docs/legacy/styled/Scrollbar.mdx +71 -0
  65. package/.docs/raw/docs/legacy/styled/Thread.mdx +84 -0
  66. package/.docs/raw/docs/legacy/styled/ThreadWidth.mdx +21 -0
  67. package/.docs/raw/docs/mcp-docs-server.mdx +324 -0
  68. package/.docs/raw/docs/migrations/deprecation-policy.mdx +41 -0
  69. package/.docs/raw/docs/migrations/v0-7.mdx +188 -0
  70. package/.docs/raw/docs/migrations/v0-8.mdx +160 -0
  71. package/.docs/raw/docs/migrations/v0-9.mdx +75 -0
  72. package/.docs/raw/docs/react-compatibility.mdx +208 -0
  73. package/.docs/raw/docs/runtimes/ai-sdk/rsc.mdx +226 -0
  74. package/.docs/raw/docs/runtimes/ai-sdk/use-assistant-hook.mdx +195 -0
  75. package/.docs/raw/docs/runtimes/ai-sdk/use-chat-hook.mdx +138 -0
  76. package/.docs/raw/docs/runtimes/ai-sdk/use-chat.mdx +136 -0
  77. package/.docs/raw/docs/runtimes/custom/external-store.mdx +1624 -0
  78. package/.docs/raw/docs/runtimes/custom/local.mdx +1185 -0
  79. package/.docs/raw/docs/runtimes/helicone.mdx +60 -0
  80. package/.docs/raw/docs/runtimes/langgraph/index.mdx +320 -0
  81. package/.docs/raw/docs/runtimes/langgraph/tutorial/index.mdx +11 -0
  82. package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +28 -0
  83. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +120 -0
  84. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +336 -0
  85. package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +385 -0
  86. package/.docs/raw/docs/runtimes/langserve.mdx +126 -0
  87. package/.docs/raw/docs/runtimes/mastra/full-stack-integration.mdx +218 -0
  88. package/.docs/raw/docs/runtimes/mastra/overview.mdx +17 -0
  89. package/.docs/raw/docs/runtimes/mastra/separate-server-integration.mdx +196 -0
  90. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +222 -0
  91. package/.docs/raw/docs/ui/AssistantModal.mdx +46 -0
  92. package/.docs/raw/docs/ui/AssistantSidebar.mdx +42 -0
  93. package/.docs/raw/docs/ui/Attachment.mdx +82 -0
  94. package/.docs/raw/docs/ui/Markdown.mdx +72 -0
  95. package/.docs/raw/docs/ui/Mermaid.mdx +79 -0
  96. package/.docs/raw/docs/ui/Scrollbar.mdx +59 -0
  97. package/.docs/raw/docs/ui/SyntaxHighlighting.mdx +253 -0
  98. package/.docs/raw/docs/ui/Thread.mdx +47 -0
  99. package/.docs/raw/docs/ui/ThreadList.mdx +49 -0
  100. package/.docs/raw/docs/ui/ToolFallback.mdx +64 -0
  101. package/.docs/raw/docs/ui/primitives/Thread.mdx +197 -0
  102. package/LICENSE +21 -0
  103. package/README.md +128 -0
  104. package/dist/chunk-C7O7EFKU.js +38 -0
  105. package/dist/chunk-CZCDQ3YH.js +420 -0
  106. package/dist/index.js +1 -0
  107. package/dist/prepare-docs/prepare.js +199 -0
  108. package/dist/stdio.js +8 -0
  109. package/package.json +43 -0
@@ -0,0 +1,1135 @@
1
+ # Example: local-ollama
2
+
3
+ ## app/api/chat/route.ts
4
+
5
+ ```typescript
6
+ import { ollama } from "ollama-ai-provider";
7
+ import { frontendTools } from "@assistant-ui/react-ai-sdk";
8
+ import { streamText } from "ai";
9
+
10
+ export const runtime = "edge";
11
+ export const maxDuration = 30;
12
+
13
+ export async function POST(req: Request) {
14
+ const { messages, system, tools } = await req.json();
15
+
16
+ const result = streamText({
17
+ model: ollama("llama3.1"),
18
+ messages,
19
+ toolCallStreaming: true,
20
+ system,
21
+ tools: {
22
+ ...frontendTools(tools),
23
+ // add backend tools here
24
+ },
25
+ });
26
+
27
+ return result.toDataStreamResponse();
28
+ }
29
+
30
+ ```
31
+
32
+ ## app/assistant.tsx
33
+
34
+ ```tsx
35
+ "use client";
36
+
37
+ import { AssistantRuntimeProvider } from "@assistant-ui/react";
38
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
39
+ import { Thread } from "@/components/assistant-ui/thread";
40
+
41
+ export const Assistant = () => {
42
+ const runtime = useChatRuntime({
43
+ api: "/api/chat",
44
+ });
45
+
46
+ return (
47
+ <AssistantRuntimeProvider runtime={runtime}>
48
+ <div className="grid h-dvh grid-cols-[200px_1fr] gap-x-2 px-4 py-4">
49
+ <Thread />
50
+ </div>
51
+ </AssistantRuntimeProvider>
52
+ );
53
+ };
54
+
55
+ ```
56
+
57
+ ## app/globals.css
58
+
59
+ ```css
60
+ @import "tailwindcss";
61
+ @import "tw-animate-css";
62
+
63
+ @custom-variant dark (&:is(.dark *));
64
+
65
+ @theme inline {
66
+ --color-background: var(--background);
67
+ --color-foreground: var(--foreground);
68
+ --font-sans: var(--font-geist-sans);
69
+ --font-mono: var(--font-geist-mono);
70
+ --color-sidebar-ring: var(--sidebar-ring);
71
+ --color-sidebar-border: var(--sidebar-border);
72
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
73
+ --color-sidebar-accent: var(--sidebar-accent);
74
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
75
+ --color-sidebar-primary: var(--sidebar-primary);
76
+ --color-sidebar-foreground: var(--sidebar-foreground);
77
+ --color-sidebar: var(--sidebar);
78
+ --color-chart-5: var(--chart-5);
79
+ --color-chart-4: var(--chart-4);
80
+ --color-chart-3: var(--chart-3);
81
+ --color-chart-2: var(--chart-2);
82
+ --color-chart-1: var(--chart-1);
83
+ --color-ring: var(--ring);
84
+ --color-input: var(--input);
85
+ --color-border: var(--border);
86
+ --color-destructive: var(--destructive);
87
+ --color-accent-foreground: var(--accent-foreground);
88
+ --color-accent: var(--accent);
89
+ --color-muted-foreground: var(--muted-foreground);
90
+ --color-muted: var(--muted);
91
+ --color-secondary-foreground: var(--secondary-foreground);
92
+ --color-secondary: var(--secondary);
93
+ --color-primary-foreground: var(--primary-foreground);
94
+ --color-primary: var(--primary);
95
+ --color-popover-foreground: var(--popover-foreground);
96
+ --color-popover: var(--popover);
97
+ --color-card-foreground: var(--card-foreground);
98
+ --color-card: var(--card);
99
+ --radius-sm: calc(var(--radius) - 4px);
100
+ --radius-md: calc(var(--radius) - 2px);
101
+ --radius-lg: var(--radius);
102
+ --radius-xl: calc(var(--radius) + 4px);
103
+ }
104
+
105
+ :root {
106
+ --radius: 0.625rem;
107
+ --background: oklch(1 0 0);
108
+ --foreground: oklch(0.141 0.005 285.823);
109
+ --card: oklch(1 0 0);
110
+ --card-foreground: oklch(0.141 0.005 285.823);
111
+ --popover: oklch(1 0 0);
112
+ --popover-foreground: oklch(0.141 0.005 285.823);
113
+ --primary: oklch(0.21 0.006 285.885);
114
+ --primary-foreground: oklch(0.985 0 0);
115
+ --secondary: oklch(0.967 0.001 286.375);
116
+ --secondary-foreground: oklch(0.21 0.006 285.885);
117
+ --muted: oklch(0.967 0.001 286.375);
118
+ --muted-foreground: oklch(0.552 0.016 285.938);
119
+ --accent: oklch(0.967 0.001 286.375);
120
+ --accent-foreground: oklch(0.21 0.006 285.885);
121
+ --destructive: oklch(0.577 0.245 27.325);
122
+ --border: oklch(0.92 0.004 286.32);
123
+ --input: oklch(0.92 0.004 286.32);
124
+ --ring: oklch(0.705 0.015 286.067);
125
+ --chart-1: oklch(0.646 0.222 41.116);
126
+ --chart-2: oklch(0.6 0.118 184.704);
127
+ --chart-3: oklch(0.398 0.07 227.392);
128
+ --chart-4: oklch(0.828 0.189 84.429);
129
+ --chart-5: oklch(0.769 0.188 70.08);
130
+ --sidebar: oklch(0.985 0 0);
131
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
132
+ --sidebar-primary: oklch(0.21 0.006 285.885);
133
+ --sidebar-primary-foreground: oklch(0.985 0 0);
134
+ --sidebar-accent: oklch(0.967 0.001 286.375);
135
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
136
+ --sidebar-border: oklch(0.92 0.004 286.32);
137
+ --sidebar-ring: oklch(0.705 0.015 286.067);
138
+ }
139
+
140
+ .dark {
141
+ --background: oklch(0.141 0.005 285.823);
142
+ --foreground: oklch(0.985 0 0);
143
+ --card: oklch(0.21 0.006 285.885);
144
+ --card-foreground: oklch(0.985 0 0);
145
+ --popover: oklch(0.21 0.006 285.885);
146
+ --popover-foreground: oklch(0.985 0 0);
147
+ --primary: oklch(0.92 0.004 286.32);
148
+ --primary-foreground: oklch(0.21 0.006 285.885);
149
+ --secondary: oklch(0.274 0.006 286.033);
150
+ --secondary-foreground: oklch(0.985 0 0);
151
+ --muted: oklch(0.274 0.006 286.033);
152
+ --muted-foreground: oklch(0.705 0.015 286.067);
153
+ --accent: oklch(0.274 0.006 286.033);
154
+ --accent-foreground: oklch(0.985 0 0);
155
+ --destructive: oklch(0.704 0.191 22.216);
156
+ --border: oklch(1 0 0 / 10%);
157
+ --input: oklch(1 0 0 / 15%);
158
+ --ring: oklch(0.552 0.016 285.938);
159
+ --chart-1: oklch(0.488 0.243 264.376);
160
+ --chart-2: oklch(0.696 0.17 162.48);
161
+ --chart-3: oklch(0.769 0.188 70.08);
162
+ --chart-4: oklch(0.627 0.265 303.9);
163
+ --chart-5: oklch(0.645 0.246 16.439);
164
+ --sidebar: oklch(0.21 0.006 285.885);
165
+ --sidebar-foreground: oklch(0.985 0 0);
166
+ --sidebar-primary: oklch(0.488 0.243 264.376);
167
+ --sidebar-primary-foreground: oklch(0.985 0 0);
168
+ --sidebar-accent: oklch(0.274 0.006 286.033);
169
+ --sidebar-accent-foreground: oklch(0.985 0 0);
170
+ --sidebar-border: oklch(1 0 0 / 10%);
171
+ --sidebar-ring: oklch(0.552 0.016 285.938);
172
+ }
173
+
174
+ @layer base {
175
+ * {
176
+ @apply border-border outline-ring/50;
177
+ }
178
+ body {
179
+ @apply bg-background text-foreground;
180
+ }
181
+ }
182
+
183
+ ```
184
+
185
+ ## app/layout.tsx
186
+
187
+ ```tsx
188
+ import type { Metadata } from "next";
189
+ import { Geist, Geist_Mono } from "next/font/google";
190
+ import "./globals.css";
191
+
192
+ const geistSans = Geist({
193
+ variable: "--font-geist-sans",
194
+ subsets: ["latin"],
195
+ });
196
+
197
+ const geistMono = Geist_Mono({
198
+ variable: "--font-geist-mono",
199
+ subsets: ["latin"],
200
+ });
201
+
202
+ export const metadata: Metadata = {
203
+ title: "assistant-ui App",
204
+ description: "Generated by create-assistant-ui",
205
+ };
206
+
207
+ export default function RootLayout({
208
+ children,
209
+ }: Readonly<{
210
+ children: React.ReactNode;
211
+ }>) {
212
+ return (
213
+ <html lang="en">
214
+ <body
215
+ className={`${geistSans.variable} ${geistMono.variable} antialiased`}
216
+ >
217
+ {children}
218
+ </body>
219
+ </html>
220
+ );
221
+ }
222
+
223
+ ```
224
+
225
+ ## app/page.tsx
226
+
227
+ ```tsx
228
+ import { Assistant } from "./assistant";
229
+
230
+ export default function Home() {
231
+ return (
232
+ <main className="h-dvh">
233
+ <Assistant />
234
+ </main>
235
+ );
236
+ }
237
+
238
+ ```
239
+
240
+ ## components.json
241
+
242
+ ```json
243
+ {
244
+ "$schema": "https://ui.shadcn.com/schema.json",
245
+ "style": "new-york",
246
+ "rsc": true,
247
+ "tsx": true,
248
+ "tailwind": {
249
+ "config": "",
250
+ "css": "app/globals.css",
251
+ "baseColor": "zinc",
252
+ "cssVariables": true,
253
+ "prefix": ""
254
+ },
255
+ "aliases": {
256
+ "components": "@/components",
257
+ "utils": "@/lib/utils",
258
+ "ui": "@/components/ui",
259
+ "lib": "@/lib",
260
+ "hooks": "@/hooks"
261
+ },
262
+ "iconLibrary": "lucide"
263
+ }
264
+
265
+ ```
266
+
267
+ ## components/assistant-ui/markdown-text.tsx
268
+
269
+ ```tsx
270
+ "use client";
271
+
272
+ import "@assistant-ui/react-markdown/styles/dot.css";
273
+
274
+ import {
275
+ CodeHeaderProps,
276
+ MarkdownTextPrimitive,
277
+ unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
278
+ useIsMarkdownCodeBlock,
279
+ } from "@assistant-ui/react-markdown";
280
+ import remarkGfm from "remark-gfm";
281
+ import { FC, memo, useState } from "react";
282
+ import { CheckIcon, CopyIcon } from "lucide-react";
283
+
284
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
285
+ import { cn } from "@/lib/utils";
286
+
287
+ const MarkdownTextImpl = () => {
288
+ return (
289
+ <MarkdownTextPrimitive
290
+ remarkPlugins={[remarkGfm]}
291
+ className="aui-md"
292
+ components={defaultComponents}
293
+ />
294
+ );
295
+ };
296
+
297
+ export const MarkdownText = memo(MarkdownTextImpl);
298
+
299
+ const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
300
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
301
+ const onCopy = () => {
302
+ if (!code || isCopied) return;
303
+ copyToClipboard(code);
304
+ };
305
+
306
+ return (
307
+ <div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
308
+ <span className="lowercase [&>span]:text-xs">{language}</span>
309
+ <TooltipIconButton tooltip="Copy" onClick={onCopy}>
310
+ {!isCopied && <CopyIcon />}
311
+ {isCopied && <CheckIcon />}
312
+ </TooltipIconButton>
313
+ </div>
314
+ );
315
+ };
316
+
317
+ const useCopyToClipboard = ({
318
+ copiedDuration = 3000,
319
+ }: {
320
+ copiedDuration?: number;
321
+ } = {}) => {
322
+ const [isCopied, setIsCopied] = useState<boolean>(false);
323
+
324
+ const copyToClipboard = (value: string) => {
325
+ if (!value) return;
326
+
327
+ navigator.clipboard.writeText(value).then(() => {
328
+ setIsCopied(true);
329
+ setTimeout(() => setIsCopied(false), copiedDuration);
330
+ });
331
+ };
332
+
333
+ return { isCopied, copyToClipboard };
334
+ };
335
+
336
+ const defaultComponents = memoizeMarkdownComponents({
337
+ h1: ({ className, ...props }) => (
338
+ <h1
339
+ className={cn(
340
+ "mb-8 scroll-m-20 text-4xl font-extrabold tracking-tight last:mb-0",
341
+ className,
342
+ )}
343
+ {...props}
344
+ />
345
+ ),
346
+ h2: ({ className, ...props }) => (
347
+ <h2
348
+ className={cn(
349
+ "mb-4 mt-8 scroll-m-20 text-3xl font-semibold tracking-tight first:mt-0 last:mb-0",
350
+ className,
351
+ )}
352
+ {...props}
353
+ />
354
+ ),
355
+ h3: ({ className, ...props }) => (
356
+ <h3
357
+ className={cn(
358
+ "mb-4 mt-6 scroll-m-20 text-2xl font-semibold tracking-tight first:mt-0 last:mb-0",
359
+ className,
360
+ )}
361
+ {...props}
362
+ />
363
+ ),
364
+ h4: ({ className, ...props }) => (
365
+ <h4
366
+ className={cn(
367
+ "mb-4 mt-6 scroll-m-20 text-xl font-semibold tracking-tight first:mt-0 last:mb-0",
368
+ className,
369
+ )}
370
+ {...props}
371
+ />
372
+ ),
373
+ h5: ({ className, ...props }) => (
374
+ <h5
375
+ className={cn(
376
+ "my-4 text-lg font-semibold first:mt-0 last:mb-0",
377
+ className,
378
+ )}
379
+ {...props}
380
+ />
381
+ ),
382
+ h6: ({ className, ...props }) => (
383
+ <h6
384
+ className={cn("my-4 font-semibold first:mt-0 last:mb-0", className)}
385
+ {...props}
386
+ />
387
+ ),
388
+ p: ({ className, ...props }) => (
389
+ <p
390
+ className={cn("mb-5 mt-5 leading-7 first:mt-0 last:mb-0", className)}
391
+ {...props}
392
+ />
393
+ ),
394
+ a: ({ className, ...props }) => (
395
+ <a
396
+ className={cn(
397
+ "text-primary font-medium underline underline-offset-4",
398
+ className,
399
+ )}
400
+ {...props}
401
+ />
402
+ ),
403
+ blockquote: ({ className, ...props }) => (
404
+ <blockquote
405
+ className={cn("border-l-2 pl-6 italic", className)}
406
+ {...props}
407
+ />
408
+ ),
409
+ ul: ({ className, ...props }) => (
410
+ <ul
411
+ className={cn("my-5 ml-6 list-disc [&>li]:mt-2", className)}
412
+ {...props}
413
+ />
414
+ ),
415
+ ol: ({ className, ...props }) => (
416
+ <ol
417
+ className={cn("my-5 ml-6 list-decimal [&>li]:mt-2", className)}
418
+ {...props}
419
+ />
420
+ ),
421
+ hr: ({ className, ...props }) => (
422
+ <hr className={cn("my-5 border-b", className)} {...props} />
423
+ ),
424
+ table: ({ className, ...props }) => (
425
+ <table
426
+ className={cn(
427
+ "my-5 w-full border-separate border-spacing-0 overflow-y-auto",
428
+ className,
429
+ )}
430
+ {...props}
431
+ />
432
+ ),
433
+ th: ({ className, ...props }) => (
434
+ <th
435
+ className={cn(
436
+ "bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [&[align=center]]:text-center [&[align=right]]:text-right",
437
+ className,
438
+ )}
439
+ {...props}
440
+ />
441
+ ),
442
+ td: ({ className, ...props }) => (
443
+ <td
444
+ className={cn(
445
+ "border-b border-l px-4 py-2 text-left last:border-r [&[align=center]]:text-center [&[align=right]]:text-right",
446
+ className,
447
+ )}
448
+ {...props}
449
+ />
450
+ ),
451
+ tr: ({ className, ...props }) => (
452
+ <tr
453
+ className={cn(
454
+ "m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg",
455
+ className,
456
+ )}
457
+ {...props}
458
+ />
459
+ ),
460
+ sup: ({ className, ...props }) => (
461
+ <sup
462
+ className={cn("[&>a]:text-xs [&>a]:no-underline", className)}
463
+ {...props}
464
+ />
465
+ ),
466
+ pre: ({ className, ...props }) => (
467
+ <pre
468
+ className={cn(
469
+ "overflow-x-auto rounded-b-lg bg-black p-4 text-white",
470
+ className,
471
+ )}
472
+ {...props}
473
+ />
474
+ ),
475
+ code: function Code({ className, ...props }) {
476
+ const isCodeBlock = useIsMarkdownCodeBlock();
477
+ return (
478
+ <code
479
+ className={cn(
480
+ !isCodeBlock && "bg-muted rounded border font-semibold",
481
+ className,
482
+ )}
483
+ {...props}
484
+ />
485
+ );
486
+ },
487
+ CodeHeader,
488
+ });
489
+
490
+ ```
491
+
492
+ ## components/assistant-ui/thread.tsx
493
+
494
+ ```tsx
495
+ import {
496
+ ActionBarPrimitive,
497
+ BranchPickerPrimitive,
498
+ ComposerPrimitive,
499
+ MessagePrimitive,
500
+ ThreadPrimitive,
501
+ } from "@assistant-ui/react";
502
+ import type { FC } from "react";
503
+ import {
504
+ ArrowDownIcon,
505
+ CheckIcon,
506
+ ChevronLeftIcon,
507
+ ChevronRightIcon,
508
+ CopyIcon,
509
+ PencilIcon,
510
+ RefreshCwIcon,
511
+ SendHorizontalIcon,
512
+ } from "lucide-react";
513
+ import { cn } from "@/lib/utils";
514
+
515
+ import { Button } from "@/components/ui/button";
516
+ import { MarkdownText } from "@/components/assistant-ui/markdown-text";
517
+ import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
518
+
519
+ export const Thread: FC = () => {
520
+ return (
521
+ <ThreadPrimitive.Root
522
+ className="bg-background box-border flex h-full flex-col overflow-hidden"
523
+ style={{
524
+ ["--thread-max-width" as string]: "42rem",
525
+ }}
526
+ >
527
+ <ThreadPrimitive.Viewport className="flex h-full flex-col items-center overflow-y-scroll scroll-smooth bg-inherit px-4 pt-8">
528
+ <ThreadWelcome />
529
+
530
+ <ThreadPrimitive.Messages
531
+ components={{
532
+ UserMessage: UserMessage,
533
+ EditComposer: EditComposer,
534
+ AssistantMessage: AssistantMessage,
535
+ }}
536
+ />
537
+
538
+ <ThreadPrimitive.If empty={false}>
539
+ <div className="min-h-8 flex-grow" />
540
+ </ThreadPrimitive.If>
541
+
542
+ <div className="sticky bottom-0 mt-3 flex w-full max-w-[var(--thread-max-width)] flex-col items-center justify-end rounded-t-lg bg-inherit pb-4">
543
+ <ThreadScrollToBottom />
544
+ <Composer />
545
+ </div>
546
+ </ThreadPrimitive.Viewport>
547
+ </ThreadPrimitive.Root>
548
+ );
549
+ };
550
+
551
+ const ThreadScrollToBottom: FC = () => {
552
+ return (
553
+ <ThreadPrimitive.ScrollToBottom asChild>
554
+ <TooltipIconButton
555
+ tooltip="Scroll to bottom"
556
+ variant="outline"
557
+ className="absolute -top-8 rounded-full disabled:invisible"
558
+ >
559
+ <ArrowDownIcon />
560
+ </TooltipIconButton>
561
+ </ThreadPrimitive.ScrollToBottom>
562
+ );
563
+ };
564
+
565
+ const ThreadWelcome: FC = () => {
566
+ return (
567
+ <ThreadPrimitive.Empty>
568
+ <div className="flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
569
+ <div className="flex w-full flex-grow flex-col items-center justify-center">
570
+ <p className="mt-4 font-medium">How can I help you today?</p>
571
+ </div>
572
+ <ThreadWelcomeSuggestions />
573
+ </div>
574
+ </ThreadPrimitive.Empty>
575
+ );
576
+ };
577
+
578
+ const ThreadWelcomeSuggestions: FC = () => {
579
+ return (
580
+ <div className="mt-3 flex w-full items-stretch justify-center gap-4">
581
+ <ThreadPrimitive.Suggestion
582
+ className="hover:bg-muted/80 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-lg border p-3 transition-colors ease-in"
583
+ prompt="What is the weather in Tokyo?"
584
+ method="replace"
585
+ autoSend
586
+ >
587
+ <span className="line-clamp-2 text-ellipsis text-sm font-semibold">
588
+ What is the weather in Tokyo?
589
+ </span>
590
+ </ThreadPrimitive.Suggestion>
591
+ <ThreadPrimitive.Suggestion
592
+ className="hover:bg-muted/80 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-lg border p-3 transition-colors ease-in"
593
+ prompt="What is assistant-ui?"
594
+ method="replace"
595
+ autoSend
596
+ >
597
+ <span className="line-clamp-2 text-ellipsis text-sm font-semibold">
598
+ What is assistant-ui?
599
+ </span>
600
+ </ThreadPrimitive.Suggestion>
601
+ </div>
602
+ );
603
+ };
604
+
605
+ const Composer: FC = () => {
606
+ return (
607
+ <ComposerPrimitive.Root className="focus-within:border-ring/20 flex w-full flex-wrap items-end rounded-lg border bg-inherit px-2.5 shadow-sm transition-colors ease-in">
608
+ <ComposerPrimitive.Input
609
+ rows={1}
610
+ autoFocus
611
+ placeholder="Write a message..."
612
+ className="placeholder:text-muted-foreground max-h-40 flex-grow resize-none border-none bg-transparent px-2 py-4 text-sm outline-none focus:ring-0 disabled:cursor-not-allowed"
613
+ />
614
+ <ComposerAction />
615
+ </ComposerPrimitive.Root>
616
+ );
617
+ };
618
+
619
+ const ComposerAction: FC = () => {
620
+ return (
621
+ <>
622
+ <ThreadPrimitive.If running={false}>
623
+ <ComposerPrimitive.Send asChild>
624
+ <TooltipIconButton
625
+ tooltip="Send"
626
+ variant="default"
627
+ className="my-2.5 size-8 p-2 transition-opacity ease-in"
628
+ >
629
+ <SendHorizontalIcon />
630
+ </TooltipIconButton>
631
+ </ComposerPrimitive.Send>
632
+ </ThreadPrimitive.If>
633
+ <ThreadPrimitive.If running>
634
+ <ComposerPrimitive.Cancel asChild>
635
+ <TooltipIconButton
636
+ tooltip="Cancel"
637
+ variant="default"
638
+ className="my-2.5 size-8 p-2 transition-opacity ease-in"
639
+ >
640
+ <CircleStopIcon />
641
+ </TooltipIconButton>
642
+ </ComposerPrimitive.Cancel>
643
+ </ThreadPrimitive.If>
644
+ </>
645
+ );
646
+ };
647
+
648
+ const UserMessage: FC = () => {
649
+ return (
650
+ <MessagePrimitive.Root className="grid w-full max-w-[var(--thread-max-width)] auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] gap-y-2 py-4 [&:where(>*)]:col-start-2">
651
+ <UserActionBar />
652
+
653
+ <div className="bg-muted text-foreground col-start-2 row-start-2 max-w-[calc(var(--thread-max-width)*0.8)] break-words rounded-3xl px-5 py-2.5">
654
+ <MessagePrimitive.Content />
655
+ </div>
656
+
657
+ <BranchPicker className="col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
658
+ </MessagePrimitive.Root>
659
+ );
660
+ };
661
+
662
+ const UserActionBar: FC = () => {
663
+ return (
664
+ <ActionBarPrimitive.Root
665
+ hideWhenRunning
666
+ autohide="not-last"
667
+ className="col-start-1 row-start-2 mr-3 mt-2.5 flex flex-col items-end"
668
+ >
669
+ <ActionBarPrimitive.Edit asChild>
670
+ <TooltipIconButton tooltip="Edit">
671
+ <PencilIcon />
672
+ </TooltipIconButton>
673
+ </ActionBarPrimitive.Edit>
674
+ </ActionBarPrimitive.Root>
675
+ );
676
+ };
677
+
678
+ const EditComposer: FC = () => {
679
+ return (
680
+ <ComposerPrimitive.Root className="bg-muted my-4 flex w-full max-w-[var(--thread-max-width)] flex-col gap-2 rounded-xl">
681
+ <ComposerPrimitive.Input className="text-foreground flex h-8 w-full resize-none bg-transparent p-4 pb-0 outline-none" />
682
+
683
+ <div className="mx-3 mb-3 flex items-center justify-center gap-2 self-end">
684
+ <ComposerPrimitive.Cancel asChild>
685
+ <Button variant="ghost">Cancel</Button>
686
+ </ComposerPrimitive.Cancel>
687
+ <ComposerPrimitive.Send asChild>
688
+ <Button>Send</Button>
689
+ </ComposerPrimitive.Send>
690
+ </div>
691
+ </ComposerPrimitive.Root>
692
+ );
693
+ };
694
+
695
+ const AssistantMessage: FC = () => {
696
+ return (
697
+ <MessagePrimitive.Root className="relative grid w-full max-w-[var(--thread-max-width)] grid-cols-[auto_auto_1fr] grid-rows-[auto_1fr] py-4">
698
+ <div className="text-foreground col-span-2 col-start-2 row-start-1 my-1.5 max-w-[calc(var(--thread-max-width)*0.8)] break-words leading-7">
699
+ <MessagePrimitive.Content components={{ Text: MarkdownText }} />
700
+ </div>
701
+
702
+ <AssistantActionBar />
703
+
704
+ <BranchPicker className="col-start-2 row-start-2 -ml-2 mr-2" />
705
+ </MessagePrimitive.Root>
706
+ );
707
+ };
708
+
709
+ const AssistantActionBar: FC = () => {
710
+ return (
711
+ <ActionBarPrimitive.Root
712
+ hideWhenRunning
713
+ autohide="not-last"
714
+ autohideFloat="single-branch"
715
+ className="text-muted-foreground data-[floating]:bg-background col-start-3 row-start-2 -ml-1 flex gap-1 data-[floating]:absolute data-[floating]:rounded-md data-[floating]:border data-[floating]:p-1 data-[floating]:shadow-sm"
716
+ >
717
+ <ActionBarPrimitive.Copy asChild>
718
+ <TooltipIconButton tooltip="Copy">
719
+ <MessagePrimitive.If copied>
720
+ <CheckIcon />
721
+ </MessagePrimitive.If>
722
+ <MessagePrimitive.If copied={false}>
723
+ <CopyIcon />
724
+ </MessagePrimitive.If>
725
+ </TooltipIconButton>
726
+ </ActionBarPrimitive.Copy>
727
+ <ActionBarPrimitive.Reload asChild>
728
+ <TooltipIconButton tooltip="Refresh">
729
+ <RefreshCwIcon />
730
+ </TooltipIconButton>
731
+ </ActionBarPrimitive.Reload>
732
+ </ActionBarPrimitive.Root>
733
+ );
734
+ };
735
+
736
+ const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
737
+ className,
738
+ ...rest
739
+ }) => {
740
+ return (
741
+ <BranchPickerPrimitive.Root
742
+ hideWhenSingleBranch
743
+ className={cn(
744
+ "text-muted-foreground inline-flex items-center text-xs",
745
+ className,
746
+ )}
747
+ {...rest}
748
+ >
749
+ <BranchPickerPrimitive.Previous asChild>
750
+ <TooltipIconButton tooltip="Previous">
751
+ <ChevronLeftIcon />
752
+ </TooltipIconButton>
753
+ </BranchPickerPrimitive.Previous>
754
+ <span className="font-medium">
755
+ <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
756
+ </span>
757
+ <BranchPickerPrimitive.Next asChild>
758
+ <TooltipIconButton tooltip="Next">
759
+ <ChevronRightIcon />
760
+ </TooltipIconButton>
761
+ </BranchPickerPrimitive.Next>
762
+ </BranchPickerPrimitive.Root>
763
+ );
764
+ };
765
+
766
+ const CircleStopIcon = () => {
767
+ return (
768
+ <svg
769
+ xmlns="http://www.w3.org/2000/svg"
770
+ viewBox="0 0 16 16"
771
+ fill="currentColor"
772
+ width="16"
773
+ height="16"
774
+ >
775
+ <rect width="10" height="10" x="3" y="3" rx="2" />
776
+ </svg>
777
+ );
778
+ };
779
+
780
+ ```
781
+
782
+ ## components/assistant-ui/tooltip-icon-button.tsx
783
+
784
+ ```tsx
785
+ "use client";
786
+
787
+ import { ComponentPropsWithoutRef, forwardRef } from "react";
788
+
789
+ import {
790
+ Tooltip,
791
+ TooltipContent,
792
+ TooltipTrigger,
793
+ } from "@/components/ui/tooltip";
794
+ import { Button } from "@/components/ui/button";
795
+ import { cn } from "@/lib/utils";
796
+
797
+ export type TooltipIconButtonProps = ComponentPropsWithoutRef<typeof Button> & {
798
+ tooltip: string;
799
+ side?: "top" | "bottom" | "left" | "right";
800
+ };
801
+
802
+ export const TooltipIconButton = forwardRef<
803
+ HTMLButtonElement,
804
+ TooltipIconButtonProps
805
+ >(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
806
+ return (
807
+ <Tooltip>
808
+ <TooltipTrigger asChild>
809
+ <Button
810
+ variant="ghost"
811
+ size="icon"
812
+ {...rest}
813
+ className={cn("size-6 p-1", className)}
814
+ ref={ref}
815
+ >
816
+ {children}
817
+ <span className="sr-only">{tooltip}</span>
818
+ </Button>
819
+ </TooltipTrigger>
820
+ <TooltipContent side={side}>{tooltip}</TooltipContent>
821
+ </Tooltip>
822
+ );
823
+ });
824
+
825
+ TooltipIconButton.displayName = "TooltipIconButton";
826
+
827
+ ```
828
+
829
+ ## components/ui/button.tsx
830
+
831
+ ```tsx
832
+ import * as React from "react";
833
+ import { Slot } from "@radix-ui/react-slot";
834
+ import { cva, type VariantProps } from "class-variance-authority";
835
+
836
+ import { cn } from "@/lib/utils";
837
+
838
+ const buttonVariants = cva(
839
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
840
+ {
841
+ variants: {
842
+ variant: {
843
+ default:
844
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
845
+ destructive:
846
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
847
+ outline:
848
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
849
+ secondary:
850
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
851
+ ghost:
852
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
853
+ link: "text-primary underline-offset-4 hover:underline",
854
+ },
855
+ size: {
856
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
857
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
858
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
859
+ icon: "size-9",
860
+ },
861
+ },
862
+ defaultVariants: {
863
+ variant: "default",
864
+ size: "default",
865
+ },
866
+ },
867
+ );
868
+
869
+ function Button({
870
+ className,
871
+ variant,
872
+ size,
873
+ asChild = false,
874
+ ...props
875
+ }: React.ComponentProps<"button"> &
876
+ VariantProps<typeof buttonVariants> & {
877
+ asChild?: boolean;
878
+ }) {
879
+ const Comp = asChild ? Slot : "button";
880
+
881
+ return (
882
+ <Comp
883
+ data-slot="button"
884
+ className={cn(buttonVariants({ variant, size, className }))}
885
+ {...props}
886
+ />
887
+ );
888
+ }
889
+
890
+ export { Button, buttonVariants };
891
+
892
+ ```
893
+
894
+ ## components/ui/tooltip.tsx
895
+
896
+ ```tsx
897
+ "use client";
898
+
899
+ import * as React from "react";
900
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
901
+
902
+ import { cn } from "@/lib/utils";
903
+
904
+ function TooltipProvider({
905
+ delayDuration = 0,
906
+ ...props
907
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
908
+ return (
909
+ <TooltipPrimitive.Provider
910
+ data-slot="tooltip-provider"
911
+ delayDuration={delayDuration}
912
+ {...props}
913
+ />
914
+ );
915
+ }
916
+
917
+ function Tooltip({
918
+ ...props
919
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
920
+ return (
921
+ <TooltipProvider>
922
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
923
+ </TooltipProvider>
924
+ );
925
+ }
926
+
927
+ function TooltipTrigger({
928
+ ...props
929
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
930
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
931
+ }
932
+
933
+ function TooltipContent({
934
+ className,
935
+ sideOffset = 0,
936
+ children,
937
+ ...props
938
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
939
+ return (
940
+ <TooltipPrimitive.Portal>
941
+ <TooltipPrimitive.Content
942
+ data-slot="tooltip-content"
943
+ sideOffset={sideOffset}
944
+ className={cn(
945
+ "bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-[--radix-tooltip-content-transform-origin] text-balance rounded-md px-3 py-1.5 text-xs",
946
+ className,
947
+ )}
948
+ {...props}
949
+ >
950
+ {children}
951
+ <TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
952
+ </TooltipPrimitive.Content>
953
+ </TooltipPrimitive.Portal>
954
+ );
955
+ }
956
+
957
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
958
+
959
+ ```
960
+
961
+ ## eslint.config.ts
962
+
963
+ ```typescript
964
+ export { default } from "@assistant-ui/x-buildutils/eslint";
965
+
966
+ ```
967
+
968
+ ## lib/utils.ts
969
+
970
+ ```typescript
971
+ import { clsx, type ClassValue } from "clsx";
972
+ import { twMerge } from "tailwind-merge";
973
+
974
+ export function cn(...inputs: ClassValue[]) {
975
+ return twMerge(clsx(inputs));
976
+ }
977
+
978
+ ```
979
+
980
+ ## next.config.ts
981
+
982
+ ```typescript
983
+ import type { NextConfig } from "next";
984
+
985
+ const nextConfig: NextConfig = {
986
+ /* config options here */
987
+ };
988
+
989
+ export default nextConfig;
990
+
991
+ ```
992
+
993
+ ## package.json
994
+
995
+ ```json
996
+ {
997
+ "name": "with-local-ollama",
998
+ "version": "0.1.0",
999
+ "private": true,
1000
+ "scripts": {
1001
+ "dev": "next dev --turbo",
1002
+ "build": "next build",
1003
+ "start": "next start",
1004
+ "lint": "next lint"
1005
+ },
1006
+ "dependencies": {
1007
+ "@assistant-ui/react": "workspace:*",
1008
+ "@assistant-ui/react-ai-sdk": "workspace:*",
1009
+ "@assistant-ui/react-markdown": "workspace:*",
1010
+ "@radix-ui/react-slot": "^1.2.3",
1011
+ "@radix-ui/react-tooltip": "^1.2.7",
1012
+ "ai": "^4.3.16",
1013
+ "class-variance-authority": "^0.7.1",
1014
+ "clsx": "^2.1.1",
1015
+ "lucide-react": "^0.511.0",
1016
+ "next": "15.3.3",
1017
+ "ollama-ai-provider": "^1.2.0",
1018
+ "react": "19.1.0",
1019
+ "react-dom": "19.1.0",
1020
+ "remark-gfm": "^4.0.1",
1021
+ "tailwind-merge": "^3.3.0",
1022
+ "tw-animate-css": "^1.3.3",
1023
+ "zod": "^3.25.49"
1024
+ },
1025
+ "devDependencies": {
1026
+ "@assistant-ui/x-buildutils": "workspace:*",
1027
+ "@types/node": "^22",
1028
+ "@types/react": "^19",
1029
+ "@types/react-dom": "^19",
1030
+ "eslint": "^9",
1031
+ "eslint-config-next": "15.3.3",
1032
+ "postcss": "^8",
1033
+ "tailwindcss": "^4.1.8",
1034
+ "typescript": "^5"
1035
+ }
1036
+ }
1037
+
1038
+ ```
1039
+
1040
+ ## README.md
1041
+
1042
+ ```markdown
1043
+ ## Project Overview
1044
+
1045
+ This project configures `assistant-ui` to work with Ollama hosted on a local instance. Additionally, it changes the theme to dark mode.
1046
+
1047
+ This source code was generated using the `Getting Started` guide hosted on [assistant-ui.com/docs](https://www.assistant-ui.com/docs).
1048
+
1049
+ ## Prerequisites
1050
+
1051
+ Ensure you have the following installed:
1052
+
1053
+ - Node.js
1054
+ - npm
1055
+
1056
+ ## Installation
1057
+
1058
+ Clone the repository:
1059
+
1060
+ ```bash
1061
+ git clone https://github.com/yourusername/assistant-ui-local-ollama.git
1062
+ cd assistant-ui-local-ollama
1063
+ ```
1064
+
1065
+ Install the dependencies:
1066
+
1067
+ ```bash
1068
+ npm install
1069
+ ```
1070
+
1071
+ ## Configuration
1072
+
1073
+ Copy the `.env.local.example` file to `.env`:
1074
+
1075
+ Add `OLLAMA_API_URL` to the `.env` file:
1076
+
1077
+ ```
1078
+ OLLAMA_API_URL=http:/x.x.x.x:11434/api
1079
+ ```
1080
+
1081
+ ## Running the Development Server
1082
+
1083
+ Start the development server:
1084
+
1085
+ ```bash
1086
+ npm run dev
1087
+ ```
1088
+
1089
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
1090
+
1091
+ ## Editing the Project
1092
+
1093
+ You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
1094
+
1095
+ ## Changing the Theme to Dark Mode
1096
+
1097
+ The theme has been set to dark mode by default. You can customize the theme by annotating html with the className `dark`.
1098
+
1099
+ ## License
1100
+
1101
+ This project is licensed under the MIT License.
1102
+
1103
+ ```
1104
+
1105
+ ## tsconfig.json
1106
+
1107
+ ```json
1108
+ {
1109
+ "extends": "@assistant-ui/x-buildutils/ts/base",
1110
+ "compilerOptions": {
1111
+ "target": "ES6",
1112
+ "module": "ESNext",
1113
+ "incremental": true,
1114
+ "plugins": [
1115
+ {
1116
+ "name": "next"
1117
+ }
1118
+ ],
1119
+ "allowJs": true,
1120
+ "strictNullChecks": true,
1121
+ "jsx": "preserve",
1122
+ "paths": {
1123
+ "@/*": ["./*"],
1124
+ "@assistant-ui/*": ["../../packages/*/src"],
1125
+ "@assistant-ui/react/*": ["../../packages/react/src/*"],
1126
+ "assistant-stream": ["../../packages/assistant-stream/src"],
1127
+ "assistant-stream/*": ["../../packages/assistant-stream/src/*"]
1128
+ }
1129
+ },
1130
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
1131
+ "exclude": ["node_modules"]
1132
+ }
1133
+
1134
+ ```
1135
+