@assistant-ui/mcp-docs-server 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.docs/organized/code-examples/waterfall.md +15 -7
  2. package/.docs/organized/code-examples/with-a2a.md +8 -20
  3. package/.docs/organized/code-examples/with-ag-ui.md +9 -6
  4. package/.docs/organized/code-examples/with-ai-sdk-v6.md +8 -8
  5. package/.docs/organized/code-examples/with-artifacts.md +10 -8
  6. package/.docs/organized/code-examples/with-assistant-transport.md +9 -10
  7. package/.docs/organized/code-examples/with-chain-of-thought.md +7 -7
  8. package/.docs/organized/code-examples/with-cloud-standalone.md +13 -10
  9. package/.docs/organized/code-examples/with-cloud.md +8 -9
  10. package/.docs/organized/code-examples/with-custom-thread-list.md +8 -8
  11. package/.docs/organized/code-examples/with-elevenlabs-conversational.md +15 -10
  12. package/.docs/organized/code-examples/with-elevenlabs-scribe.md +11 -11
  13. package/.docs/organized/code-examples/with-expo.md +20 -16
  14. package/.docs/organized/code-examples/with-external-store.md +7 -7
  15. package/.docs/organized/code-examples/with-ffmpeg.md +15 -10
  16. package/.docs/organized/code-examples/with-generative-ui.md +7 -7
  17. package/.docs/organized/code-examples/with-google-adk.md +6 -6
  18. package/.docs/organized/code-examples/with-heat-graph.md +5 -5
  19. package/.docs/organized/code-examples/with-interactables.md +8 -23
  20. package/.docs/organized/code-examples/with-langchain.md +437 -0
  21. package/.docs/organized/code-examples/with-langgraph.md +15 -15
  22. package/.docs/organized/code-examples/with-livekit.md +15 -10
  23. package/.docs/organized/code-examples/with-opencode.md +8 -10
  24. package/.docs/organized/code-examples/with-parent-id-grouping.md +8 -8
  25. package/.docs/organized/code-examples/with-react-hook-form.md +219 -147
  26. package/.docs/organized/code-examples/with-react-ink.md +2 -2
  27. package/.docs/organized/code-examples/with-react-router.md +10 -10
  28. package/.docs/organized/code-examples/with-store.md +8 -5
  29. package/.docs/organized/code-examples/with-tanstack.md +8 -8
  30. package/.docs/organized/code-examples/with-tap-runtime.md +9 -5
  31. package/.docs/raw/docs/(docs)/guides/mentions.mdx +248 -109
  32. package/.docs/raw/docs/(docs)/guides/slash-commands.mdx +112 -92
  33. package/.docs/raw/docs/(docs)/rtl.mdx +79 -0
  34. package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +149 -40
  35. package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +2 -0
  36. package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +4 -0
  37. package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +1 -1
  38. package/.docs/raw/docs/primitives/composer.mdx +94 -62
  39. package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +57 -0
  40. package/.docs/raw/docs/runtimes/custom/custom-thread-list.mdx +47 -1
  41. package/.docs/raw/docs/runtimes/custom/external-store.mdx +1 -1
  42. package/.docs/raw/docs/runtimes/langchain/comparison.mdx +60 -0
  43. package/.docs/raw/docs/runtimes/langchain/index.mdx +210 -0
  44. package/.docs/raw/docs/runtimes/langgraph/index.mdx +155 -63
  45. package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +12 -4
  46. package/.docs/raw/docs/ui/composer-trigger-popover.mdx +199 -0
  47. package/.docs/raw/docs/ui/directive-text.mdx +113 -0
  48. package/.docs/raw/docs/ui/reasoning.mdx +13 -9
  49. package/dist/utils/logger.js +1 -1
  50. package/dist/utils/logger.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/utils/logger.ts +1 -1
  53. package/.docs/raw/docs/ui/mention.mdx +0 -168
@@ -416,76 +416,124 @@ import { AuiIf } from "@assistant-ui/react";
416
416
  </AuiIf>
417
417
  ```
418
418
 
419
- ## Mention Primitives (Unstable)
419
+ ## Trigger Popover Primitives (Unstable)
420
420
 
421
421
  <Callout type="warn">
422
422
  These primitives are under the `Unstable_` prefix and may change without notice.
423
423
  </Callout>
424
424
 
425
- Primitives for an @-mention picker in the composer. See the [Mention component guide](/docs/ui/mention) for a pre-built implementation.
425
+ Unified primitives for any character-triggered popover (`@` mentions, `/` slash commands, `:` emoji, etc.). Multiple triggers coexist under a single `TriggerPopoverRoot`. See the [Mentions guide](/docs/guides/mentions) and [Slash Commands guide](/docs/guides/slash-commands) for full documentation and the [ComposerTriggerPopover component](/docs/ui/composer-trigger-popover) for a pre-built implementation.
426
426
 
427
427
  ### Anatomy
428
428
 
429
429
  ```tsx
430
430
  import { ComposerPrimitive } from "@assistant-ui/react";
