@assistant-ui/mcp-docs-server 0.1.34 → 0.1.35

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 (64) hide show
  1. package/.docs/organized/code-examples/waterfall.md +4 -4
  2. package/.docs/organized/code-examples/with-a2a.md +5 -5
  3. package/.docs/organized/code-examples/with-ag-ui.md +6 -6
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +7 -7
  5. package/.docs/organized/code-examples/with-artifacts.md +7 -7
  6. package/.docs/organized/code-examples/with-assistant-transport.md +5 -5
  7. package/.docs/organized/code-examples/with-browser-extension.md +5 -5
  8. package/.docs/organized/code-examples/with-chain-of-thought.md +8 -8
  9. package/.docs/organized/code-examples/with-cloud-standalone.md +7 -7
  10. package/.docs/organized/code-examples/with-cloud.md +7 -7
  11. package/.docs/organized/code-examples/with-custom-thread-list.md +7 -7
  12. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +9 -9
  13. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +9 -9
  14. package/.docs/organized/code-examples/with-expo.md +43 -17
  15. package/.docs/organized/code-examples/with-external-store.md +5 -5
  16. package/.docs/organized/code-examples/with-ffmpeg.md +7 -7
  17. package/.docs/organized/code-examples/with-generative-ui.md +32 -308
  18. package/.docs/organized/code-examples/with-google-adk.md +5 -5
  19. package/.docs/organized/code-examples/with-heat-graph.md +4 -4
  20. package/.docs/organized/code-examples/with-image-generation.md +7 -7
  21. package/.docs/organized/code-examples/with-interactables.md +7 -7
  22. package/.docs/organized/code-examples/with-langchain.md +7 -7
  23. package/.docs/organized/code-examples/with-langgraph.md +6 -6
  24. package/.docs/organized/code-examples/with-livekit.md +9 -9
  25. package/.docs/organized/code-examples/with-mcp.md +7 -7
  26. package/.docs/organized/code-examples/with-opencode.md +106 -580
  27. package/.docs/organized/code-examples/with-pi.md +2044 -0
  28. package/.docs/organized/code-examples/with-react-hook-form.md +8 -8
  29. package/.docs/organized/code-examples/with-react-ink-web.md +691 -0
  30. package/.docs/organized/code-examples/with-react-ink.md +28 -16
  31. package/.docs/organized/code-examples/with-react-router.md +5 -5
  32. package/.docs/organized/code-examples/with-resumable-stream.md +8 -8
  33. package/.docs/organized/code-examples/with-store.md +14 -10
  34. package/.docs/organized/code-examples/with-tanstack.md +18 -4
  35. package/.docs/organized/code-examples/with-tap-runtime.md +5 -5
  36. package/.docs/organized/code-examples/with-virtualized-thread.md +656 -0
  37. package/.docs/raw/docs/(docs)/architecture.mdx +13 -12
  38. package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +44 -1
  39. package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -1
  40. package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +2 -23
  41. package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +22 -0
  42. package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +0 -7
  43. package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +20 -21
  44. package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
  45. package/.docs/raw/docs/guides/index.mdx +3 -0
  46. package/.docs/raw/docs/guides/input-history.mdx +55 -0
  47. package/.docs/raw/docs/guides/virtualization.mdx +63 -0
  48. package/.docs/raw/docs/ink/hooks.mdx +2 -2
  49. package/.docs/raw/docs/react-native/hooks.mdx +1 -1
  50. package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +1 -3
  51. package/.docs/raw/docs/runtimes/concepts/stability.mdx +1 -1
  52. package/.docs/raw/docs/runtimes/custom/data-stream.mdx +1 -1
  53. package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +108 -4
  54. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +6 -6
  55. package/.docs/raw/docs/tools/tool-ui.mdx +37 -1
  56. package/.docs/raw/docs/ui/dot-matrix.mdx +133 -0
  57. package/.docs/raw/docs/ui/model-selector.mdx +219 -52
  58. package/.docs/raw/docs/ui/number-roll.mdx +154 -0
  59. package/.docs/raw/docs/ui/reasoning.mdx +3 -3
  60. package/.docs/raw/docs/ui/streamdown.mdx +2 -0
  61. package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -1
  62. package/.docs/raw/docs/ui/thread.mdx +52 -0
  63. package/.docs/raw/docs/ui/tool-fallback.mdx +2 -2
  64. package/package.json +3 -3
