@assistant-ui/mcp-docs-server 0.1.34 → 0.1.36
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 +73 -57
- package/.docs/organized/code-examples/with-browser-extension.md +7 -7
- package/.docs/organized/code-examples/with-chain-of-thought.md +44 -93
- package/.docs/organized/code-examples/with-cloud-standalone.md +7 -7
- 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 +9 -9
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +9 -9
- package/.docs/organized/code-examples/with-eve.md +343 -0
- package/.docs/organized/code-examples/with-expo.md +943 -940
- package/.docs/organized/code-examples/with-external-store.md +5 -5
- package/.docs/organized/code-examples/with-ffmpeg.md +8 -11
- package/.docs/organized/code-examples/with-generative-ui.md +33 -309
- package/.docs/organized/code-examples/with-google-adk.md +5 -5
- package/.docs/organized/code-examples/with-heat-graph.md +4 -4
- package/.docs/organized/code-examples/with-image-generation.md +7 -7
- package/.docs/organized/code-examples/with-interactables.md +169 -341
- package/.docs/organized/code-examples/with-langchain.md +7 -7
- package/.docs/organized/code-examples/with-langgraph.md +23 -160
- package/.docs/organized/code-examples/with-livekit.md +10 -10
- package/.docs/organized/code-examples/with-mcp.md +7 -7
- package/.docs/organized/code-examples/with-opencode.md +106 -580
- package/.docs/organized/code-examples/with-pi.md +2046 -0
- package/.docs/organized/code-examples/with-react-hook-form.md +16 -9
- package/.docs/organized/code-examples/with-react-ink-web.md +691 -0
- package/.docs/organized/code-examples/with-react-ink.md +29 -17
- package/.docs/organized/code-examples/with-react-router.md +12 -12
- package/.docs/organized/code-examples/with-resumable-stream.md +8 -8
- package/.docs/organized/code-examples/with-store.md +14 -10
- package/.docs/organized/code-examples/with-tanstack.md +21 -7
- package/.docs/organized/code-examples/with-tap-runtime.md +5 -5
- package/.docs/organized/code-examples/with-virtualized-thread.md +676 -0
- package/.docs/raw/docs/(docs)/architecture.mdx +13 -12
- package/.docs/raw/docs/(docs)/cli.mdx +4 -2
- package/.docs/raw/docs/(docs)/devtools.mdx +25 -2
- package/.docs/raw/docs/(docs)/index.mdx +5 -2
- package/.docs/raw/docs/(docs)/installation.mdx +5 -2
- package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +16 -16
- package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +73 -42
- package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +3 -20
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +234 -123
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +51 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +70 -38
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +30 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +7 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +26 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/chain-of-thought.mdx +15 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +103 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +16 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +56 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/queue-item.mdx +12 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +12 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +14 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +57 -1
- package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +6 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/interactables-legacy.mdx +55 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/interactables.mdx +151 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +17 -38
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +20 -27
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +40 -25
- package/.docs/raw/docs/guides/chain-of-thought.mdx +1 -1
- package/.docs/raw/docs/guides/headless-composer-input.mdx +113 -0
- package/.docs/raw/docs/guides/index.mdx +3 -0
- package/.docs/raw/docs/guides/input-history.mdx +55 -0
- package/.docs/raw/docs/guides/latex.mdx +28 -22
- package/.docs/raw/docs/guides/mentions.mdx +32 -7
- package/.docs/raw/docs/guides/slash-commands.mdx +3 -6
- package/.docs/raw/docs/guides/speech.mdx +5 -7
- package/.docs/raw/docs/guides/virtualization.mdx +133 -0
- package/.docs/raw/docs/guides/voice.mdx +3 -2
- package/.docs/raw/docs/ink/hooks.mdx +2 -2
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +4 -12
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +7 -10
- package/.docs/raw/docs/integrations/auth/clerk.mdx +3 -9
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +3 -8
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +8 -5
- package/.docs/raw/docs/integrations/index.mdx +5 -12
- package/.docs/raw/docs/integrations/observability/helicone.mdx +3 -4
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +3 -5
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +3 -2
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +4 -3
- package/.docs/raw/docs/primitives/composer.mdx +8 -0
- package/.docs/raw/docs/primitives/thread.mdx +24 -0
- package/.docs/raw/docs/react-native/hooks.mdx +1 -1
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +22 -3
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +1 -1
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +54 -0
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +108 -4
- package/.docs/raw/docs/runtimes/eve/overview.mdx +100 -0
- package/.docs/raw/docs/runtimes/eve/quickstart.mdx +143 -0
- package/.docs/raw/docs/runtimes/langchain.mdx +386 -18
- package/.docs/raw/docs/runtimes/langgraph/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +1 -1
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +12 -6
- package/.docs/raw/docs/tools/defining-tools.mdx +4 -0
- package/.docs/raw/docs/tools/interactables-legacy.mdx +410 -0
- package/.docs/raw/docs/tools/interactables.mdx +892 -223
- package/.docs/raw/docs/tools/mcp.mdx +4 -4
- package/.docs/raw/docs/tools/multi-agent.mdx +5 -0
- package/.docs/raw/docs/tools/tool-ui.mdx +37 -1
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +2 -0
- package/.docs/raw/docs/ui/dot-matrix.mdx +133 -0
- package/.docs/raw/docs/ui/file.mdx +1 -1
- package/.docs/raw/docs/ui/model-selector.mdx +219 -52
- package/.docs/raw/docs/ui/number-roll.mdx +154 -0
- package/.docs/raw/docs/ui/part-grouping.mdx +38 -0
- package/.docs/raw/docs/ui/reasoning.mdx +3 -3
- package/.docs/raw/docs/ui/streamdown.mdx +2 -0
- package/.docs/raw/docs/ui/syntax-highlighting.mdx +1 -1
- package/.docs/raw/docs/ui/thread.mdx +52 -0
- package/.docs/raw/docs/ui/tool-fallback.mdx +2 -2
- package/.docs/raw/docs/utilities/react-o11y.mdx +92 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +14 -6
- package/src/tools/tests/mcp-protocol.test.ts +9 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Number Roll
|
|
3
|
+
description: Animated number that rolls digits odometer-style when the value changes.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
import { PreviewCode } from "@/components/docs/preview-code.server";
|
|
8
|
+
import {
|
|
9
|
+
NumberRollSample,
|
|
10
|
+
NumberRollCompactSample,
|
|
11
|
+
NumberRollFormatSample,
|
|
12
|
+
NumberRollLiveSample,
|
|
13
|
+
} from "@/components/docs/samples/number-roll";
|
|
14
|
+
|
|
15
|
+
<Callout>
|
|
16
|
+
This is a **standalone component** that does not depend on the assistant-ui runtime. Use it anywhere in your application.
|
|
17
|
+
</Callout>
|
|
18
|
+
|
|
19
|
+
<NumberRollSample />
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
<InstallCommand shadcn={["number-roll"]} />
|
|
24
|
+
|
|
25
|
+
This adds a `/components/assistant-ui/number-roll.tsx` file to your project, which you can adjust as needed. The component has no dependencies beyond React.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { NumberRoll } from "@/components/assistant-ui/number-roll";
|
|
31
|
+
|
|
32
|
+
export function TokenCounter({ count }: { count: number }) {
|
|
33
|
+
return <NumberRoll value={count} format={{ notation: "compact" }} />;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When `value` changes, each digit rolls in place to its new value. Formatting is handled by `Intl.NumberFormat`, so structural changes animate too: when `700` becomes `1.1K` with compact notation, the surviving ones digit rolls from 0 to 1 while the leading `70` slides out and the decimal point, fraction digit, and `K` suffix slide in.
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Compact Notation
|
|
42
|
+
|
|
43
|
+
Pass any `Intl.NumberFormatOptions` via the `format` prop. Crossing a compact-notation threshold animates the formatting change instead of remounting the whole string.
|
|
44
|
+
|
|
45
|
+
<PreviewCode file="components/docs/samples/number-roll" name="NumberRollCompactSample">
|
|
46
|
+
<NumberRollCompactSample />
|
|
47
|
+
</PreviewCode>
|
|
48
|
+
|
|
49
|
+
### Formats and Locales
|
|
50
|
+
|
|
51
|
+
Currencies, percentages, suffixes, and non-English locales all work through the same `Intl.NumberFormat` pipeline. Compact thresholds and suffixes are locale-dependent (`1.2万` in `zh-CN`), so never hardcode them.
|
|
52
|
+
|
|
53
|
+
<PreviewCode file="components/docs/samples/number-roll" name="NumberRollFormatSample">
|
|
54
|
+
<NumberRollFormatSample />
|
|
55
|
+
</PreviewCode>
|
|
56
|
+
|
|
57
|
+
### Live Counter
|
|
58
|
+
|
|
59
|
+
Rapid successive updates retarget the in-flight roll smoothly, which makes the component suitable for streaming token counts and other live metrics.
|
|
60
|
+
|
|
61
|
+
<PreviewCode file="components/docs/samples/number-roll" name="NumberRollLiveSample">
|
|
62
|
+
<NumberRollLiveSample />
|
|
63
|
+
</PreviewCode>
|
|
64
|
+
|
|
65
|
+
## How It Works
|
|
66
|
+
|
|
67
|
+
The value is formatted with `Intl.NumberFormat.formatToParts` and split into keyed parts. Integer digits are keyed by place value counted from the right, so when `999` becomes `1,000` the existing columns keep their identity and roll in place while only the new leading digit and separator enter. Symbols (decimal point, group separators, currency signs, compact suffixes) cross-fade and collapse via animated `grid-template-columns`.
|
|
68
|
+
|
|
69
|
+
Each digit renders a strip of 0 to 9 and animates a registered CSS custom property; CSS `mod()` math wraps the strip into an endless ribbon, so rolling from 9 to 0 continues in the trend direction instead of spinning backwards. There is no JavaScript animation loop and no animation library dependency.
|
|
70
|
+
|
|
71
|
+
In browsers without CSS `mod()` support, and during server rendering, the component renders the plain formatted string. With `prefers-reduced-motion`, values swap instantly without rolling. When server rendering, pass an explicit `locales`: the server's default locale can differ from the visitor's browser locale, and a mismatched formatted string causes a React hydration error. Locales whose default numbering system is non-Latin (such as `ar-EG`) cross-fade their digits as symbols instead of rolling.
|
|
72
|
+
|
|
73
|
+
The formatted value is exposed to screen readers as plain text while the animated digits are `aria-hidden`. Value changes are not announced automatically; wrap the component in an `aria-live` region if you need announcements.
|
|
74
|
+
|
|
75
|
+
## API Reference
|
|
76
|
+
|
|
77
|
+
### NumberRoll
|
|
78
|
+
|
|
79
|
+
<ParametersTable
|
|
80
|
+
type="NumberRollProps"
|
|
81
|
+
parameters={[
|
|
82
|
+
{
|
|
83
|
+
name: "value",
|
|
84
|
+
type: "number",
|
|
85
|
+
required: true,
|
|
86
|
+
description: "The number to display.",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "format",
|
|
90
|
+
type: "Intl.NumberFormatOptions",
|
|
91
|
+
description:
|
|
92
|
+
"Number formatting options, e.g. `{ notation: \"compact\" }` or `{ style: \"currency\", currency: \"USD\" }`.",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "locales",
|
|
96
|
+
type: "Intl.LocalesArgument",
|
|
97
|
+
description:
|
|
98
|
+
"Locale(s) passed to `Intl.NumberFormat`. Pass an explicit value in server-rendered apps so the server and client format identically.",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "prefix",
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "Static text rendered before the number.",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "suffix",
|
|
107
|
+
type: "string",
|
|
108
|
+
description: "Static text rendered after the number.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "trend",
|
|
112
|
+
type: '"auto" | "up" | "down"',
|
|
113
|
+
default: '"auto"',
|
|
114
|
+
description:
|
|
115
|
+
"Roll direction. `auto` follows the sign of the value change; `up` and `down` force a direction, wrapping digits through 9/0 as needed.",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "duration",
|
|
119
|
+
type: "number",
|
|
120
|
+
default: "500",
|
|
121
|
+
description:
|
|
122
|
+
"Digit roll duration in milliseconds. Enter/exit fades run at 60% of this value.",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "className",
|
|
126
|
+
type: "string",
|
|
127
|
+
description: "Additional CSS classes.",
|
|
128
|
+
},
|
|
129
|
+
]}
|
|
130
|
+
/>
|
|
131
|
+
|
|
132
|
+
### Styling
|
|
133
|
+
|
|
134
|
+
The root applies `tabular-nums` so digits keep a constant width while rolling; the font you use must provide tabular figures for the layout to stay stable. Size and color are inherited from the surrounding text, so style it like any span:
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<NumberRoll value={value} className="text-4xl font-semibold" />
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Change the animation speed via the `duration` prop; it drives both the CSS timing and the cleanup that unmounts exited characters, so overriding the duration variable in CSS alone would remove them mid-fade. The fade and easing variables are safe to override via the `style` prop (the defaults are set as inline styles, so plain `className` overrides do not apply):
|
|
141
|
+
|
|
142
|
+
| Variable | Default | Description |
|
|
143
|
+
|----------|---------|-------------|
|
|
144
|
+
| `--aui-number-roll-duration` | `500ms` (from the `duration` prop) | Digit roll duration. |
|
|
145
|
+
| `--aui-number-roll-fade` | 60% of the duration | Enter/exit fade and width-collapse duration. |
|
|
146
|
+
| `--aui-number-roll-ease` | `cubic-bezier(0.23, 1, 0.32, 1)` | Digit roll easing. |
|
|
147
|
+
|
|
148
|
+
Parts are targetable via data attributes: `[data-slot="number-roll"]`, `[data-slot="number-roll-part"]`, `[data-slot="number-roll-digit"]`, and `[data-slot="number-roll-symbol"]`.
|
|
149
|
+
|
|
150
|
+
## Related Components
|
|
151
|
+
|
|
152
|
+
- [Context Display](/docs/ui/context-display) - Live token usage ring and bar
|
|
153
|
+
- [Message Timing](/docs/ui/message-timing) - Streaming stats badge
|
|
154
|
+
- [Badge](/docs/ui/badge) - Small status and metadata labels
|
|
@@ -252,6 +252,44 @@ The synthetic `"standalone-tool-call"` key on `groupPartByType` matches all of t
|
|
|
252
252
|
The `"mcp-app"` key is deprecated in favor of `"standalone-tool-call"`, which is a superset (it also matches MCP-app tool calls). Existing `"mcp-app"` usage keeps working.
|
|
253
253
|
</Callout>
|
|
254
254
|
|
|
255
|
+
### Render Tool Calls as Flat Rows
|
|
256
|
+
|
|
257
|
+
The previous section keeps `"tool-call"` folded into the chain-of-thought and only lifts standalone tool UIs out. To keep reasoning collapsed in a group while every tool call renders as its own row in the message flow, map both tool keys to `[]`:
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
<MessagePrimitive.GroupedParts
|
|
261
|
+
groupBy={groupPartByType({
|
|
262
|
+
reasoning: ["group-thought", "group-reasoning"],
|
|
263
|
+
"tool-call": [],
|
|
264
|
+
"standalone-tool-call": [],
|
|
265
|
+
})}
|
|
266
|
+
>
|
|
267
|
+
{({ part, children }) => {
|
|
268
|
+
switch (part.type) {
|
|
269
|
+
case "group-thought":
|
|
270
|
+
case "group-reasoning":
|
|
271
|
+
return <ReasoningBlock>{children}</ReasoningBlock>;
|
|
272
|
+
case "reasoning":
|
|
273
|
+
return <Reasoning {...part} />;
|
|
274
|
+
case "tool-call":
|
|
275
|
+
return part.toolUI ?? <ToolFallback {...part} />;
|
|
276
|
+
case "text":
|
|
277
|
+
return <MarkdownText />;
|
|
278
|
+
case "indicator":
|
|
279
|
+
return <LoadingDots />;
|
|
280
|
+
default:
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}}
|
|
284
|
+
</MessagePrimitive.GroupedParts>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Adjacent `reasoning` parts still coalesce into one `group-thought`, while each tool call is a leaf at the same level as text — the `"standalone-tool-call"` entry is mapped to `[]` too so human-in-the-loop and generative-UI tools stay flat alongside routine calls instead of falling through to `"tool-call"`. Tool-call leaves keep their stable identity keys across re-renders, so rows don't remount as the message streams.
|
|
288
|
+
|
|
289
|
+
<Callout type="warn">
|
|
290
|
+
This renders tool calls flat **in the message flow** — each leaf sits where the part appears, in order. It does not pin, portal, float, or otherwise move tool UIs out of the flow into a sidebar or fixed region. For out-of-flow placement you still own the layout outside `GroupedParts`.
|
|
291
|
+
</Callout>
|
|
292
|
+
|
|
255
293
|
### Group by Custom Metadata
|
|
256
294
|
|
|
257
295
|
Use any custom metadata in your parts for grouping:
|
|
@@ -28,7 +28,7 @@ Previously, reasoning parts were rendered via `components.Reasoning` and grouped
|
|
|
28
28
|
|
|
29
29
|
Render reasoning parts through `MessagePrimitive.GroupedParts`. Group consecutive reasoning parts with `"group-reasoning"`, then compose `ReasoningRoot`, `ReasoningTrigger`, `ReasoningContent`, and `ReasoningText` around the grouped children.
|
|
30
30
|
|
|
31
|
-
While reasoning is streaming, `part.status.type === "running"`. Pass that to `
|
|
31
|
+
While reasoning is streaming, `part.status.type === "running"`. Pass that to `streaming` so the accordion auto-opens during streaming with a bottom-pinned live preview of the newest tokens, auto-collapses when the model moves on, and permanently defers to the first manual toggle. When `streaming` is provided it supersedes `defaultOpen`.
|
|
32
32
|
|
|
33
33
|
```tsx title="/app/components/assistant-ui/thread.tsx"
|
|
34
34
|
import { MessagePrimitive, groupPartByType } from "@assistant-ui/react";
|
|
@@ -56,7 +56,7 @@ const AssistantMessage: FC = () => {
|
|
|
56
56
|
case "group-reasoning": { // [!code ++]
|
|
57
57
|
const running = part.status.type === "running"; // [!code ++]
|
|
58
58
|
return ( // [!code ++]
|
|
59
|
-
<ReasoningRoot
|
|
59
|
+
<ReasoningRoot streaming={running}> // [!code ++]
|
|
60
60
|
<ReasoningTrigger active={running} /> // [!code ++]
|
|
61
61
|
<ReasoningContent aria-busy={running}> // [!code ++]
|
|
62
62
|
<ReasoningText>{children}</ReasoningText> // [!code ++]
|
|
@@ -139,7 +139,7 @@ const ReasoningGroupImpl: ReasoningGroupComponent = ({
|
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
return (
|
|
142
|
-
<ReasoningRoot
|
|
142
|
+
<ReasoningRoot streaming={isReasoningStreaming}>
|
|
143
143
|
<ReasoningTrigger active={isReasoningStreaming} />
|
|
144
144
|
<ReasoningContent aria-busy={isReasoningStreaming}>
|
|
145
145
|
<ReasoningText>{children}</ReasoningText>
|
|
@@ -119,6 +119,8 @@ const StreamdownText = () => (
|
|
|
119
119
|
| `components` | `object` | - | Custom components including `SyntaxHighlighter` and `CodeHeader` |
|
|
120
120
|
| `componentsByLanguage` | `object` | - | Language-specific component overrides |
|
|
121
121
|
| `preprocess` | `(text: string) => string` | - | Text preprocessing function |
|
|
122
|
+
| `defer` | `boolean` | `false` | Defer markdown parsing to a lower priority via `useDeferredValue` so typing and scrolling stay responsive during streaming |
|
|
123
|
+
| `smooth` | `boolean \| SmoothOptions` | `false` | Typewriter-style reveal via `useSmooth`; the caret and controls stay active until the reveal catches up. Prefer the native `animated` prop for entrance animations |
|
|
122
124
|
| `controls` | `boolean \| object` | `true` | Enable/disable UI controls for code blocks and tables |
|
|
123
125
|
| `caret` | `"block" \| "circle"` | - | Streaming caret style |
|
|
124
126
|
| `mermaid` | `MermaidOptions` | - | Mermaid diagram configuration |
|
|
@@ -29,7 +29,7 @@ import { SyntaxHighlightingSample } from "@/components/docs/samples/syntax-highl
|
|
|
29
29
|
|
|
30
30
|
This adds a `/components/assistant-ui/shiki-highlighter.tsx` file to your project and
|
|
31
31
|
installs the `react-shiki` dependency. The highlighter can be customized by editing
|
|
32
|
-
the config in the `shiki-highlighter.tsx` file.
|
|
32
|
+
the config in the `shiki-highlighter.tsx` file. While a message part is still streaming, the component renders the plain code without tokenization and highlights once the part settles, so streaming stays cheap.
|
|
33
33
|
|
|
34
34
|
</Step>
|
|
35
35
|
<Step>
|
|
@@ -133,6 +133,58 @@ const SuggestionItem = () => (
|
|
|
133
133
|
);
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
## Component Overrides
|
|
137
|
+
|
|
138
|
+
`Thread` accepts an optional `components` prop that swaps parts of the rendering without editing the copied file. All slots are optional; omitted slots keep the built-in rendering.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import { Thread, type ThreadComponents } from "@/components/assistant-ui/thread";
|
|
142
|
+
|
|
143
|
+
const THREAD_COMPONENTS: ThreadComponents = {
|
|
144
|
+
ToolFallback: MyToolFallback,
|
|
145
|
+
ToolGroup: MyToolGroup,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export default function Chat() {
|
|
149
|
+
return <Thread components={THREAD_COMPONENTS} />;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
<ParametersTable
|
|
154
|
+
type="ThreadComponents"
|
|
155
|
+
parameters={[
|
|
156
|
+
{
|
|
157
|
+
name: "AssistantMessage",
|
|
158
|
+
type: "ComponentType",
|
|
159
|
+
description: "Replaces the entire assistant message, including the action bar and branch picker.",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "Welcome",
|
|
163
|
+
type: "ComponentType",
|
|
164
|
+
description: "Replaces the welcome screen shown for a new chat.",
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "ToolFallback",
|
|
168
|
+
type: "ToolCallMessagePartComponent",
|
|
169
|
+
description: "Renders tool calls that have no tool UI registered by name. Registered tool UIs take precedence over this slot.",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "ToolGroup",
|
|
173
|
+
type: "ComponentType<PropsWithChildren<{ group: ThreadGroupPart }>>",
|
|
174
|
+
description: "Wraps runs of consecutive tool calls. Receives the group part (`indices`, `status`) and the rendered children.",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "ReasoningGroup",
|
|
178
|
+
type: "ComponentType<PropsWithChildren<{ group: ThreadGroupPart }>>",
|
|
179
|
+
description: "Wraps runs of consecutive reasoning parts. Receives the group part and the rendered children.",
|
|
180
|
+
},
|
|
181
|
+
]}
|
|
182
|
+
/>
|
|
183
|
+
|
|
184
|
+
Define the `components` object once at module scope (or memoize it) so message subtrees do not re-render whenever the parent re-renders.
|
|
185
|
+
|
|
186
|
+
For per-tool UI, prefer registering a renderer by tool name over overriding `ToolFallback`: put `render` on the matching toolkit entry (see [Tool UI](/docs/tools/tool-ui)). `data` message parts render through renderers registered with `useAssistantDataUI`; parts without a registered renderer are not displayed.
|
|
187
|
+
|
|
136
188
|
## API Reference
|
|
137
189
|
|
|
138
190
|
The following primitives are used within the Thread component and can be customized in your `/components/assistant-ui/thread.tsx` file.
|
|
@@ -74,7 +74,7 @@ Shows a muted appearance when a tool call was cancelled.
|
|
|
74
74
|
|
|
75
75
|
### Approval State
|
|
76
76
|
|
|
77
|
-
Shows the default Allow / Deny buttons rendered when a tool call enters `requires-action`. The block auto-expands so the decision is visible without a click. Edit your project's copy of `tool-fallback.tsx` to add trust escalation, edit-args, custom labels, or analytics hooks — the shadcn philosophy is you own the file.
|
|
77
|
+
Shows the default Allow / Deny buttons rendered when a tool call enters `requires-action`. A tool call whose approval gate is already decided renders no buttons. The block auto-expands so the decision is visible without a click. Edit your project's copy of `tool-fallback.tsx` to add trust escalation, edit-args, custom labels, or analytics hooks — the shadcn philosophy is you own the file.
|
|
78
78
|
|
|
79
79
|
<ToolFallbackRequiresActionSample />
|
|
80
80
|
|
|
@@ -90,7 +90,7 @@ All sub-components are exported for custom layouts:
|
|
|
90
90
|
| `ToolFallback.Args` | Displays tool arguments |
|
|
91
91
|
| `ToolFallback.Result` | Displays tool execution result |
|
|
92
92
|
| `ToolFallback.Error` | Displays error or cancellation messages |
|
|
93
|
-
| `ToolFallback.Approval` | Renders Allow / Deny buttons for `requires-action` tools; wires `resume` / `addResult` / `respondToApproval` |
|
|
93
|
+
| `ToolFallback.Approval` | Renders Allow / Deny buttons for `requires-action` tools until a decision is recorded; wires `resume` / `addResult` / `respondToApproval` |
|
|
94
94
|
|
|
95
95
|
```tsx
|
|
96
96
|
import {
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: react-o11y
|
|
3
|
-
description: Headless primitives for visualizing observability spans
|
|
3
|
+
description: Headless primitives for visualizing observability spans as collapsible trace trees, waterfalls, and agent and LLM call timelines.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
import { WaterfallSample } from "@/components/docs/samples/o11y/waterfall";
|
|
8
|
+
import {
|
|
9
|
+
StatusSample,
|
|
10
|
+
CollapseSample,
|
|
11
|
+
StreamingSample,
|
|
12
|
+
} from "@/components/docs/samples/o11y/capability-samples";
|
|
13
|
+
|
|
7
14
|
<Callout type="warn">
|
|
8
|
-
`@assistant-ui/react-o11y` is
|
|
15
|
+
`@assistant-ui/react-o11y` is experimental. The API may change without notice.
|
|
9
16
|
</Callout>
|
|
10
17
|
|
|
11
18
|
`@assistant-ui/react-o11y` provides headless, Radix-style primitives for rendering observability spans as collapsible, indented hierarchical UIs. Use it to build trace inspectors, waterfall debug panels, or LLM call timelines on top of your own span data source.
|
|
@@ -15,6 +22,10 @@ platforms: ["react"]
|
|
|
15
22
|
- **Tree-aware** — Automatic depth, parent / child collapse, time range computation.
|
|
16
23
|
- **Reactive** — Built on the same reactive core as the runtimes, so spans stream into your UI as they change.
|
|
17
24
|
|
|
25
|
+
<div className="not-prose my-6">
|
|
26
|
+
<WaterfallSample />
|
|
27
|
+
</div>
|
|
28
|
+
|
|
18
29
|
## Installation
|
|
19
30
|
|
|
20
31
|
<InstallCommand npm={["@assistant-ui/react-o11y"]} />
|
|
@@ -43,13 +54,12 @@ function SpanRow() {
|
|
|
43
54
|
<SpanPrimitive.StatusIndicator className="size-2 rounded-full data-[span-status=running]:bg-yellow-500 data-[span-status=completed]:bg-green-500 data-[span-status=failed]:bg-red-500" />
|
|
44
55
|
<SpanPrimitive.TypeBadge className="rounded bg-muted px-1.5 text-xs" />
|
|
45
56
|
<SpanPrimitive.Name className="text-sm" />
|
|
46
|
-
<SpanPrimitive.Children components={{ Span: SpanRow }} />
|
|
47
57
|
</SpanPrimitive.Root>
|
|
48
58
|
);
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
export function TraceView({ spans }: { spans: SpanData[] }) {
|
|
52
|
-
const aui = useAui({
|
|
62
|
+
const aui = useAui({ span: SpanResource({ spans }) });
|
|
53
63
|
|
|
54
64
|
return (
|
|
55
65
|
<AuiProvider value={aui}>
|
|
@@ -61,6 +71,32 @@ export function TraceView({ spans }: { spans: SpanData[] }) {
|
|
|
61
71
|
|
|
62
72
|
`SpanData` is the input shape your code produces (see [SpanData](#spandata)). `SpanResource` enriches it with depth, child counts, time range, and collapse state.
|
|
63
73
|
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
### Status states
|
|
77
|
+
|
|
78
|
+
`data-span-status` exposes each span's lifecycle, so running, completed, failed, and skipped are styled with pure CSS.
|
|
79
|
+
|
|
80
|
+
<div className="not-prose my-6">
|
|
81
|
+
<StatusSample />
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
### Collapsible subtrees
|
|
85
|
+
|
|
86
|
+
`SpanPrimitive.CollapseToggle` removes a span's descendants from the visible flat list, not just hides them. Click a chevron to collapse a subtree.
|
|
87
|
+
|
|
88
|
+
<div className="not-prose my-6">
|
|
89
|
+
<CollapseSample />
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
### Streaming spans
|
|
93
|
+
|
|
94
|
+
`SpanResource` re-derives the tree whenever the `spans` prop changes, so spans stream in and update live.
|
|
95
|
+
|
|
96
|
+
<div className="not-prose my-6">
|
|
97
|
+
<StreamingSample />
|
|
98
|
+
</div>
|
|
99
|
+
|
|
64
100
|
## Anatomy
|
|
65
101
|
|
|
66
102
|
```tsx
|
|
@@ -71,7 +107,7 @@ import {
|
|
|
71
107
|
} from "@assistant-ui/react-o11y";
|
|
72
108
|
|
|
73
109
|
// Top-level: mount SpanResource via useAui
|
|
74
|
-
const aui = useAui({
|
|
110
|
+
const aui = useAui({ span: SpanResource({ spans }) });
|
|
75
111
|
|
|
76
112
|
<AuiProvider value={aui}>
|
|
77
113
|
{/* Render visible spans (flat-list output respecting collapsed state) */}
|
|
@@ -104,7 +140,7 @@ Resource that ingests raw span data and exposes a tree-aware reactive state to p
|
|
|
104
140
|
SpanResource({ spans }: { spans: SpanData[] }): ClientOutput<"span">;
|
|
105
141
|
```
|
|
106
142
|
|
|
107
|
-
Mount through `useAui({
|
|
143
|
+
Mount through `useAui({ span: SpanResource({ spans }) })`.
|
|
108
144
|
|
|
109
145
|
The resource computes:
|
|
110
146
|
|
|
@@ -243,6 +279,56 @@ Convenience component that pairs `SpanByIndexProvider` with a render component:
|
|
|
243
279
|
|
|
244
280
|
Useful when you want explicit control over which child indices to render (e.g. for virtualization).
|
|
245
281
|
|
|
282
|
+
### SpanPrimitive.Timeline
|
|
283
|
+
|
|
284
|
+
A `<div>` that provides a timeline range to descendant `TimelineBar` primitives and exposes range CSS variables.
|
|
285
|
+
|
|
286
|
+
| Prop | Type | Default | Description |
|
|
287
|
+
| --- | --- | --- | --- |
|
|
288
|
+
| `timeRange` | `{ min: number; max: number }` | `span.timeRange` | Override the range used for positioning bars. |
|
|
289
|
+
| `paddingEnd` | `number` | `0` | Extends the max by this ratio of the range duration, useful for right-side breathing room. |
|
|
290
|
+
|
|
291
|
+
Exposes `data-span-timeline` and CSS variables:
|
|
292
|
+
|
|
293
|
+
| Variable | Description |
|
|
294
|
+
| --- | --- |
|
|
295
|
+
| `--span-timeline-min-ms` | Timeline start timestamp. |
|
|
296
|
+
| `--span-timeline-max-ms` | Timeline end timestamp after padding. |
|
|
297
|
+
| `--span-timeline-range-ms` | Timeline duration after padding. |
|
|
298
|
+
|
|
299
|
+
### SpanPrimitive.TimelineBar
|
|
300
|
+
|
|
301
|
+
A `<div>` that positions the current span within the nearest `SpanPrimitive.Timeline` range. It reads `startedAt`, `endedAt`, `status`, `type`, and `timeRange` from the current span scope.
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
<SpanPrimitive.Timeline>
|
|
305
|
+
<SpanPrimitive.Children>
|
|
306
|
+
{() => (
|
|
307
|
+
<div className="relative h-8">
|
|
308
|
+
<SpanPrimitive.TimelineBar className="top-1 h-6 rounded bg-blue-500" />
|
|
309
|
+
</div>
|
|
310
|
+
)}
|
|
311
|
+
</SpanPrimitive.Children>
|
|
312
|
+
</SpanPrimitive.Timeline>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Running spans use the timeline range max when `now` is omitted, keeping SSR and hydration deterministic. For live ticking, update a timestamp from an effect or animation loop and pass it as `now`.
|
|
316
|
+
|
|
317
|
+
| Prop | Type | Default | Description |
|
|
318
|
+
| --- | --- | --- | --- |
|
|
319
|
+
| `now` | `number` | `undefined` | Explicit timestamp used as the end of running spans. |
|
|
320
|
+
| `timeRange` | `{ min: number; max: number }` | nearest `Timeline` range | Override the range used for this bar. |
|
|
321
|
+
|
|
322
|
+
Exposes `data-span-status`, `data-span-type`, `data-span-running`, and these CSS variables:
|
|
323
|
+
|
|
324
|
+
| Variable | Description |
|
|
325
|
+
| --- | --- |
|
|
326
|
+
| `--span-timeline-left` | Bar start position as a percentage. |
|
|
327
|
+
| `--span-timeline-end` | Bar end position as a percentage. |
|
|
328
|
+
| `--span-timeline-width` | Bar width as a percentage. |
|
|
329
|
+
| `--span-timeline-duration-ms` | Bar duration in milliseconds. |
|
|
330
|
+
| `--span-timeline-min-width` | Optional consumer-set minimum width used by the default inline size. |
|
|
331
|
+
|
|
246
332
|
## Styling
|
|
247
333
|
|
|
248
334
|
All primitives forward refs and accept standard DOM props (`className`, `style`, etc.). Use the data attributes for state-based styling:
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;cAca,MAAA,EAAM,SAGjB;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;cAca,MAAA,EAAM,SAGjB;AAAA,iBAuBoB,SAAA,IAAS,OAAA"}
|
package/dist/index.js
CHANGED
|
@@ -12,8 +12,24 @@ const server = new McpServer({
|
|
|
12
12
|
name: "assistant-ui-docs",
|
|
13
13
|
version: packageJson.version
|
|
14
14
|
});
|
|
15
|
-
server.
|
|
16
|
-
|
|
15
|
+
server.registerTool(docsTools.name, {
|
|
16
|
+
title: "assistant-ui Documentation",
|
|
17
|
+
description: docsTools.description,
|
|
18
|
+
inputSchema: docsTools.parameters,
|
|
19
|
+
annotations: {
|
|
20
|
+
readOnlyHint: true,
|
|
21
|
+
openWorldHint: false
|
|
22
|
+
}
|
|
23
|
+
}, docsTools.execute);
|
|
24
|
+
server.registerTool(examplesTools.name, {
|
|
25
|
+
title: "assistant-ui Examples",
|
|
26
|
+
description: examplesTools.description,
|
|
27
|
+
inputSchema: examplesTools.parameters,
|
|
28
|
+
annotations: {
|
|
29
|
+
readOnlyHint: true,
|
|
30
|
+
openWorldHint: false
|
|
31
|
+
}
|
|
32
|
+
}, examplesTools.execute);
|
|
17
33
|
async function runServer() {
|
|
18
34
|
try {
|
|
19
35
|
logger.info(`Starting assistant-ui MCP docs server v${packageJson.version}`);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { docsTools } from \"./tools/docs.js\";\nimport { examplesTools } from \"./tools/examples.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { PACKAGE_DIR } from \"./constants.js\";\n\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst packageJson = JSON.parse(\n readFileSync(join(PACKAGE_DIR, \"package.json\"), \"utf-8\"),\n);\n\nexport const server = new McpServer({\n name: \"assistant-ui-docs\",\n version: packageJson.version,\n});\n\nserver.
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { docsTools } from \"./tools/docs.js\";\nimport { examplesTools } from \"./tools/examples.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { PACKAGE_DIR } from \"./constants.js\";\n\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nconst packageJson = JSON.parse(\n readFileSync(join(PACKAGE_DIR, \"package.json\"), \"utf-8\"),\n);\n\nexport const server = new McpServer({\n name: \"assistant-ui-docs\",\n version: packageJson.version,\n});\n\nserver.registerTool(\n docsTools.name,\n {\n title: \"assistant-ui Documentation\",\n description: docsTools.description,\n inputSchema: docsTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n docsTools.execute,\n);\nserver.registerTool(\n examplesTools.name,\n {\n title: \"assistant-ui Examples\",\n description: examplesTools.description,\n inputSchema: examplesTools.parameters,\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n examplesTools.execute,\n);\n\nexport async function runServer() {\n try {\n logger.info(\n `Starting assistant-ui MCP docs server v${packageJson.version}`,\n );\n const transport = new StdioServerTransport();\n await server.connect(transport);\n } catch (error) {\n logger.error(\"Failed to start MCP server\", error);\n process.exit(1);\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n void runServer().catch((error) => {\n console.error(\"Failed to start server:\", error);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,cAAc,KAAK,MACvB,aAAa,KAAK,aAAa,cAAc,GAAG,OAAO,CACzD;AAEA,MAAa,SAAS,IAAI,UAAU;CAClC,MAAM;CACN,SAAS,YAAY;AACvB,CAAC;AAED,OAAO,aACL,UAAU,MACV;CACE,OAAO;CACP,aAAa,UAAU;CACvB,aAAa,UAAU;CACvB,aAAa;EAAE,cAAc;EAAM,eAAe;CAAM;AAC1D,GACA,UAAU,OACZ;AACA,OAAO,aACL,cAAc,MACd;CACE,OAAO;CACP,aAAa,cAAc;CAC3B,aAAa,cAAc;CAC3B,aAAa;EAAE,cAAc;EAAM,eAAe;CAAM;AAC1D,GACA,cAAc,OAChB;AAEA,eAAsB,YAAY;CAChC,IAAI;EACF,OAAO,KACL,0CAA0C,YAAY,SACxD;EACA,MAAM,YAAY,IAAI,qBAAqB;EAC3C,MAAM,OAAO,QAAQ,SAAS;CAChC,SAAS,OAAO;EACd,OAAO,MAAM,8BAA8B,KAAK;EAChD,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,IAAI,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,MAC7C,UAAe,CAAC,CAAC,OAAO,UAAU;CAChC,QAAQ,MAAM,2BAA2B,KAAK;CAC9C,QAAQ,KAAK,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/mcp-docs-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "MCP server for assistant-ui documentation and examples",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"zod": "^4.4.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@types/node": "^
|
|
40
|
+
"@types/node": "^26.0.0",
|
|
41
41
|
"tsx": "^4.22.4",
|
|
42
|
-
"vitest": "^4.1.
|
|
43
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
42
|
+
"vitest": "^4.1.9",
|
|
43
|
+
"@assistant-ui/x-buildutils": "0.0.16"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public",
|
package/src/index.ts
CHANGED
|
@@ -17,16 +17,24 @@ export const server = new McpServer({
|
|
|
17
17
|
version: packageJson.version,
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
server.
|
|
20
|
+
server.registerTool(
|
|
21
21
|
docsTools.name,
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
{
|
|
23
|
+
title: "assistant-ui Documentation",
|
|
24
|
+
description: docsTools.description,
|
|
25
|
+
inputSchema: docsTools.parameters,
|
|
26
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
27
|
+
},
|
|
24
28
|
docsTools.execute,
|
|
25
29
|
);
|
|
26
|
-
server.
|
|
30
|
+
server.registerTool(
|
|
27
31
|
examplesTools.name,
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
{
|
|
33
|
+
title: "assistant-ui Examples",
|
|
34
|
+
description: examplesTools.description,
|
|
35
|
+
inputSchema: examplesTools.parameters,
|
|
36
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
37
|
+
},
|
|
30
38
|
examplesTools.execute,
|
|
31
39
|
);
|
|
32
40
|
|
|
@@ -73,6 +73,15 @@ describe("MCP Protocol Integration", () => {
|
|
|
73
73
|
expect(examplesTool.inputSchema).toBeDefined();
|
|
74
74
|
expect(examplesTool.inputSchema.type).toBe("object");
|
|
75
75
|
expect(examplesTool.inputSchema.properties).toBeDefined();
|
|
76
|
+
|
|
77
|
+
// registerTool metadata is surfaced on tools/list: `title` is a
|
|
78
|
+
// top-level field, `annotations` carries only the hint flags.
|
|
79
|
+
expect(docsTool.title).toBe("assistant-ui Documentation");
|
|
80
|
+
expect(docsTool.annotations?.readOnlyHint).toBe(true);
|
|
81
|
+
expect(docsTool.annotations?.openWorldHint).toBe(false);
|
|
82
|
+
expect(examplesTool.title).toBe("assistant-ui Examples");
|
|
83
|
+
expect(examplesTool.annotations?.readOnlyHint).toBe(true);
|
|
84
|
+
expect(examplesTool.annotations?.openWorldHint).toBe(false);
|
|
76
85
|
});
|
|
77
86
|
|
|
78
87
|
it("should handle CallTool request for assistantUIDocs", async () => {
|