431
+ import { unstable_defaultDirectiveFormatter } from "@assistant-ui/core";
431
432
 
432
433
  const Composer = () => (
433
- <ComposerPrimitive.Unstable_MentionRoot adapter={mentionAdapter}>
434
+ <ComposerPrimitive.Unstable_TriggerPopoverRoot>
434
435
  <ComposerPrimitive.Root>
435
436
  <ComposerPrimitive.Input />
436
- <ComposerPrimitive.Unstable_MentionPopover>
437
- <ComposerPrimitive.Unstable_MentionCategories>
437
+
438
+ <ComposerPrimitive.Unstable_TriggerPopover
439
+ char="@"
440
+ adapter={mention.adapter}
441
+ >
442
+ <ComposerPrimitive.Unstable_TriggerPopover.Directive
443
+ {...mention.directive}
444
+ />
445
+ <ComposerPrimitive.Unstable_TriggerPopoverCategories>
438
446
  {(categories) =>
439
447
  categories.map((cat) => (
440
- <ComposerPrimitive.Unstable_MentionCategoryItem
448
+ <ComposerPrimitive.Unstable_TriggerPopoverCategoryItem
441
449
  key={cat.id}
442
450
  categoryId={cat.id}
443
451
  >
444
452
  {cat.label}
445
- </ComposerPrimitive.Unstable_MentionCategoryItem>
453
+ </ComposerPrimitive.Unstable_TriggerPopoverCategoryItem>
446
454
  ))
447
455
  }
448
- </ComposerPrimitive.Unstable_MentionCategories>
449
- <ComposerPrimitive.Unstable_MentionItems>
456
+ </ComposerPrimitive.Unstable_TriggerPopoverCategories>
457
+ <ComposerPrimitive.Unstable_TriggerPopoverItems>
450
458
  {(items) =>
451
459
  items.map((item) => (
452
- <ComposerPrimitive.Unstable_MentionItem
460
+ <ComposerPrimitive.Unstable_TriggerPopoverItem
453
461
  key={item.id}
454
462
  item={item}
455
463
  >
456
464
  {item.label}
457
- </ComposerPrimitive.Unstable_MentionItem>
465
+ </ComposerPrimitive.Unstable_TriggerPopoverItem>
458
466
  ))
459
467
  }
460
- </ComposerPrimitive.Unstable_MentionItems>
461
- <ComposerPrimitive.Unstable_MentionBack>
468
+ </ComposerPrimitive.Unstable_TriggerPopoverItems>
469
+ <ComposerPrimitive.Unstable_TriggerPopoverBack>
462
470
  Back
463
- </ComposerPrimitive.Unstable_MentionBack>
464
- </ComposerPrimitive.Unstable_MentionPopover>
471
+ </ComposerPrimitive.Unstable_TriggerPopoverBack>
472
+ </ComposerPrimitive.Unstable_TriggerPopover>
465
473
  </ComposerPrimitive.Root>
466
- </ComposerPrimitive.Unstable_MentionRoot>
474
+ </ComposerPrimitive.Unstable_TriggerPopoverRoot>
467
475
  );