@@ -188,7 +188,7 @@ export default function RootLayout({
188
188
  ```tsx
189
189
  "use client";
190
190
 
191
- import { AssistantRuntimeProvider } from "@assistant-ui/react";
191
+ import { AssistantRuntimeProvider, Tools, useAui } from "@assistant-ui/react";
192
192
  import {
193
193
  SidebarInset,
194
194
  SidebarProvider,
@@ -200,7 +200,22 @@ import {
200
200
  useOpenCodeRuntime,
201
201
  useOpenCodeSession,
202
202
  } from "@assistant-ui/react-opencode";
203
- import { Thread } from "../components/assistant-ui/thread";
203
+ import {
204
+ Thread,
205
+ type ThreadComponents,
206
+ } from "@/components/assistant-ui/thread";
207
+ import { OpenCodeDataPart } from "@/components/opencode-data-part";
208
+ import { FallbackTool } from "@/components/tools/opencode-tools";
209
+ import { ReasoningGroup } from "@/components/tools/reasoning-ghost";
210
+ import { ToolGroup } from "@/components/tools/tool-group";
211
+ import toolkit from "@/components/tools/toolkit";
212
+ import { useEffect } from "react";
213
+
214
+ const THREAD_COMPONENTS: ThreadComponents = {
215
+ ToolFallback: FallbackTool,
216
+ ToolGroup,
217
+ ReasoningGroup,
218
+ };
204
219
 
205
220
  export default function Home() {
206
221
  const runtime = useOpenCodeRuntime({
@@ -208,8 +223,17 @@ export default function Home() {
208
223
  process.env.NEXT_PUBLIC_OPENCODE_BASE_URL ?? "http://localhost:4096",
209
224
  });
210
225
 
226
+ const aui = useAui({
227
+ tools: Tools({ toolkit }),
228
+ });
229
+
230
+ useEffect(
231
+ () => aui.dataRenderers().setFallbackDataUI(OpenCodeDataPart),
232
+ [aui],
233
+ );
234
+
211
235
  return (
212
- <AssistantRuntimeProvider runtime={runtime}>
236
+ <AssistantRuntimeProvider aui={aui} runtime={runtime}>
213
237
  <SidebarProvider>
214
238
  <div className="flex h-dvh w-full overflow-hidden pr-0.5">
215
239
  <ThreadListSidebar />
@@ -223,7 +247,7 @@ export default function Home() {
223
247
  </div>
224
248
  </header>
225
249
  <div className="min-h-0 flex-1 overflow-hidden">
226
- <Thread />
250
+ <Thread components={THREAD_COMPONENTS} />
227
251
  </div>
228
252
  </SidebarInset>
229
253
  </div>
@@ -277,576 +301,6 @@ function SelectedSessionTitle() {
277
301
 
278
302
  ```
279
303
 
280
- ## components/assistant-ui/thread-list.tsx
281
-
282
- ```tsx
283
- import { Button } from "@/components/ui/button";
284
- import { Skeleton } from "@/components/ui/skeleton";
285
- import {
286
- AuiIf,
287
- ThreadListItemMorePrimitive,
288
- ThreadListItemPrimitive,
289
- ThreadListPrimitive,
290
- } from "@assistant-ui/react";
291
- import { MoreHorizontalIcon, PlusIcon, TrashIcon } from "lucide-react";
292
- import type { FC } from "react";
293
-
294
- export const ThreadList: FC = () => {
295
- return (
296
- <ThreadListPrimitive.Root className="aui-root aui-thread-list-root flex min-h-0 flex-1 flex-col gap-1 overflow-hidden">
297
- <ThreadListNew />
298
- <AuiIf condition={(s) => s.threads.isLoading}>
299
- <ThreadListSkeleton />
300
- </AuiIf>
301
- <AuiIf condition={(s) => !s.threads.isLoading}>
302
- <div className="min-h-0 flex-1 overflow-y-auto">
303
- <ThreadListPrimitive.Items components={{ ThreadListItem }} />
304
- </div>
305
- </AuiIf>
306
- </ThreadListPrimitive.Root>
307
- );
308
- };
309
-
310
- const ThreadListNew: FC = () => {
311
- return (
312
- <ThreadListPrimitive.New asChild>
313
- <Button
314
- variant="outline"
315
- className="aui-thread-list-new hover:bg-muted data-active:bg-muted h-9 justify-start gap-2 rounded-lg px-3 text-sm"
316
- >
317
- <PlusIcon className="size-4" />
318
- New Session
319
- </Button>
320
- </ThreadListPrimitive.New>
321
- );
322
- };
323
-
324
- const ThreadListSkeleton: FC = () => {
325
- return (
326
- <div className="flex flex-col gap-1">
327
- {Array.from({ length: 5 }, (_, i) => (
328
- <div
329
- key={i}
330
- role="status"
331
- aria-label="Loading threads"
332
- className="aui-thread-list-skeleton-wrapper flex h-9 items-center px-3"
333
- >
334
- <Skeleton className="aui-thread-list-skeleton h-4 w-full" />
335
- </div>
336
- ))}
337
- </div>
338
- );
339
- };
340
-
341
- const ThreadListItem: FC = () => {
342
- return (
343
- <ThreadListItemPrimitive.Root className="aui-thread-list-item group hover:bg-muted focus-visible:bg-muted data-active:bg-muted flex h-9 items-center gap-2 rounded-lg transition-colors focus-visible:outline-none">
344
- <ThreadListItemPrimitive.Trigger className="aui-thread-list-item-trigger flex h-full min-w-0 flex-1 items-center truncate px-3 text-start text-sm">
345
- <ThreadListItemPrimitive.Title fallback="New Session" />
346
- </ThreadListItemPrimitive.Trigger>
347
- <ThreadListItemMore />
348
- </ThreadListItemPrimitive.Root>
349
- );
350
- };
351
-
352
- const ThreadListItemMore: FC = () => {
353
- return (
354
- <ThreadListItemMorePrimitive.Root>
355
- <ThreadListItemMorePrimitive.Trigger asChild>
356
- <Button
357
- variant="ghost"
358
- size="icon"
359
- className="aui-thread-list-item-more data-[state=open]:bg-accent mr-2 size-7 p-0 opacity-0 transition-opacity group-hover:opacity-100 group-data-active:opacity-100 data-[state=open]:opacity-100"
360
- >
361
- <MoreHorizontalIcon className="size-4" />
362
- <span className="sr-only">More options</span>
363
- </Button>
364
- </ThreadListItemMorePrimitive.Trigger>
365
- <ThreadListItemMorePrimitive.Content
366
- side="bottom"
367
- align="start"
368
- className="aui-thread-list-item-more-content bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md"
369
- >
370
- <ThreadListItemPrimitive.Delete asChild>
371
- <ThreadListItemMorePrimitive.Item className="aui-thread-list-item-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none">
372
- <TrashIcon className="size-4" />
373
- Delete
374
- </ThreadListItemMorePrimitive.Item>
375
- </ThreadListItemPrimitive.Delete>
376
- </ThreadListItemMorePrimitive.Content>
377
- </ThreadListItemMorePrimitive.Root>
378
- );
379
- };
380
-
381
- ```
382
-
383
- ## components/assistant-ui/thread.tsx
384
-
385
- ```tsx
386
- import {
387
- ComposerAddAttachment,
388
- ComposerAttachments,
389
- UserMessageAttachments,
390
- } from "@/components/assistant-ui/attachment";
391
- import { MarkdownText } from "@/components/assistant-ui/markdown-text";
392
- import { Reasoning } from "@/components/assistant-ui/reasoning";
393
- import {
394
- AskQuestionInline,
395
- withOpenCodeToolInteractions,
396
- } from "@/components/tools/opencode-tool-interactions";
397
- import { ReasoningGroup as ReasoningGhostGroup } from "@/components/tools/reasoning-ghost";
398
- import { BashTerminal } from "@/components/tools/tool-ui-bash";
399
- import { ApplyPatchDiff } from "@/components/tools/tool-ui-apply-patch";
400
- import {
401
- EditInline,
402
- GlobInline,
403
- GrepInline,
404
- ReadInline,
405
- ToolCallFallback,
406
- WebFetchInline,
407
- WebSearchInline,
408
- WriteInline,
409
- } from "@/components/tools/tool-ui-inline";
410
- import { ToolGroup as ToolCallGroup } from "@/components/tools/tool-group";
411
- import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
412
- import { OpenCodeDataPart } from "@/components/opencode-data-part";
413
- import { Button } from "@/components/ui/button";
414
- import { cn } from "@/lib/utils";
415
- import {
416
- ActionBarMorePrimitive,
417
- ActionBarPrimitive,
418
- AuiIf,
419
- BranchPickerPrimitive,
420
- ComposerPrimitive,
421
- ErrorPrimitive,
422
- groupPartByType,
423
- MessagePrimitive,
424
- SuggestionPrimitive,
425
- ThreadPrimitive,
426
- useAuiState,
427
- } from "@assistant-ui/react";
428
- import {
429
- ArrowDownIcon,
430
- ArrowUpIcon,
431
- CheckIcon,
432
- ChevronLeftIcon,
433
- ChevronRightIcon,
434
- CopyIcon,
435
- DownloadIcon,
436
- MoreHorizontalIcon,
437
- PencilIcon,
438
- RefreshCwIcon,
439
- SquareIcon,
440
- } from "lucide-react";
441
- import type { ComponentProps, FC } from "react";
442
-
443
- const ReadTool = withOpenCodeToolInteractions(ReadInline);
444
- const EditTool = withOpenCodeToolInteractions(EditInline);
445
- const WriteTool = withOpenCodeToolInteractions(WriteInline);
446
- const BashTool = withOpenCodeToolInteractions(BashTerminal);
447
- const GrepTool = withOpenCodeToolInteractions(GrepInline);
448
- const GlobTool = withOpenCodeToolInteractions(GlobInline);
449
- const WebSearchTool = withOpenCodeToolInteractions(WebSearchInline);
450
- const WebFetchTool = withOpenCodeToolInteractions(WebFetchInline);
451
- const ApplyPatchTool = withOpenCodeToolInteractions(ApplyPatchDiff);
452
- const AskQuestionTool = withOpenCodeToolInteractions(AskQuestionInline);
453
- const FallbackTool = withOpenCodeToolInteractions(ToolCallFallback);
454
-
455
- const renderOpenCodeTool = (
456
- part: Extract<
457
- Parameters<
458
- NonNullable<
459
- ComponentProps<typeof MessagePrimitive.GroupedParts>["children"]
460
- >
461
- >[0]["part"],
462
- { type: "tool-call" }
463
- >,
464
- ) => {
465
- switch (part.toolName) {
466
- case "read":
467
- return <ReadTool {...part} />;
468
- case "edit":
469
- return <EditTool {...part} />;
470
- case "write":
471
- return <WriteTool {...part} />;
472
- case "bash":
473
- return <BashTool {...part} />;
474
- case "grep":
475
- return <GrepTool {...part} />;
476
- case "glob":
477
- return <GlobTool {...part} />;
478
- case "webSearch":
479
- return <WebSearchTool {...part} />;
480
- case "webFetch":
481
- return <WebFetchTool {...part} />;
482
- case "apply_patch":
483
- return <ApplyPatchTool {...part} />;
484
- case "ask_question":
485
- case "request_user_input":
486
- case "requestUserInput":
487
- return <AskQuestionTool {...part} />;
488
- default:
489
- return <FallbackTool {...part} />;
490
- }
491
- };
492
-
493
- export const Thread: FC = () => {
494
- return (
495
- <ThreadPrimitive.Root
496
- className="aui-root aui-thread-root bg-background @container flex h-full flex-col"
497
- style={{
498
- ["--thread-max-width" as string]: "44rem",
499
- ["--composer-radius" as string]: "24px",
500
- ["--composer-padding" as string]: "10px",
501
- }}
502
- >
503
- <ThreadPrimitive.Viewport
504
- turnAnchor="top"
505
- className="aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
506
- >
507
- <AuiIf condition={(s) => s.thread.isEmpty}>
508
- <ThreadWelcome />
509
- </AuiIf>
510
-
511
- <ThreadPrimitive.Messages>
512
- {() => <ThreadMessage />}
513
- </ThreadPrimitive.Messages>
514
-
515
- <ThreadPrimitive.ViewportFooter className="aui-thread-viewport-footer bg-background sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-(--composer-radius) pb-4 md:pb-6">
516
- <ThreadScrollToBottom />
517
- <Composer />
518
- </ThreadPrimitive.ViewportFooter>
519
- </ThreadPrimitive.Viewport>
520
- </ThreadPrimitive.Root>
521
- );
522
- };
523
-
524
- const ThreadMessage: FC = () => {
525
- const role = useAuiState((s) => s.message.role);
526
- const isEditing = useAuiState((s) => s.message.composer.isEditing);
527
- if (isEditing) return <EditComposer />;
528
- if (role === "user") return <UserMessage />;
529
- return <AssistantMessage />;
530
- };
531
-
532
- const ThreadScrollToBottom: FC = () => {
533
- return (
534
- <ThreadPrimitive.ScrollToBottom asChild>
535
- <TooltipIconButton
536
- tooltip="Scroll to bottom"
537
- variant="outline"
538
- className="aui-thread-scroll-to-bottom dark:border-border dark:bg-background dark:hover:bg-accent absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible"
539
- >
540
- <ArrowDownIcon />
541
- </TooltipIconButton>
542
- </ThreadPrimitive.ScrollToBottom>
543
- );
544
- };
545
-
546
- const ThreadWelcome: FC = () => {
547
- return (
548
- <div className="aui-thread-welcome-root mx-auto my-auto flex w-full max-w-(--thread-max-width) grow flex-col">
549
- <div className="aui-thread-welcome-center flex w-full grow flex-col items-center justify-center">
550
- <div className="aui-thread-welcome-message flex size-full flex-col justify-center px-4">
551
- <h1 className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-semibold duration-200">
552
- Welcome
553
- </h1>
554
- <p className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground text-xl delay-75 duration-200">
555
- How can I help you today?
556
- </p>
557
- </div>
558
- </div>
559
- <ThreadSuggestions />
560
- </div>
561
- );
562
- };
563
-
564
- const ThreadSuggestions: FC = () => {
565
- return (
566
- <div className="aui-thread-welcome-suggestions grid w-full gap-2 pb-4 @md:grid-cols-2">
567
- <ThreadPrimitive.Suggestions>
568
- {() => <ThreadSuggestionItem />}
569
- </ThreadPrimitive.Suggestions>
570
- </div>
571
- );
572
- };
573
-
574
- const ThreadSuggestionItem: FC = () => {
575
- return (
576
- <div className="aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200 nth-[n+3]:hidden @md:nth-[n+3]:block">
577
- <SuggestionPrimitive.Trigger send asChild>
578
- <Button
579
- variant="ghost"
580
- className="aui-thread-welcome-suggestion bg-background hover:bg-muted h-auto w-full flex-wrap items-start justify-start gap-1 rounded-3xl border px-4 py-3 text-left text-sm transition-colors @md:flex-col"
581
- >
582
- <SuggestionPrimitive.Title className="aui-thread-welcome-suggestion-text-1 font-medium" />
583
- <SuggestionPrimitive.Description className="aui-thread-welcome-suggestion-text-2 text-muted-foreground empty:hidden" />
584
- </Button>
585
- </SuggestionPrimitive.Trigger>
586
- </div>
587
- );
588
- };
589
-
590
- const Composer: FC = () => {
591
- return (
592
- <ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
593
- <ComposerPrimitive.AttachmentDropzone asChild>
594
- <div
595
- data-slot="composer-shell"
596
- className="bg-background focus-within:border-ring/75 focus-within:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:bg-accent/50 flex w-full flex-col gap-2 rounded-(--composer-radius) border p-(--composer-padding) transition-shadow focus-within:ring-2 data-[dragging=true]:border-dashed"
597
- >
598
- <ComposerAttachments />
599
- <ComposerPrimitive.Input
600
- placeholder="Send a message..."
601
- className="aui-composer-input placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none bg-transparent px-1.75 py-1 text-sm outline-none"
602
- rows={1}
603
- autoFocus
604
- aria-label="Message input"
605
- />
606
- <ComposerAction />
607
- </div>
608
- </ComposerPrimitive.AttachmentDropzone>
609
- </ComposerPrimitive.Root>
610
- );
611
- };
612
-
613
- const ComposerAction: FC = () => {
614
- return (
615
- <div className="aui-composer-action-wrapper relative flex items-center justify-between">
616
- <ComposerAddAttachment />
617
- <AuiIf condition={(s) => !s.thread.isRunning}>
618
- <ComposerPrimitive.Send asChild>
619
- <TooltipIconButton
620
- tooltip="Send message"
621
- side="bottom"
622
- type="button"
623
- variant="default"
624
- size="icon"
625
- className="aui-composer-send size-8 rounded-full"
626
- aria-label="Send message"
627
- >
628
- <ArrowUpIcon className="aui-composer-send-icon size-4" />
629
- </TooltipIconButton>
630
- </ComposerPrimitive.Send>
631
- </AuiIf>
632
- <AuiIf condition={(s) => s.thread.isRunning}>
633
- <ComposerPrimitive.Cancel asChild>
634
- <Button
635
- type="button"
636
- variant="default"
637
- size="icon"
638
- className="aui-composer-cancel size-8 rounded-full"
639
- aria-label="Stop generating"
640
- >
641
- <SquareIcon className="aui-composer-cancel-icon size-3 fill-current" />
642
- </Button>
643
- </ComposerPrimitive.Cancel>
644
- </AuiIf>
645
- </div>
646
- );
647
- };
648
-
649
- const MessageError: FC = () => {
650
- return (
651
- <MessagePrimitive.Error>
652
- <ErrorPrimitive.Root className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-full border px-3 py-2 text-sm dark:text-red-200">
653
- <ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
654
- </ErrorPrimitive.Root>
655
- </MessagePrimitive.Error>
656
- );
657
- };
658
-
659
- const AssistantMessage: FC = () => {
660
- return (
661
- <MessagePrimitive.Root
662
- className="aui-assistant-message-root fade-in slide-in-from-bottom-1 animate-in relative mx-auto w-full max-w-(--thread-max-width) py-3 duration-150"
663
- data-role="assistant"
664
- >
665
- <div className="aui-assistant-message-content text-foreground px-2 leading-relaxed wrap-break-word">
666
- <MessagePrimitive.GroupedParts
667
- groupBy={groupPartByType({
668
- reasoning: ["group-chainOfThought", "group-reasoning"],
669
- "tool-call": ["group-chainOfThought", "group-tool"],
670
- })}
671
- >
672
- {({ part, children }) => {
673
- switch (part.type) {
674
- case "group-chainOfThought":
675
- return <div data-slot="aui_chain-of-thought">{children}</div>;
676
- case "group-reasoning":
677
- return (
678
- <ReasoningGhostGroup group={part}>
679
- {children}
680
- </ReasoningGhostGroup>
681
- );
682
- case "group-tool":
683
- return <ToolCallGroup group={part}>{children}</ToolCallGroup>;
684
- case "text":
685
- return <MarkdownText />;
686
- case "reasoning":
687
- return <Reasoning {...part} />;
688
- case "tool-call":
689
- return renderOpenCodeTool(part);
690
- case "data":
691
- return <OpenCodeDataPart {...part} />;
692
- default:
693
- return null;
694
- }
695
- }}
696
- </MessagePrimitive.GroupedParts>
697
- <MessageError />
698
- </div>
699
-
700
- <div className="aui-assistant-message-footer mt-1 ml-2 flex">
701
- <BranchPicker />
702
- <AssistantActionBar />
703
- </div>
704
- </MessagePrimitive.Root>
705
- );
706
- };
707
-
708
- const AssistantActionBar: FC = () => {
709
- return (
710
- <ActionBarPrimitive.Root
711
- hideWhenRunning
712
- autohide="not-last"
713
- autohideFloat="single-branch"
714
- className="aui-assistant-action-bar-root 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"
715
- >
716
- <ActionBarPrimitive.Copy asChild>
717
- <TooltipIconButton tooltip="Copy">
718
- <AuiIf condition={(s) => s.message.isCopied}>
719
- <CheckIcon />
720
- </AuiIf>
721
- <AuiIf condition={(s) => !s.message.isCopied}>
722
- <CopyIcon />
723
- </AuiIf>
724
- </TooltipIconButton>
725
- </ActionBarPrimitive.Copy>
726
- <ActionBarPrimitive.Reload asChild>
727
- <TooltipIconButton tooltip="Refresh">
728
- <RefreshCwIcon />
729
- </TooltipIconButton>
730
- </ActionBarPrimitive.Reload>
731
- <ActionBarMorePrimitive.Root>
732
- <ActionBarMorePrimitive.Trigger asChild>
733
- <TooltipIconButton
734
- tooltip="More"
735
- className="data-[state=open]:bg-accent"
736
- >
737
- <MoreHorizontalIcon />
738
- </TooltipIconButton>
739
- </ActionBarMorePrimitive.Trigger>
740
- <ActionBarMorePrimitive.Content
741
- side="bottom"
742
- align="start"
743
- className="aui-action-bar-more-content bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md"
744
- >
745
- <ActionBarPrimitive.ExportMarkdown asChild>
746
- <ActionBarMorePrimitive.Item className="aui-action-bar-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none">
747
- <DownloadIcon className="size-4" />
748
- Export as Markdown
749
- </ActionBarMorePrimitive.Item>
750
- </ActionBarPrimitive.ExportMarkdown>
751
- </ActionBarMorePrimitive.Content>
752
- </ActionBarMorePrimitive.Root>
753
- </ActionBarPrimitive.Root>
754
- );
755
- };
756
-
757
- const UserMessage: FC = () => {
758
- return (
759
- <MessagePrimitive.Root
760
- className="aui-user-message-root fade-in slide-in-from-bottom-1 animate-in mx-auto grid w-full max-w-(--thread-max-width) auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2"
761
- data-role="user"
762
- >
763
- <UserMessageAttachments />
764
-
765
- <div className="aui-user-message-content-wrapper relative col-start-2 min-w-0">
766
- <div className="aui-user-message-content bg-muted text-foreground rounded-2xl px-4 py-2.5 wrap-break-word">
767
- <MessagePrimitive.Parts />
768
- </div>
769
- <div className="aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2">
770
- <UserActionBar />
771
- </div>
772
- </div>
773
-
774
- <BranchPicker className="aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
775
- </MessagePrimitive.Root>
776
- );
777
- };
778
-
779
- const UserActionBar: FC = () => {
780
- return (
781
- <ActionBarPrimitive.Root
782
- hideWhenRunning
783
- autohide="not-last"
784
- className="aui-user-action-bar-root flex flex-col items-end"
785
- >
786
- <ActionBarPrimitive.Edit asChild>
787
- <TooltipIconButton tooltip="Edit" className="aui-user-action-edit p-4">
788
- <PencilIcon />
789
- </TooltipIconButton>
790
- </ActionBarPrimitive.Edit>
791
- </ActionBarPrimitive.Root>
792
- );
793
- };
794
-
795
- const EditComposer: FC = () => {
796
- return (
797
- <MessagePrimitive.Root className="aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3">
798
- <ComposerPrimitive.Root className="aui-edit-composer-root bg-muted ml-auto flex w-full max-w-[85%] flex-col rounded-2xl">
799
- <ComposerPrimitive.Input
800
- className="aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent p-4 text-sm outline-none"
801
- autoFocus
802
- />
803
- <div className="aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end">
804
- <ComposerPrimitive.Cancel asChild>
805
- <Button variant="ghost" size="sm">
806
- Cancel
807
- </Button>
808
- </ComposerPrimitive.Cancel>
809
- <ComposerPrimitive.Send asChild>
810
- <Button size="sm">Update</Button>
811
- </ComposerPrimitive.Send>
812
- </div>
813
- </ComposerPrimitive.Root>
814
- </MessagePrimitive.Root>
815
- );
816
- };
817
-
818
- const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
819
- className,
820
- ...rest
821
- }) => {
822
- return (
823
- <BranchPickerPrimitive.Root
824
- hideWhenSingleBranch
825
- className={cn(
826
- "aui-branch-picker-root text-muted-foreground mr-2 -ml-2 inline-flex items-center text-xs",
827
- className,
828
- )}
829
- {...rest}
830
- >
831
- <BranchPickerPrimitive.Previous asChild>
832
- <TooltipIconButton tooltip="Previous">
833
- <ChevronLeftIcon />
834
- </TooltipIconButton>
835
- </BranchPickerPrimitive.Previous>
836
- <span className="aui-branch-picker-state font-medium">
837
- <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
838
- </span>
839
- <BranchPickerPrimitive.Next asChild>
840
- <TooltipIconButton tooltip="Next">
841
- <ChevronRightIcon />
842
- </TooltipIconButton>
843
- </BranchPickerPrimitive.Next>
844
- </BranchPickerPrimitive.Root>
845
- );
846
- };
847
-
848
- ```
849
-
850
304
  ## components/opencode-data-part.tsx
851
305
 
852
306
  ```tsx
@@ -1599,6 +1053,42 @@ AskQuestionInline.displayName = "AskQuestionInline";
1599
1053
 
1600
1054
  ```
1601
1055
 
1056
+ ## components/tools/opencode-tools.tsx
1057
+
1058
+ ```tsx
1059
+ "use client";
1060
+
1061
+ import {
1062
+ AskQuestionInline,
1063
+ withOpenCodeToolInteractions,
1064
+ } from "./opencode-tool-interactions";
1065
+ import { ApplyPatchDiff } from "./tool-ui-apply-patch";
1066
+ import { BashTerminal } from "./tool-ui-bash";
1067
+ import {
1068
+ EditInline,
1069
+ GlobInline,
1070
+ GrepInline,
1071
+ ReadInline,
1072
+ ToolCallFallback,
1073
+ WebFetchInline,
1074
+ WebSearchInline,
1075
+ WriteInline,
1076
+ } from "./tool-ui-inline";
1077
+
1078
+ export const ReadTool = withOpenCodeToolInteractions(ReadInline);
1079
+ export const EditTool = withOpenCodeToolInteractions(EditInline);
1080
+ export const WriteTool = withOpenCodeToolInteractions(WriteInline);
1081
+ export const BashTool = withOpenCodeToolInteractions(BashTerminal);
1082
+ export const GrepTool = withOpenCodeToolInteractions(GrepInline);
1083
+ export const GlobTool = withOpenCodeToolInteractions(GlobInline);
1084
+ export const WebSearchTool = withOpenCodeToolInteractions(WebSearchInline);
1085
+ export const WebFetchTool = withOpenCodeToolInteractions(WebFetchInline);
1086
+ export const ApplyPatchTool = withOpenCodeToolInteractions(ApplyPatchDiff);
1087
+ export const AskQuestionTool = withOpenCodeToolInteractions(AskQuestionInline);
1088
+ export const FallbackTool = withOpenCodeToolInteractions(ToolCallFallback);
1089
+
1090
+ ```
1091
+
1602
1092
  ## components/tools/reasoning-ghost.tsx
1603
1093
 
1604
1094
  ```tsx
@@ -2336,6 +1826,42 @@ export const ToolStatusIcon = ({
2336
1826
 
2337
1827
  ```
2338
1828
 
1829
+ ## components/tools/toolkit.tsx
1830
+
1831
+ ```tsx
1832
+ "use generative";
1833
+
1834
+ import { defineToolkit, externalTool } from "@assistant-ui/react";
1835
+ import {
1836
+ ApplyPatchTool,
1837
+ AskQuestionTool,
1838
+ BashTool,
1839
+ EditTool,
1840
+ GlobTool,
1841
+ GrepTool,
1842
+ ReadTool,
1843
+ WebFetchTool,
1844
+ WebSearchTool,
1845
+ WriteTool,
1846
+ } from "./opencode-tools";
1847
+
1848
+ export default defineToolkit({
1849
+ read: { execute: externalTool(), render: ReadTool },
1850
+ edit: { execute: externalTool(), render: EditTool },
1851
+ write: { execute: externalTool(), render: WriteTool },
1852
+ bash: { execute: externalTool(), render: BashTool },
1853
+ grep: { execute: externalTool(), render: GrepTool },
1854
+ glob: { execute: externalTool(), render: GlobTool },
1855
+ webSearch: { execute: externalTool(), render: WebSearchTool },
1856
+ webFetch: { execute: externalTool(), render: WebFetchTool },
1857
+ apply_patch: { execute: externalTool(), render: ApplyPatchTool },
1858
+ ask_question: { execute: externalTool(), render: AskQuestionTool },
1859
+ request_user_input: { execute: externalTool(), render: AskQuestionTool },
1860
+ requestUserInput: { execute: externalTool(), render: AskQuestionTool },
1861
+ });
1862
+
1863
+ ```
1864
+
2339
1865
  ## next.config.ts
2340
1866
 
2341
1867
  ```typescript
@@ -2368,11 +1894,11 @@ export default withAui(nextConfig);
2368
1894
  "@assistant-ui/react-markdown": "workspace:*",
2369
1895
  "@assistant-ui/react-opencode": "workspace:*",
2370
1896
  "@assistant-ui/ui": "workspace:*",
2371
- "@pierre/diffs": "^1.2.7",
1897
+ "@pierre/diffs": "^1.2.10",
2372
1898
  "class-variance-authority": "^0.7.1",
2373
1899
  "clsx": "^2.1.1",
2374
- "lucide-react": "^1.17.0",
2375
- "next": "^16.2.7",
1900
+ "lucide-react": "^1.18.0",
1901
+ "next": "^16.2.9",
2376
1902
  "react": "^19.2.7",
2377
1903
  "react-dom": "^19.2.7",
2378
1904
  "tailwind-merge": "^3.6.0",
@@ -2381,12 +1907,12 @@ export default withAui(nextConfig);
2381
1907
  "devDependencies": {
2382
1908
  "@assistant-ui/next": "workspace:*",
2383
1909
  "@assistant-ui/x-buildutils": "workspace:*",
2384
- "@tailwindcss/postcss": "^4.3.0",
2385
- "@types/node": "^25.9.2",
1910
+ "@tailwindcss/postcss": "^4.3.1",
1911
+ "@types/node": "^25.9.3",
2386
1912
  "@types/react": "^19.2.17",
2387
1913
  "@types/react-dom": "^19.2.3",
2388
1914
  "postcss": "^8.5.15",
2389
- "tailwindcss": "^4.3.0",
1915
+ "tailwindcss": "^4.3.1",
2390
1916
  "tw-animate-css": "^1.4.0",
2391
1917
  "typescript": "^6.0.3"
2392
1918
  }