@assistant-ui/mcp-docs-server 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/organized/code-examples/waterfall.md +4 -4
- package/.docs/organized/code-examples/with-a2a.md +5 -5
- package/.docs/organized/code-examples/with-ag-ui.md +6 -6
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +7 -7
- package/.docs/organized/code-examples/with-artifacts.md +7 -7
- package/.docs/organized/code-examples/with-assistant-transport.md +5 -5
- package/.docs/organized/code-examples/with-chain-of-thought.md +7 -7
- package/.docs/organized/code-examples/with-cloud-standalone.md +8 -8
- package/.docs/organized/code-examples/with-cloud.md +7 -7
- package/.docs/organized/code-examples/with-custom-thread-list.md +7 -7
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +511 -0
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +10 -10
- package/.docs/organized/code-examples/with-expo.md +18 -18
- package/.docs/organized/code-examples/with-external-store.md +5 -5
- package/.docs/organized/code-examples/with-ffmpeg.md +220 -66
- package/.docs/organized/code-examples/with-google-adk.md +6 -6
- package/.docs/organized/code-examples/with-heat-graph.md +4 -4
- package/.docs/organized/code-examples/with-interactables.md +836 -0
- package/.docs/organized/code-examples/with-langgraph.md +6 -6
- package/.docs/organized/code-examples/with-livekit.md +591 -0
- package/.docs/organized/code-examples/with-parent-id-grouping.md +6 -6
- package/.docs/organized/code-examples/with-react-hook-form.md +8 -8
- package/.docs/organized/code-examples/with-react-ink.md +3 -3
- package/.docs/organized/code-examples/with-react-router.md +11 -11
- package/.docs/organized/code-examples/with-store.md +11 -6
- package/.docs/organized/code-examples/with-tanstack.md +8 -8
- package/.docs/organized/code-examples/with-tap-runtime.md +8 -8
- package/.docs/raw/blog/2026-03-launch-week/index.mdx +31 -0
- package/.docs/raw/docs/(docs)/cli.mdx +60 -0
- package/.docs/raw/docs/(docs)/copilots/model-context.mdx +9 -1
- package/.docs/raw/docs/(docs)/guides/attachments.mdx +65 -4
- package/.docs/raw/docs/(docs)/guides/interactables.mdx +354 -0
- package/.docs/raw/docs/(docs)/guides/message-timing.mdx +3 -3
- package/.docs/raw/docs/(docs)/guides/multi-agent.mdx +1 -0
- package/.docs/raw/docs/(docs)/guides/tool-ui.mdx +29 -0
- package/.docs/raw/docs/(docs)/guides/voice.mdx +333 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +128 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +23 -0
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +6 -0
- package/.docs/raw/docs/cloud/ai-sdk.mdx +81 -1
- package/.docs/raw/docs/ink/primitives.mdx +141 -0
- package/.docs/raw/docs/primitives/action-bar.mdx +351 -0
- package/.docs/raw/docs/primitives/assistant-modal.mdx +215 -0
- package/.docs/raw/docs/primitives/attachment.mdx +216 -0
- package/.docs/raw/docs/primitives/branch-picker.mdx +221 -0
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +311 -0
- package/.docs/raw/docs/primitives/composer.mdx +526 -0
- package/.docs/raw/docs/primitives/error.mdx +141 -0
- package/.docs/raw/docs/primitives/index.mdx +98 -0
- package/.docs/raw/docs/primitives/message.mdx +524 -0
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +165 -0
- package/.docs/raw/docs/primitives/suggestion.mdx +242 -0
- package/.docs/raw/docs/primitives/thread-list.mdx +404 -0
- package/.docs/raw/docs/primitives/thread.mdx +482 -0
- package/.docs/raw/docs/runtimes/a2a/index.mdx +4 -0
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +2 -2
- package/.docs/raw/docs/runtimes/assistant-transport.mdx +6 -2
- package/.docs/raw/docs/ui/context-display.mdx +2 -2
- package/.docs/raw/docs/ui/mention.mdx +168 -0
- package/.docs/raw/docs/ui/model-selector.mdx +1 -1
- package/.docs/raw/docs/ui/voice.mdx +172 -0
- package/package.json +3 -4
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AssistantModal
|
|
3
|
+
description: A floating chat popover with a fixed-position trigger button that opens a chat panel.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { AssistantModalSample } from "@/components/docs/samples/assistant-modal";
|
|
7
|
+
import { AssistantModalPrimitive as AssistantModalPrimitiveDocs } from "@/generated/primitiveDocs";
|
|
8
|
+
|
|
9
|
+
The AssistantModal primitive is a floating chat popover built on [Radix Popover](https://www.radix-ui.com/primitives/docs/components/popover). A trigger button opens a chat panel, which is a common floating assistant launcher pattern. You control the trigger, content, positioning, and animations.
|
|
10
|
+
|
|
11
|
+
<Tabs items={["Preview", "Code"]}>
|
|
12
|
+
<Tab>
|
|
13
|
+
<AssistantModalSample />
|
|
14
|
+
</Tab>
|
|
15
|
+
<Tab>
|
|
16
|
+
```tsx
|
|
17
|
+
import { AssistantModalPrimitive } from "@assistant-ui/react";
|
|
18
|
+
|
|
19
|
+
function MinimalAssistantModal() {
|
|
20
|
+
return (
|
|
21
|
+
<AssistantModalPrimitive.Root>
|
|
22
|
+
<AssistantModalPrimitive.Anchor>
|
|
23
|
+
<AssistantModalPrimitive.Trigger>
|
|
24
|
+
Open Chat
|
|
25
|
+
</AssistantModalPrimitive.Trigger>
|
|
26
|
+
</AssistantModalPrimitive.Anchor>
|
|
27
|
+
<AssistantModalPrimitive.Content>
|
|
28
|
+
{/* Your Thread goes here */}
|
|
29
|
+
</AssistantModalPrimitive.Content>
|
|
30
|
+
</AssistantModalPrimitive.Root>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
</Tab>
|
|
35
|
+
</Tabs>
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
Minimal example:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { AssistantModalPrimitive } from "@assistant-ui/react";
|
|
43
|
+
|
|
44
|
+
<AssistantModalPrimitive.Root>
|
|
45
|
+
<AssistantModalPrimitive.Anchor>
|
|
46
|
+
<AssistantModalPrimitive.Trigger>Open</AssistantModalPrimitive.Trigger>
|
|
47
|
+
</AssistantModalPrimitive.Anchor>
|
|
48
|
+
<AssistantModalPrimitive.Content>
|
|
49
|
+
<Thread />
|
|
50
|
+
</AssistantModalPrimitive.Content>
|
|
51
|
+
</AssistantModalPrimitive.Root>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`Root` is a Radix Popover provider (no DOM), `Trigger` renders a `<button>`, `Anchor` renders a `<div>`, and `Content` renders a `<div>` inside a portal. Add your own classes, animations, and layout.
|
|
55
|
+
|
|
56
|
+
<Callout type="info">
|
|
57
|
+
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
|
|
58
|
+
</Callout>
|
|
59
|
+
|
|
60
|
+
## Core Concepts
|
|
61
|
+
|
|
62
|
+
### Popover Architecture
|
|
63
|
+
|
|
64
|
+
AssistantModal is built directly on Radix Popover. `Root` manages open/close state, `Trigger` toggles it, `Anchor` positions the popover, and `Content` is the floating panel. All Radix Popover props are available on the corresponding parts.
|
|
65
|
+
|
|
66
|
+
### Anchor vs Trigger
|
|
67
|
+
|
|
68
|
+
`Content` positions itself relative to `Anchor`, not `Trigger`. The common pattern is wrapping `Trigger` inside `Anchor` so the popover aligns to a larger area (like a fixed-position button container) rather than the button itself:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<AssistantModalPrimitive.Anchor className="fixed right-4 bottom-4 size-11">
|
|
72
|
+
<AssistantModalPrimitive.Trigger>
|
|
73
|
+
Open
|
|
74
|
+
</AssistantModalPrimitive.Trigger>
|
|
75
|
+
</AssistantModalPrimitive.Anchor>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Auto-Open on Run Start
|
|
79
|
+
|
|
80
|
+
The `unstable_openOnRunStart` prop (default `true`) automatically opens the modal when the assistant starts responding. This means if a user triggers a run programmatically while the modal is closed, it pops open to show the response. Set to `false` to disable.
|
|
81
|
+
|
|
82
|
+
### Dismiss Behavior
|
|
83
|
+
|
|
84
|
+
`Content` uses `dissmissOnInteractOutside` *(intentional current API spelling, with the extra `s`)* and defaults it to `false`. Clicking outside the modal does **not** close it. This matches expected chat UX where users interact with the page while keeping the chat open. Set it to `true` for standard popover dismiss behavior.
|
|
85
|
+
|
|
86
|
+
### Open/Close Animations
|
|
87
|
+
|
|
88
|
+
`Content` exposes `data-[state=open]` and `data-[state=closed]` attributes for CSS animations:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<AssistantModalPrimitive.Content
|
|
92
|
+
className="data-[state=open]:animate-in data-[state=open]:fade-in data-[state=closed]:animate-out data-[state=closed]:fade-out"
|
|
93
|
+
>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Parts
|
|
97
|
+
|
|
98
|
+
### Root
|
|
99
|
+
|
|
100
|
+
Radix Popover provider, manages open/close state. No DOM element rendered.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<AssistantModalPrimitive.Root unstable_openOnRunStart={false}>
|
|
104
|
+
...
|
|
105
|
+
</AssistantModalPrimitive.Root>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
<PrimitivesTypeTable type="AssistantModalPrimitiveRootProps" parameters={AssistantModalPrimitiveDocs.Root.props} />
|
|
109
|
+
|
|
110
|
+
### Trigger
|
|
111
|
+
|
|
112
|
+
Button that toggles the modal open and closed. Renders a `<button>` element unless `asChild` is set.
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<AssistantModalPrimitive.Trigger className="rounded-full bg-primary px-4 py-2 text-primary-foreground">
|
|
116
|
+
Open Chat
|
|
117
|
+
</AssistantModalPrimitive.Trigger>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Anchor
|
|
121
|
+
|
|
122
|
+
Positions the trigger and content relative to a shared anchor. Renders a `<div>` element unless `asChild` is set.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<AssistantModalPrimitive.Anchor className="fixed right-4 bottom-4">
|
|
126
|
+
<AssistantModalPrimitive.Trigger>Chat</AssistantModalPrimitive.Trigger>
|
|
127
|
+
</AssistantModalPrimitive.Anchor>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Content
|
|
131
|
+
|
|
132
|
+
The floating chat panel. Renders a `<div>` element inside a portal.
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
<AssistantModalPrimitive.Content
|
|
136
|
+
sideOffset={16}
|
|
137
|
+
className="h-[600px] w-[400px] rounded-xl border bg-background shadow-lg"
|
|
138
|
+
>
|
|
139
|
+
<Thread />
|
|
140
|
+
</AssistantModalPrimitive.Content>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
<PrimitivesTypeTable type="AssistantModalPrimitiveContentProps" parameters={AssistantModalPrimitiveDocs.Content.props} />
|
|
144
|
+
|
|
145
|
+
## Patterns
|
|
146
|
+
|
|
147
|
+
### Floating Bottom-Right Widget
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
<AssistantModalPrimitive.Root>
|
|
151
|
+
<AssistantModalPrimitive.Anchor className="fixed right-4 bottom-4 size-11">
|
|
152
|
+
<AssistantModalPrimitive.Trigger className="size-full rounded-full bg-primary text-primary-foreground shadow-lg">
|
|
153
|
+
<BotIcon className="size-6" />
|
|
154
|
+
</AssistantModalPrimitive.Trigger>
|
|
155
|
+
</AssistantModalPrimitive.Anchor>
|
|
156
|
+
<AssistantModalPrimitive.Content
|
|
157
|
+
sideOffset={16}
|
|
158
|
+
className="h-[600px] w-[400px] rounded-xl border bg-background shadow-lg"
|
|
159
|
+
>
|
|
160
|
+
<Thread />
|
|
161
|
+
</AssistantModalPrimitive.Content>
|
|
162
|
+
</AssistantModalPrimitive.Root>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Trigger Icon Swap
|
|
166
|
+
|
|
167
|
+
The `Trigger` button receives a `data-state` attribute from Radix (`"open"` or `"closed"`). To pass that state down to child icons, use `asChild` with a wrapper component that destructures and forwards it:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { forwardRef } from "react";
|
|
171
|
+
|
|
172
|
+
const ModalButton = forwardRef<
|
|
173
|
+
HTMLButtonElement,
|
|
174
|
+
React.ComponentPropsWithoutRef<"button"> & { "data-state"?: string }
|
|
175
|
+
>(({ "data-state": state, ...props }, ref) => (
|
|
176
|
+
<button ref={ref} {...props} className="relative size-11 rounded-full">
|
|
177
|
+
<BotIcon
|
|
178
|
+
data-state={state}
|
|
179
|
+
className="absolute size-6 transition-all data-[state=open]:rotate-90 data-[state=open]:scale-0"
|
|
180
|
+
/>
|
|
181
|
+
<XIcon
|
|
182
|
+
data-state={state}
|
|
183
|
+
className="absolute size-6 transition-all data-[state=closed]:-rotate-90 data-[state=closed]:scale-0"
|
|
184
|
+
/>
|
|
185
|
+
</button>
|
|
186
|
+
));
|
|
187
|
+
|
|
188
|
+
<AssistantModalPrimitive.Trigger asChild>
|
|
189
|
+
<ModalButton />
|
|
190
|
+
</AssistantModalPrimitive.Trigger>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Custom Portal Container
|
|
194
|
+
|
|
195
|
+
Render the content inside a specific container instead of `document.body`:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
<AssistantModalPrimitive.Content
|
|
199
|
+
portalProps={{ container: myContainerRef.current }}
|
|
200
|
+
>
|
|
201
|
+
<Thread />
|
|
202
|
+
</AssistantModalPrimitive.Content>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Relationship to Components
|
|
206
|
+
|
|
207
|
+
The shadcn [AssistantModal](/docs/ui/assistant-modal) component wraps these primitives with slide/fade animations, icon transitions between open and closed states, and responsive sizing. Start there for a prebuilt floating chat widget.
|
|
208
|
+
|
|
209
|
+
## API Reference
|
|
210
|
+
|
|
211
|
+
For full prop details on every part, see the [AssistantModalPrimitive API Reference](/docs/api-reference/primitives/assistant-modal).
|
|
212
|
+
|
|
213
|
+
Related:
|
|
214
|
+
- [ThreadPrimitive](/docs/primitives/thread)
|
|
215
|
+
- [ComposerPrimitive](/docs/primitives/composer)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Attachment
|
|
3
|
+
description: File and image attachment rendering for the composer and messages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { AttachmentSample } from "@/components/docs/samples/attachment";
|
|
7
|
+
|
|
8
|
+
The Attachment primitive renders file and image attachments. It appears in two places: inside the composer for pending uploads (with a remove button), and inside messages for sent attachments (read-only). You provide the layout and styling.
|
|
9
|
+
|
|
10
|
+
<Tabs items={["Preview", "Code"]}>
|
|
11
|
+
<Tab>
|
|
12
|
+
<AttachmentSample />
|
|
13
|
+
</Tab>
|
|
14
|
+
<Tab>
|
|
15
|
+
```tsx
|
|
16
|
+
import {
|
|
17
|
+
AttachmentPrimitive,
|
|
18
|
+
ComposerPrimitive,
|
|
19
|
+
} from "@assistant-ui/react";
|
|
20
|
+
import { XIcon } from "lucide-react";
|
|
21
|
+
|
|
22
|
+
function ComposerAttachment() {
|
|
23
|
+
return (
|
|
24
|
+
<AttachmentPrimitive.Root className="flex items-center gap-2 rounded-lg border p-2">
|
|
25
|
+
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs" />
|
|
26
|
+
<span className="text-sm">
|
|
27
|
+
<AttachmentPrimitive.Name />
|
|
28
|
+
</span>
|
|
29
|
+
<AttachmentPrimitive.Remove className="ml-auto rounded-full p-1 hover:bg-muted">
|
|
30
|
+
<XIcon className="size-3" />
|
|
31
|
+
</AttachmentPrimitive.Remove>
|
|
32
|
+
</AttachmentPrimitive.Root>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
</Tab>
|
|
37
|
+
</Tabs>
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
An attachment inside a composer:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { AttachmentPrimitive, ComposerPrimitive } from "@assistant-ui/react";
|
|
45
|
+
|
|
46
|
+
<ComposerPrimitive.Root>
|
|
47
|
+
<ComposerPrimitive.Attachments>
|
|
48
|
+
{() => <MyAttachment />}
|
|
49
|
+
</ComposerPrimitive.Attachments>
|
|
50
|
+
<ComposerPrimitive.Input placeholder="Ask anything..." />
|
|
51
|
+
<ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
|
|
52
|
+
</ComposerPrimitive.Root>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`Root` renders a `<div>`, `unstable_Thumb` renders a `<div>` showing the file extension with a leading dot (e.g., `.pdf`), `Name` renders plain text, and `Remove` renders a `<button>`.
|
|
56
|
+
|
|
57
|
+
<Callout type="info">
|
|
58
|
+
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
|
|
59
|
+
</Callout>
|
|
60
|
+
|
|
61
|
+
## Core Concepts
|
|
62
|
+
|
|
63
|
+
### Two Contexts
|
|
64
|
+
|
|
65
|
+
Attachments appear in two different contexts:
|
|
66
|
+
|
|
67
|
+
- **Composer**: via `ComposerPrimitive.Attachments`. These are pending uploads that can be removed before sending.
|
|
68
|
+
- **Messages**: via `MessagePrimitive.Attachments`. These are sent attachments, displayed read-only (the iterator renders attachments for user messages).
|
|
69
|
+
|
|
70
|
+
The same `AttachmentPrimitive` parts work in both contexts. The difference is behavioral: `Remove` only works in the composer context.
|
|
71
|
+
|
|
72
|
+
### Iterator Pattern
|
|
73
|
+
|
|
74
|
+
You don't loop over attachments yourself. Instead, use the children render function:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
// Composer attachments
|
|
78
|
+
<ComposerPrimitive.Attachments>
|
|
79
|
+
{({ attachment }) => {
|
|
80
|
+
if (attachment.type === "image") return <ImageAttachment />;
|
|
81
|
+
if (attachment.type === "document") return <DocumentAttachment />;
|
|
82
|
+
return <GenericAttachment />;
|
|
83
|
+
}}
|
|
84
|
+
</ComposerPrimitive.Attachments>
|
|
85
|
+
|
|
86
|
+
// Message attachments
|
|
87
|
+
<MessagePrimitive.Attachments>
|
|
88
|
+
{({ attachment }) => {
|
|
89
|
+
if (attachment.type === "image") return <ImageAttachment />;
|
|
90
|
+
if (attachment.type === "document") return <DocumentAttachment />;
|
|
91
|
+
return <GenericAttachment />;
|
|
92
|
+
}}
|
|
93
|
+
</MessagePrimitive.Attachments>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Each component receives its attachment context automatically, with no props to pass. `components` is deprecated — use the `children` render function instead.
|
|
97
|
+
|
|
98
|
+
### Remove Button
|
|
99
|
+
|
|
100
|
+
`Remove` calls the attachment runtime remove action. In composer attachments it removes the attachment from the pending message. In message attachments, this action is not supported and clicking `Remove` will throw `"Message attachments cannot be removed"`. Only render `Remove` in composer UIs.
|
|
101
|
+
|
|
102
|
+
### Name as Text
|
|
103
|
+
|
|
104
|
+
`Name` renders plain text with no wrapper element. Wrap it in a `<span>` or other element for styling:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<span className="text-sm font-medium">
|
|
108
|
+
<AttachmentPrimitive.Name />
|
|
109
|
+
</span>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Parts
|
|
113
|
+
|
|
114
|
+
### Root
|
|
115
|
+
|
|
116
|
+
Container for a single attachment item. Renders a `<div>` element unless `asChild` is set.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
<AttachmentPrimitive.Root className="flex items-center gap-2 rounded-lg border p-2">
|
|
120
|
+
<AttachmentPrimitive.Name />
|
|
121
|
+
</AttachmentPrimitive.Root>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### unstable_Thumb
|
|
125
|
+
|
|
126
|
+
Thumbnail slot for attachment previews. Renders a `<div>` element unless `asChild` is set.
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs" />
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Name
|
|
133
|
+
|
|
134
|
+
Renders the attachment filename text.
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<AttachmentPrimitive.Name />
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Remove
|
|
141
|
+
|
|
142
|
+
Button that removes the current attachment when used in a removable attachment context. Renders a `<button>` element unless `asChild` is set.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<AttachmentPrimitive.Remove className="rounded-full p-1 hover:bg-muted">
|
|
146
|
+
<XIcon className="size-3" />
|
|
147
|
+
</AttachmentPrimitive.Remove>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Patterns
|
|
151
|
+
|
|
152
|
+
### Composer Attachment with Remove
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
function ComposerAttachmentItem() {
|
|
156
|
+
return (
|
|
157
|
+
<AttachmentPrimitive.Root className="flex items-center gap-2 rounded-lg border p-2">
|
|
158
|
+
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs font-mono" />
|
|
159
|
+
<span className="min-w-0 flex-1 truncate text-sm">
|
|
160
|
+
<AttachmentPrimitive.Name />
|
|
161
|
+
</span>
|
|
162
|
+
<AttachmentPrimitive.Remove className="rounded-full p-1 hover:bg-muted">
|
|
163
|
+
<XIcon className="size-3" />
|
|
164
|
+
</AttachmentPrimitive.Remove>
|
|
165
|
+
</AttachmentPrimitive.Root>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
<ComposerPrimitive.Root>
|
|
170
|
+
<ComposerPrimitive.Attachments
|
|
171
|
+
components={{ Attachment: ComposerAttachmentItem }}
|
|
172
|
+
/>
|
|
173
|
+
<ComposerPrimitive.Input placeholder="Ask anything..." />
|
|
174
|
+
<ComposerPrimitive.Send>Send</ComposerPrimitive.Send>
|
|
175
|
+
</ComposerPrimitive.Root>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Message Attachment (Read-Only)
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
function MessageAttachment() {
|
|
182
|
+
return (
|
|
183
|
+
<AttachmentPrimitive.Root className="flex items-center gap-2 rounded-lg border p-2">
|
|
184
|
+
<AttachmentPrimitive.unstable_Thumb className="flex size-10 items-center justify-center rounded bg-muted text-xs font-mono" />
|
|
185
|
+
<span className="text-sm">
|
|
186
|
+
<AttachmentPrimitive.Name />
|
|
187
|
+
</span>
|
|
188
|
+
</AttachmentPrimitive.Root>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Custom Layout with asChild
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
<AttachmentPrimitive.Root asChild>
|
|
197
|
+
<li className="flex items-center gap-3 py-1">
|
|
198
|
+
<AttachmentPrimitive.unstable_Thumb className="size-8 rounded bg-muted text-xs" />
|
|
199
|
+
<span className="text-sm">
|
|
200
|
+
<AttachmentPrimitive.Name />
|
|
201
|
+
</span>
|
|
202
|
+
</li>
|
|
203
|
+
</AttachmentPrimitive.Root>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Relationship to Components
|
|
207
|
+
|
|
208
|
+
The shadcn [Attachment](/docs/ui/attachment) component wraps these primitives with styled thumbnails, tooltip filenames, remove buttons, and image preview dialogs. Start there for a prebuilt attachment UI.
|
|
209
|
+
|
|
210
|
+
## API Reference
|
|
211
|
+
|
|
212
|
+
For full prop details on every part, see the [AttachmentPrimitive API Reference](/docs/api-reference/primitives/attachment).
|
|
213
|
+
|
|
214
|
+
Related:
|
|
215
|
+
- [ComposerPrimitive API Reference](/docs/api-reference/primitives/composer)
|
|
216
|
+
- [MessagePrimitive API Reference](/docs/api-reference/primitives/message)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: BranchPicker
|
|
3
|
+
description: Navigate between message branches, which are alternative responses the user can flip through.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
import { BranchPickerPrimitiveSample } from "@/components/docs/samples/branch-picker-primitive";
|
|
7
|
+
import { BranchPickerPrimitive as BranchPickerPrimitiveDocs } from "@/generated/primitiveDocs";
|
|
8
|
+
|
|
9
|
+
The BranchPicker primitive lets users navigate between message branches, which are alternative responses generated by editing a message or regenerating a reply. It's used alongside ActionBar inside message components.
|
|
10
|
+
|
|
11
|
+
<Tabs items={["Preview", "Code"]}>
|
|
12
|
+
<Tab>
|
|
13
|
+
<BranchPickerPrimitiveSample />
|
|
14
|
+
</Tab>
|
|
15
|
+
<Tab>
|
|
16
|
+
```tsx
|
|
17
|
+
import {
|
|
18
|
+
BranchPickerPrimitive,
|
|
19
|
+
MessagePrimitive,
|
|
20
|
+
} from "@assistant-ui/react";
|
|
21
|
+
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
22
|
+
|
|
23
|
+
function AssistantMessage() {
|
|
24
|
+
return (
|
|
25
|
+
<MessagePrimitive.Root className="flex flex-col items-start gap-1">
|
|
26
|
+
<div className="rounded-2xl bg-muted px-4 py-2.5 text-sm">
|
|
27
|
+
<MessagePrimitive.Parts />
|
|
28
|
+
</div>
|
|
29
|
+
<BranchPickerPrimitive.Root className="inline-flex items-center gap-0.5 text-xs">
|
|
30
|
+
<BranchPickerPrimitive.Previous className="flex size-6 items-center justify-center rounded-md disabled:opacity-30">
|
|
31
|
+
<ChevronLeftIcon className="size-3.5" />
|
|
32
|
+
</BranchPickerPrimitive.Previous>
|
|
33
|
+
<span>
|
|
34
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
35
|
+
</span>
|
|
36
|
+
<BranchPickerPrimitive.Next className="flex size-6 items-center justify-center rounded-md disabled:opacity-30">
|
|
37
|
+
<ChevronRightIcon className="size-3.5" />
|
|
38
|
+
</BranchPickerPrimitive.Next>
|
|
39
|
+
</BranchPickerPrimitive.Root>
|
|
40
|
+
</MessagePrimitive.Root>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
</Tab>
|
|
45
|
+
</Tabs>
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
Minimal example:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { BranchPickerPrimitive } from "@assistant-ui/react";
|
|
53
|
+
|
|
54
|
+
<BranchPickerPrimitive.Root>
|
|
55
|
+
<BranchPickerPrimitive.Previous>←</BranchPickerPrimitive.Previous>
|
|
56
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
57
|
+
<BranchPickerPrimitive.Next>→</BranchPickerPrimitive.Next>
|
|
58
|
+
</BranchPickerPrimitive.Root>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`Root` renders a `<div>`, `Previous` and `Next` render `<button>` elements that auto-disable at boundaries. `Number` and `Count` render plain text (the current branch index and total count).
|
|
62
|
+
|
|
63
|
+
<Callout type="info">
|
|
64
|
+
BranchPicker must be placed inside a `MessagePrimitive.Root` because it reads branch state from the nearest message context.
|
|
65
|
+
</Callout>
|
|
66
|
+
|
|
67
|
+
<Callout type="info">
|
|
68
|
+
Runtime setup: primitives require runtime context. Wrap your UI in `AssistantRuntimeProvider` with a runtime (for example `useLocalRuntime(...)`). See [Pick a Runtime](/docs/runtimes/pick-a-runtime).
|
|
69
|
+
</Callout>
|
|
70
|
+
|
|
71
|
+
## Core Concepts
|
|
72
|
+
|
|
73
|
+
### Branch Navigation
|
|
74
|
+
|
|
75
|
+
`Previous` and `Next` buttons automatically disable at boundaries. `Previous` is disabled on the first branch, and `Next` is disabled on the last. Both also disable while the thread is running if the runtime doesn't support `switchBranchDuringRun`.
|
|
76
|
+
|
|
77
|
+
### Number & Count
|
|
78
|
+
|
|
79
|
+
`Number` and `Count` are text-only primitives that render raw numbers with no wrapping element. Use a `<span>` if you need to style them:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
<span className="tabular-nums">
|
|
83
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
84
|
+
</span>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### hideWhenSingleBranch
|
|
88
|
+
|
|
89
|
+
The `hideWhenSingleBranch` prop on `Root` hides the entire picker when there's only one branch. This is a common production pattern to reduce visual clutter:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
<BranchPickerPrimitive.Root hideWhenSingleBranch>
|
|
93
|
+
<BranchPickerPrimitive.Previous>←</BranchPickerPrimitive.Previous>
|
|
94
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
95
|
+
<BranchPickerPrimitive.Next>→</BranchPickerPrimitive.Next>
|
|
96
|
+
</BranchPickerPrimitive.Root>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Context Requirement
|
|
100
|
+
|
|
101
|
+
BranchPicker reads branch state from the nearest message context. It must be placed inside a `MessagePrimitive.Root`, either directly or nested inside your message component.
|
|
102
|
+
|
|
103
|
+
## Parts
|
|
104
|
+
|
|
105
|
+
### Root
|
|
106
|
+
|
|
107
|
+
Container with optional `hideWhenSingleBranch`. Renders a `<div>` element unless `asChild` is set.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<BranchPickerPrimitive.Root hideWhenSingleBranch className="inline-flex items-center gap-1">
|
|
111
|
+
<BranchPickerPrimitive.Previous>←</BranchPickerPrimitive.Previous>
|
|
112
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
113
|
+
<BranchPickerPrimitive.Next>→</BranchPickerPrimitive.Next>
|
|
114
|
+
</BranchPickerPrimitive.Root>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
<PrimitivesTypeTable type="BranchPickerPrimitiveRootProps" parameters={BranchPickerPrimitiveDocs.Root.props.filter(p => p.name !== "asChild")} />
|
|
118
|
+
|
|
119
|
+
### Previous
|
|
120
|
+
|
|
121
|
+
Button that selects the previous branch. Renders a `<button>` element unless `asChild` is set.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<BranchPickerPrimitive.Previous>Previous</BranchPickerPrimitive.Previous>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Next
|
|
128
|
+
|
|
129
|
+
Button that selects the next branch. Renders a `<button>` element unless `asChild` is set.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<BranchPickerPrimitive.Next>Next</BranchPickerPrimitive.Next>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Number
|
|
136
|
+
|
|
137
|
+
Displays the current branch number.
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<BranchPickerPrimitive.Number />
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Count
|
|
144
|
+
|
|
145
|
+
Displays the total number of branches for the current message.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<BranchPickerPrimitive.Count />
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Patterns
|
|
152
|
+
|
|
153
|
+
### Standard Picker with Icons
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
157
|
+
|
|
158
|
+
<BranchPickerPrimitive.Root
|
|
159
|
+
hideWhenSingleBranch
|
|
160
|
+
className="inline-flex items-center gap-1 text-xs text-muted-foreground"
|
|
161
|
+
>
|
|
162
|
+
<BranchPickerPrimitive.Previous className="size-6 rounded-md hover:bg-muted disabled:opacity-30">
|
|
163
|
+
<ChevronLeftIcon className="size-3.5" />
|
|
164
|
+
</BranchPickerPrimitive.Previous>
|
|
165
|
+
<span className="tabular-nums">
|
|
166
|
+
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
167
|
+
</span>
|
|
168
|
+
<BranchPickerPrimitive.Next className="size-6 rounded-md hover:bg-muted disabled:opacity-30">
|
|
169
|
+
<ChevronRightIcon className="size-3.5" />
|
|
170
|
+
</BranchPickerPrimitive.Next>
|
|
171
|
+
</BranchPickerPrimitive.Root>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Custom Elements with asChild
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<BranchPickerPrimitive.Previous asChild>
|
|
178
|
+
<MyIconButton tooltip="Previous branch">
|
|
179
|
+
<ChevronLeftIcon />
|
|
180
|
+
</MyIconButton>
|
|
181
|
+
</BranchPickerPrimitive.Previous>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The primitive's disabled state and click handler merge onto your element.
|
|
185
|
+
|
|
186
|
+
### Inside a Message Footer
|
|
187
|
+
|
|
188
|
+
The most common pattern places the BranchPicker alongside an ActionBar in a message footer:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
function AssistantMessage() {
|
|
192
|
+
return (
|
|
193
|
+
<MessagePrimitive.Root>
|
|
194
|
+
<div className="rounded-xl bg-muted p-3">
|
|
195
|
+
<MessagePrimitive.Parts />
|
|
196
|
+
</div>
|
|
197
|
+
<div className="flex items-center justify-between">
|
|
198
|
+
<BranchPickerPrimitive.Root hideWhenSingleBranch>
|
|
199
|
+
{/* prev / number / count / next */}
|
|
200
|
+
</BranchPickerPrimitive.Root>
|
|
201
|
+
<ActionBarPrimitive.Root>
|
|
202
|
+
<ActionBarPrimitive.Copy>Copy</ActionBarPrimitive.Copy>
|
|
203
|
+
<ActionBarPrimitive.Reload>Reload</ActionBarPrimitive.Reload>
|
|
204
|
+
</ActionBarPrimitive.Root>
|
|
205
|
+
</div>
|
|
206
|
+
</MessagePrimitive.Root>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Relationship to Components
|
|
212
|
+
|
|
213
|
+
The shadcn [Thread](/docs/ui/thread) component includes a BranchPicker in both AssistantMessage and UserMessage footers, with `hideWhenSingleBranch` enabled. If the default layout works, use the component. Reach for `BranchPickerPrimitive` directly when you need a custom position, different styling, or a non-standard branch navigation experience.
|
|
214
|
+
|
|
215
|
+
## API Reference
|
|
216
|
+
|
|
217
|
+
For full prop details on every part, see the [BranchPickerPrimitive API Reference](/docs/api-reference/primitives/branch-picker).
|
|
218
|
+
|
|
219
|
+
Related:
|
|
220
|
+
- [ActionBarPrimitive API Reference](/docs/api-reference/primitives/action-bar)
|
|
221
|
+
- [MessagePrimitive API Reference](/docs/api-reference/primitives/message)
|