468
476
  ```
469
477
 
470
- ### Unstable_MentionRoot
478
+ ### Unstable_TriggerPopoverRoot
479
+
480
+ Root provider that groups one or more `TriggerPopover` declarations. Owns the shared `ComposerInputPluginRegistry` that routes cursor and keyboard events to each registered trigger.
481
+
482
+ No props.
483
+
484
+ ### Unstable_TriggerPopover
485
+
486
+ Declares a trigger and renders its popover container. Only renders its DOM (and children) while this trigger is active in the composer input. Each declaration has an isolated scope — sub-primitives placed inside read state from this declaration only.
487
+
488
+ | Prop | Type | Default | Description |
489
+ | --- | --- | --- | --- |
490
+ | `char` | `string` | — | Character(s) that activate the trigger (e.g. `"@"`, `"/"`) — unique within the root |
491
+ | `adapter` | `Unstable_TriggerAdapter` | — | Provides categories, items, and search |
492
+
493
+ Selection behavior is declared by rendering **exactly one** behavior sub-primitive inside the `TriggerPopover`:
494
+
495
+ - [`Unstable_TriggerPopover.Directive`](#unstable_triggerpopoverdirective) — inserts `:type[label]{name=id}` into the composer on selection (mention behavior).
496
+ - [`Unstable_TriggerPopover.Action`](#unstable_triggerpopoveraction) — fires `onExecute` on selection; leaves a directive chip as an audit trail by default.
497
+
498
+ Renders a `<div>` with `role="listbox"` when open.
499
+
500
+ ### Unstable_TriggerPopover.Directive
501
+
502
+ Behavior sub-primitive. Placed inside a `<Unstable_TriggerPopover>`. Renders nothing — registers an `"directive"` behavior with its parent. Exactly one behavior sub-primitive is allowed per `TriggerPopover`.
503
+
504
+ | Prop | Type | Default | Description |
505
+ | --- | --- | --- | --- |
506
+ | `formatter` | `Unstable_DirectiveFormatter` | `unstable_defaultDirectiveFormatter` | Serializes the selected item into composer text (and parses it back). |
507
+ | `onInserted` | `(item) => void` | — | Fires after the directive text has been inserted. |
508
+
509
+ ### Unstable_TriggerPopover.Action
471
510
 
472
- Provider that wraps the composer with mention trigger detection, keyboard navigation, and popover state.
511
+ Behavior sub-primitive. Placed inside a `<Unstable_TriggerPopover>`. Renders nothing — registers an `"action"` behavior with its parent. Exactly one behavior sub-primitive is allowed per `TriggerPopover`.
473
512
 
474
513
  | Prop | Type | Default | Description |
475
514
  | --- | --- | --- | --- |
476
- | `adapter` | `Unstable_MentionAdapter` | — | Provides categories, items, and search |
477
- | `trigger` | `string` | `"@"` | Character(s) that activate the popover |
478
- | `formatter` | `Unstable_DirectiveFormatter` | Default | Serializer/parser for mention directives |
515
+ | `formatter` | `Unstable_DirectiveFormatter` | `unstable_defaultDirectiveFormatter` | Serializes the audit-trail chip (unused when `removeOnExecute` is true). |
516
+ | `onExecute` | `(item) => void` | — | Called the moment an item is selected — typically routes to a handler map. Required. |
517
+ | `removeOnExecute` | `boolean` | `false` | When `true`, strips the trigger text from the composer instead of leaving a chip. |
479
518
 
480
- ### Unstable_MentionPopover
519
+ ### Unstable_TriggerBehavior
481
520
 
482
- Container that only renders when a mention trigger is active. Renders a `<div>` with `role="listbox"`.
521
+ Union type returned by the two behavior sub-primitives and consumed internally by the popover resources. Exported for advanced use cases (e.g. custom sub-primitives).
483
522
 
484
- ### Unstable_MentionCategories
523
+ ```ts
524
+ import type { Unstable_TriggerBehavior } from "@assistant-ui/react";
525
+
526
+ // Equivalent shape:
527
+ // Unstable_TriggerBehavior =
528
+ // | { kind: "directive"; formatter: Unstable_DirectiveFormatter; onInserted?: (item) => void }
529
+ // | { kind: "action"; formatter: Unstable_DirectiveFormatter; onExecute: (item) => void; removeOnExecute?: boolean }
530
+ ```
531
+
532
+ ### Unstable_TriggerPopoverCategories
485
533
 
486
534
  Renders the top-level category list. Accepts a render function `(categories) => ReactNode`. Hidden when a category is selected or when in search mode.
487
535
 
488
- ### Unstable_MentionCategoryItem
536
+ ### Unstable_TriggerPopoverCategoryItem
489
537
 
490
538
  A button that drills into a category. Renders `role="option"` with automatic `data-highlighted` and `aria-selected` when keyboard-navigated.
491
539
 
@@ -493,25 +541,26 @@ A button that drills into a category. Renders `role="option"` with automatic `da
493
541
  | --- | --- | --- |
494
542
  | `categoryId` | `string` | The category to select on click |
495
543
 
496
- ### Unstable_MentionItems
544
+ ### Unstable_TriggerPopoverItems
497
545
 
498
546
  Renders the item list for the active category or search results. Accepts a render function `(items) => ReactNode`. Hidden when no category is selected and not in search mode.
499
547
 
500
- ### Unstable_MentionItem
548
+ ### Unstable_TriggerPopoverItem
501
549
 
502
- A button that inserts a mention into the composer. Renders `role="option"` with automatic `data-highlighted` and `aria-selected` when keyboard-navigated.
550
+ A button that selects an item. Renders `role="option"` with automatic `data-highlighted` and `aria-selected` when keyboard-navigated.
503
551
 
504
552
  | Prop | Type | Description |
505
553
  | --- | --- | --- |
506
- | `item` | `Unstable_MentionItem` | The item to insert on click |
554
+ | `item` | `Unstable_TriggerItem` | The item to select on click |
555
+ | `index` | `number` | Optional index override for highlight matching |
507
556
 
508
- ### Unstable_MentionBack
557
+ ### Unstable_TriggerPopoverBack
509
558
 
510
559
  A button that navigates back from items to the category list. Only renders when a category is active.
511
560
 
512
- ### unstable_useMentionContext
561
+ ### unstable_useTriggerPopoverScopeContext
513
562
 
514
- Hook to access the mention popover state and actions from within `Unstable_MentionRoot`.
563
+ Hook to access the popover state and actions for the nearest enclosing `Unstable_TriggerPopover`.
515
564
 
516
565
  ```tsx
517
566
  const {
@@ -527,19 +576,79 @@ const {
527
576
  goBack,
528
577
  close,
529
578
  handleKeyDown,
530
- formatter,
531
- } = unstable_useMentionContext();
579
+ } = unstable_useTriggerPopoverScopeContext();
532
580
  ```
533
581
 
534
- ### unstable_useToolMentionAdapter
582
+ ### unstable_useTriggerPopoverTriggers
583
+
584
+ Hook to iterate every trigger registered under the current `Unstable_TriggerPopoverRoot`. Intended for input-level integrations (e.g. Lexical `DirectivePlugin`). Returns `ReadonlyMap<string, Unstable_RegisteredTrigger>`.
585
+
586
+ ### unstable_useMentionAdapter
535
587
 
536
- Hook that creates a `Unstable_MentionAdapter` from registered tools (via `useAssistantTool`).
588
+ Returns a spreadable `{ adapter, directive }` bundle for `@` mentions. Reads tools registered via `useAssistantTool`, accepts explicit `items`, and supports multi-category drill-down.
537
589
 
538
590
  ```tsx
539
- import { unstable_useToolMentionAdapter } from "@assistant-ui/react";
591
+ import {
592
+ unstable_useMentionAdapter,
593
+ type Unstable_Mention,
594
+ } from "@assistant-ui/react";
595
+
596
+ function MyComposer() {
597
+ // Default: tools from model context as a single "Tools" category
598
+ const mention = unstable_useMentionAdapter();
599
+
600
+ return (
601
+ <ComposerTriggerPopover char="@" {...mention} />
602
+ );
603
+ }
604
+ ```
540
605
 
541
- const adapter = unstable_useToolMentionAdapter({
542
- formatLabel: (name) => name.replaceAll("_", " "),
543
- categoryLabel: "Tools",
606
+ ```tsx
607
+ // Multi-category + tools appended as their own category
608
+ const mention = unstable_useMentionAdapter({
609
+ categories: [
610
+ { id: "users", label: "Users", items: [/* ... */] },
611
+ { id: "files", label: "Files", items: [/* ... */] },
612
+ ],
613
+ includeModelContextTools: true,
544
614
  });
545
615
  ```
616
+
617
+ Options:
618
+
619
+ | Option | Type | Description |
620
+ | --- | --- | --- |
621
+ | `items` | `Unstable_Mention[]` | Flat list; ignored when `categories` is set. |
622
+ | `categories` | `{ id, label, items: Unstable_Mention[] }[]` | Drill-down groups. |
623
+ | `includeModelContextTools` | `boolean \| { category?, formatLabel?, icon? }` | Tools integration. Defaults to `true` iff neither `items` nor `categories`. |
624
+ | `formatter` | `Unstable_DirectiveFormatter` | Override directive serialization. |
625
+ | `onInserted` | `(item) => void` | Fires after the directive is inserted. |
626
+ | `iconMap` | `Record<string, Unstable_IconComponent>` | `metadata.icon` / category id → React component. |
627
+ | `fallbackIcon` | `Unstable_IconComponent` | Fallback when no `iconMap` entry matches. |
628
+
629
+ Returns `{ adapter, directive, iconMap?, fallbackIcon? }`.
630
+
631
+ ### unstable_useSlashCommandAdapter
632
+
633
+ Returns a spreadable `{ adapter, action }` bundle for slash commands. Commands are declared as data + inline `execute` callbacks; `execute` lives in the hook closure and is never attached to the returned `Unstable_TriggerItem`, keeping items JSON-serializable.
634
+
635
+ ```tsx
636
+ import {
637
+ unstable_useSlashCommandAdapter,
638
+ type Unstable_SlashCommand,
639
+ } from "@assistant-ui/react";
640
+
641
+ const SLASH_COMMANDS: readonly Unstable_SlashCommand[] = [
642
+ { id: "summarize", execute: () => runSummarize(), icon: "FileText" },
643
+ { id: "translate", execute: () => runTranslate(), icon: "Languages" },
644
+ ];
645
+
646
+ function MyComposer() {
647
+ const slash = unstable_useSlashCommandAdapter({ commands: SLASH_COMMANDS });
648
+ return (
649
+ <ComposerTriggerPopover char="/" {...slash} />
650
+ );
651
+ }
652
+ ```
653
+
654
+ Pass `removeOnExecute: true` on the hook options to strip the trigger text from the composer after executing. The hook also accepts `iconMap` / `fallbackIcon` options that flow into the returned bundle — `{...slash}` spreads them into `ComposerTriggerPopover`.
@@ -187,6 +187,8 @@ function MyComponent() {
187
187
 
188
188
  Each data component receives the full data part as props: `{ type: "data", name: string, data: T, status: MessagePartStatus }`.
189
189
 
190
+ For a catch-all renderer (e.g. LangSmith's [`LoadExternalComponent`](/docs/runtimes/langgraph#dynamic-loading-with-fallback) loaded at runtime), pass `Fallback` via the inline `data` config on `MessagePrimitive.Parts`, or use the LangGraph adapter's [`uiComponents.fallback`](/docs/runtimes/langgraph#dynamic-loading-with-fallback) option.
191
+
190
192
  ### Messages (Sub-Agent)
191
193
 
192
194
  Renders nested messages from a tool call part's `messages` field. This is used in multi-agent setups where a sub-agent's conversation is embedded inside a tool call.
@@ -18,6 +18,10 @@ const aui = useAui();
18
18
  await aui.threads().switchToNewThread();
19
19
  await aui.threads().switchToThread(threadId);
20
20
 
21
+ // Re-fetch the thread list from the remote adapter
22
+ // (e.g. after async auth completes)
23
+ await aui.threads().reload();
24
+
21
25
  // Access the main thread runtime
22
26
  const mainThread = aui.threads().main;
23
27
 
@@ -166,7 +166,7 @@ export default function ChatPage() {
166
166
  name: "history",
167
167
  type: "ThreadHistoryAdapter",
168
168
  description:
169
- "Adapter for loading and saving thread history. Used to restore previous messages when switching threads.",
169
+ "Adapter for loading and saving thread history. Used to restore previous messages when switching threads. The adapter must implement `withFormat` when used with AI SDK — see [Persisting Chat History](/docs/runtimes/ai-sdk/v6#persisting-chat-history).",
170
170
  },
171
171
  ],
172
172
  },
@@ -104,26 +104,31 @@ The primitive's behavior (keyboard handling, disabled state, form submission) is
104
104
 
105
105
  ### Unstable Trigger Popovers
106
106
 
107
- Composer includes an unstable **trigger popover** system for character-triggered popovers (e.g. `@` for mentions, `/` for slash commands). Multiple triggers can coexist on the same input.
108
-
109
- **Mentions** (`@` trigger) — insert directive text into the message:
107
+ Composer includes an unstable **trigger popover** system for character-triggered popovers (e.g. `@` for mentions, `/` for slash commands). Multiple triggers coexist under a single `TriggerPopoverRoot`.
110
108
 
111
109
  ```tsx
112
- <ComposerPrimitive.Unstable_MentionRoot adapter={mentionAdapter}>
110
+ <ComposerPrimitive.Unstable_TriggerPopoverRoot>
113
111
  <ComposerPrimitive.Root>
114
- <ComposerPrimitive.Input placeholder="Type @ to mention..." />
115
- <ComposerPrimitive.Unstable_MentionPopover />
116
- </ComposerPrimitive.Root>
117
- </ComposerPrimitive.Unstable_MentionRoot>
118
- ```
119
-
120
- **Slash commands** (`/` trigger) — execute an action and clear the command text:
112
+ <ComposerPrimitive.Input placeholder="Type @ to mention, / for commands..." />
121
113
 
122
- ```tsx
123
- <ComposerPrimitive.Unstable_SlashCommandRoot adapter={slashAdapter}>
124
- <ComposerPrimitive.Root>
125
- <ComposerPrimitive.Input placeholder="Type / for commands..." />
126
- <ComposerPrimitive.Unstable_TriggerPopoverPopover>
114
+ {/* @ mention — inserts directive text into the message */}
115
+ <ComposerPrimitive.Unstable_TriggerPopover
116
+ char="@"
117
+ adapter={mentionAdapter}
118
+ >
119
+ <ComposerPrimitive.Unstable_TriggerPopover.Directive formatter={formatter} />
120
+ {/* popover UI */}
121
+ </ComposerPrimitive.Unstable_TriggerPopover>
122
+
123
+ {/* / slash command — runs a handler on selection; leaves an audit-trail chip by default */}
124
+ <ComposerPrimitive.Unstable_TriggerPopover
125
+ char="/"
126
+ adapter={slashAdapter}
127
+ >
128
+ <ComposerPrimitive.Unstable_TriggerPopover.Action
129
+ formatter={formatter}
130
+ onExecute={(item) => commandHandlers[item.id]?.()}
131
+ />
127
132
  <ComposerPrimitive.Unstable_TriggerPopoverItems>
128
133
  {(items) => items.map(item => (
129
134
  <ComposerPrimitive.Unstable_TriggerPopoverItem key={item.id} item={item}>
@@ -131,9 +136,9 @@ Composer includes an unstable **trigger popover** system for character-triggered
131
136
  </ComposerPrimitive.Unstable_TriggerPopoverItem>
132
137
  ))}
133
138
  </ComposerPrimitive.Unstable_TriggerPopoverItems>
134
- </ComposerPrimitive.Unstable_TriggerPopoverPopover>
139
+ </ComposerPrimitive.Unstable_TriggerPopover>
135
140
  </ComposerPrimitive.Root>
136
- </ComposerPrimitive.Unstable_SlashCommandRoot>
141
+ </ComposerPrimitive.Unstable_TriggerPopoverRoot>
137
142
  ```
138
143
 
139
144
  See the [Mentions guide](/docs/guides/mentions) and [Slash Commands guide](/docs/guides/slash-commands) for full documentation.
@@ -313,103 +318,130 @@ Clears the active quote from the composer. Renders a `<button>` element unless `
313
318
  </ComposerPrimitive.QuoteDismiss>
314
319
  ```
315
320
 
316
- ### Unstable_MentionRoot
321
+ ### Unstable_TriggerPopoverRoot
317
322
 
318
- Provider that manages mention state and `@` trigger detection.
323
+ Root provider that groups one or more `TriggerPopover` declarations and owns the shared input plugin registry.
319
324
 
320
325
  ```tsx
321
- <ComposerPrimitive.Unstable_MentionRoot trigger="@" adapter={mentionAdapter}>
326
+ <ComposerPrimitive.Unstable_TriggerPopoverRoot>
322
327
  <ComposerPrimitive.Root>
323
- <LexicalComposerInput placeholder="Type @ to mention a tool..." />
324
- <ComposerPrimitive.Unstable_MentionPopover />
328
+ <LexicalComposerInput placeholder="Type @ to mention, / for commands..." />
329
+ <ComposerPrimitive.Unstable_TriggerPopover char="@" adapter={mentionAdapter}>
330
+ <ComposerPrimitive.Unstable_TriggerPopover.Directive formatter={formatter} />
331
+ ...
332
+ </ComposerPrimitive.Unstable_TriggerPopover>
325
333
  </ComposerPrimitive.Root>
326
- </ComposerPrimitive.Unstable_MentionRoot>
334
+ </ComposerPrimitive.Unstable_TriggerPopoverRoot>
327
335
  ```
328
336
 
329
- <PrimitivesTypeTable type="ComposerPrimitiveMentionRootProps" parameters={ComposerPrimitiveDocs.Unstable_MentionRoot.props} />
337
+ ### Unstable_TriggerPopover
330
338
 
331
- ### Unstable_MentionPopover
332
-
333
- Container for the mention picker popover. It only renders while a trigger match is active.
339
+ Declares a trigger (by `char`, `adapter`) and renders the popover container. Selection behavior is declared by rendering exactly one behavior sub-primitive inside — either `<Unstable_TriggerPopover.Directive>` (insert a directive on selection) or `<Unstable_TriggerPopover.Action>` (run `onExecute` on selection). Only renders its DOM (and children) while the trigger is active in the composer input.
334
340
 
335
341
  ```tsx
336
- <ComposerPrimitive.Unstable_MentionPopover className="rounded-lg border bg-popover p-1 shadow-md">
337
- <ComposerPrimitive.Unstable_MentionCategories>
342
+ <ComposerPrimitive.Unstable_TriggerPopover
343
+ char="@"
344
+ adapter={mentionAdapter}
345
+ className="rounded-lg border bg-popover p-1 shadow-md"
346
+ >
347
+ <ComposerPrimitive.Unstable_TriggerPopover.Directive formatter={formatter} />
348
+ <ComposerPrimitive.Unstable_TriggerPopoverCategories>
338
349
  {(categories) => categories.map((category) => (
339
- <ComposerPrimitive.Unstable_MentionCategoryItem
350
+ <ComposerPrimitive.Unstable_TriggerPopoverCategoryItem
340
351
  key={category.id}
341
352
  categoryId={category.id}
342
353
  >
343
354
  {category.label}
344
- </ComposerPrimitive.Unstable_MentionCategoryItem>
355
+ </ComposerPrimitive.Unstable_TriggerPopoverCategoryItem>
345
356
  ))}
346
- </ComposerPrimitive.Unstable_MentionCategories>
347
- </ComposerPrimitive.Unstable_MentionPopover>
357
+ </ComposerPrimitive.Unstable_TriggerPopoverCategories>
358
+ </ComposerPrimitive.Unstable_TriggerPopover>
359
+ ```
360
+
361
+ Behavior is supplied by exactly one of two sub-primitives:
362
+
363
+ - `<Unstable_TriggerPopover.Directive formatter={...} onInserted={...} />` — writes `:type[label]{name=id}` into the composer text (mention behavior)
364
+ - `<Unstable_TriggerPopover.Action onExecute={...} removeOnExecute={...} />` — runs a callback on selection; leaves a directive chip behind by default (slash-command behavior)
365
+
366
+ ### Unstable_TriggerPopover.Directive
367
+
368
+ Behavior sub-primitive. Registers the directive-insert behavior with its parent `TriggerPopover`. Renders nothing.
369
+
370
+ ```tsx
371
+ <ComposerPrimitive.Unstable_TriggerPopover.Directive
372
+ formatter={unstable_defaultDirectiveFormatter}
373
+ onInserted={(item) => track("mention", item.id)}
374
+ />
375
+ ```
376
+
377
+ ### Unstable_TriggerPopover.Action
378
+
379
+ Behavior sub-primitive. Registers the action behavior with its parent `TriggerPopover`. Renders nothing. By default leaves a directive chip behind after executing (audit trail); pass `removeOnExecute` to strip the trigger text entirely.
380
+
381
+ ```tsx
382
+ <ComposerPrimitive.Unstable_TriggerPopover.Action
383
+ onExecute={(item) => commandHandlers[item.id]?.()}
384
+ removeOnExecute={false}
385
+ />
348
386
  ```
349
387
 
350
- ### Unstable_MentionCategories
388
+ ### Unstable_TriggerPopoverCategories
351
389
 
352
- Render-function primitive for the top-level mention categories.
390
+ Render-function primitive for the top-level category list. Only renders while no category is active and search mode is off.
353
391
 
354
392
  ```tsx
355
- <ComposerPrimitive.Unstable_MentionCategories>
393
+ <ComposerPrimitive.Unstable_TriggerPopoverCategories>
356
394
  {(categories) => categories.map((category) => (
357
- <ComposerPrimitive.Unstable_MentionCategoryItem
395
+ <ComposerPrimitive.Unstable_TriggerPopoverCategoryItem
358
396
  key={category.id}
359
397
  categoryId={category.id}
360
398
  >
361
399
  {category.label}
362
- </ComposerPrimitive.Unstable_MentionCategoryItem>
400
+ </ComposerPrimitive.Unstable_TriggerPopoverCategoryItem>
363
401
  ))}
364
- </ComposerPrimitive.Unstable_MentionCategories>
402
+ </ComposerPrimitive.Unstable_TriggerPopoverCategories>
365
403
  ```
366
404
 
367
- <PrimitivesTypeTable type="ComposerPrimitiveMentionCategoriesProps" parameters={ComposerPrimitiveDocs.Unstable_MentionCategories.props} />
405
+ ### Unstable_TriggerPopoverCategoryItem
368
406
 
369
- ### Unstable_MentionCategoryItem
370
-
371
- Button that selects a mention category and drills into its items.
407
+ Button that selects a category and drills into its items.
372
408
 
373
409
  ```tsx
374
- <ComposerPrimitive.Unstable_MentionCategoryItem categoryId="tools">
410
+ <ComposerPrimitive.Unstable_TriggerPopoverCategoryItem categoryId="tools">
375
411
  Tools
376
- </ComposerPrimitive.Unstable_MentionCategoryItem>
412
+ </ComposerPrimitive.Unstable_TriggerPopoverCategoryItem>
377
413
  ```
378
414
 
379
- ### Unstable_MentionItems
415
+ ### Unstable_TriggerPopoverItems
380
416
 
381
- Render-function primitive for the items inside the currently selected category.
417
+ Render-function primitive for the items inside the currently selected category (or global search results).
382
418
 
383
419
  ```tsx
384
- <ComposerPrimitive.Unstable_MentionItems>
420
+ <ComposerPrimitive.Unstable_TriggerPopoverItems>
385
421
  {(items) => items.map((item) => (
386
- <ComposerPrimitive.Unstable_MentionItem key={item.id} item={item} />
422
+ <ComposerPrimitive.Unstable_TriggerPopoverItem key={item.id} item={item} />
387
423
  ))}
388
- </ComposerPrimitive.Unstable_MentionItems>
424
+ </ComposerPrimitive.Unstable_TriggerPopoverItems>
389
425
  ```
390
426
 
391
- <PrimitivesTypeTable type="ComposerPrimitiveMentionItemsProps" parameters={ComposerPrimitiveDocs.Unstable_MentionItems.props} />
392
-
393
- ### Unstable_MentionItem
427
+ ### Unstable_TriggerPopoverItem
394
428
 
395
- Selectable mention item inside the popover.
429
+ Selectable item inside the popover.
396
430
 
397
431
  ```tsx
398
- <ComposerPrimitive.Unstable_MentionItem item={item}>
432
+ <ComposerPrimitive.Unstable_TriggerPopoverItem item={item}>
399
433
  {item.label}
400
- </ComposerPrimitive.Unstable_MentionItem>
434
+ </ComposerPrimitive.Unstable_TriggerPopoverItem>
401
435
  ```
402
436
 
403
- <PrimitivesTypeTable type="ComposerPrimitiveMentionItemProps" parameters={ComposerPrimitiveDocs.Unstable_MentionItem.props} />
404
-
405
- ### Unstable_MentionBack
437
+ ### Unstable_TriggerPopoverBack
406
438
 
407
439
  Back button used when drilling from categories into a specific item list.
408
440
 
409
441
  ```tsx
410
- <ComposerPrimitive.Unstable_MentionBack className="rounded-md px-2 py-1 text-sm hover:bg-accent">
442
+ <ComposerPrimitive.Unstable_TriggerPopoverBack className="rounded-md px-2 py-1 text-sm hover:bg-accent">
411
443
  Back
412
- </ComposerPrimitive.Unstable_MentionBack>
444
+ </ComposerPrimitive.Unstable_TriggerPopoverBack>
413
445
  ```
414
446
 
415
447
  ## Patterns
@@ -154,6 +154,63 @@ export function TokenCounter() {
154
154
  </Step>
155
155
  </Steps>
156
156
 
157
+ ## Persisting Chat History
158
+
159
+ By default, messages live only in memory and reset on reload. To persist and restore history per thread, provide a `ThreadHistoryAdapter` via `adapters.history`.
160
+
161
+ <Callout type="warn">
162
+ The adapter **must** implement `withFormat`. `useChatRuntime` persists history through `withFormat(fmt)` so messages round-trip as AI SDK `UIMessage` objects. An adapter without `withFormat` throws at runtime — `load` / `append` on the top level are unused in the AI SDK path.
163
+ </Callout>
164
+
165
+ <Callout type="info">
166
+ For server-side cloud persistence with zero adapter code, see the [AssistantCloud integration](/docs/cloud/ai-sdk-assistant-ui).
167
+ </Callout>
168
+
169
+ ### Example
170
+
171
+ ```tsx
172
+ "use client";
173
+
174
+ import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
175
+ import type { ThreadHistoryAdapter } from "@assistant-ui/react";
176
+
177
+ const historyAdapter: ThreadHistoryAdapter = {
178
+ // Required by the type — unused by useChatRuntime.
179
+ async load() {
180
+ return { headId: null, messages: [] };
181
+ },
182
+ async append() {},
183
+
184
+ // `fmt` encodes UIMessage ↔ storage rows (ai-sdk/v6 format).
185
+ withFormat: (fmt) => ({
186
+ async load() {
187
+ const rows = await fetch("/api/history").then((r) => r.json());
188
+ return { messages: rows.map(fmt.decode) };
189
+ },
190
+ async append(item) {
191
+ await fetch("/api/history", {
192
+ method: "POST",
193
+ body: JSON.stringify({
194
+ id: fmt.getId(item.message),
195
+ parent_id: item.parentId,
196
+ format: fmt.format,
197
+ content: fmt.encode(item),
198
+ }),
199
+ });
200
+ },
201
+ }),
202
+ };
203
+
204
+ function Chat() {
205
+ const runtime = useChatRuntime({
206
+ adapters: { history: historyAdapter },
207
+ });
208
+ // ...
209
+ }
210
+ ```
211
+
212
+ Each persisted row follows `{ id, parent_id, format, content }`; `fmt.encode` produces the `content` payload and `fmt.decode` reverses it, so your backend never needs to know about `UIMessage` internals.
213
+
157
214
  ## Key Changes from v5
158
215
 
159
216
  | Feature | v5 | v6 |
@@ -216,12 +216,58 @@ When the hook mounts it calls `list()` on your adapter, hydrates existing thread
216
216
 
217
217
  ## Thread Lifecycle Cheatsheet
218
218
 
219
- - `list()` hydrates threads on mount and during refreshes.
219
+ - `list()` hydrates threads on mount. It runs once; call `runtime.threads.reload()` to re-fetch.
220
220
  - Creating a new conversation calls `initialize()` once the user sends the first message.
221
221
  - `archive`, `unarchive`, and `delete` are called optimistically; throw to revert the UI.
222
222
  - `generateTitle()` powers the automatic title button and expects an `AssistantStream`.
223
223
  - Provide a `runtimeHook` that always returns a fresh runtime instance per active thread.
224
224
 
225
+ ## Reloading After Async Authentication
226
+
227
+ If your adapter depends on an authenticated user (e.g. an OIDC provider, `better-auth`, `next-auth`) and the auth state resolves asynchronously after `useRemoteThreadListRuntime` has mounted, the initial `list()` call may run before the user is available. Call `aui.threads().reload()` when auth completes to re-fetch with the authenticated request.
228
+
229
+ ```tsx title="app/ThreadListProvider.tsx"
230
+ "use client";
231
+
232
+ import { useEffect } from "react";
233
+ import { useAuth } from "react-oidc-context";
234
+ import {
235
+ AssistantRuntimeProvider,
236
+ useAui,
237
+ useLocalRuntime,
238
+ useRemoteThreadListRuntime,
239
+ } from "@assistant-ui/react";
240
+
241
+ function ReloadOnAuth() {
242
+ const aui = useAui();
243
+ const { isLoading, user } = useAuth();
244
+
245
+ useEffect(() => {
246
+ if (!isLoading && user) {
247
+ aui.threads().reload();
248
+ }
249
+ }, [isLoading, user?.id]);
250
+
251
+ return null;
252
+ }
253
+
254
+ export function ThreadListProvider({ children }) {
255
+ const runtime = useRemoteThreadListRuntime({
256
+ runtimeHook: () => useLocalRuntime(myModelAdapter),
257
+ adapter: useThreadListAdapter(),
258
+ });
259
+
260
+ return (
261
+ <AssistantRuntimeProvider runtime={runtime}>
262
+ <ReloadOnAuth />
263
+ {children}
264
+ </AssistantRuntimeProvider>
265
+ );
266
+ }
267
+ ```
268
+
269
+ `reload()` replaces the cached load promise and discards any in-flight response from a superseded call, so it is safe to invoke multiple times (for example, on logout followed by a new login). `useAui` must be called inside `AssistantRuntimeProvider`, so the effect lives in a child component.
270
+
225
271
  ## Avoiding Race Conditions in History Adapters
226
272
 
227
273
  <Callout type="warn">