@assistant-ui/mcp-docs-server 0.1.31 → 0.1.32
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 +8 -8
- package/.docs/organized/code-examples/with-a2a.md +10 -10
- package/.docs/organized/code-examples/with-ag-ui.md +11 -11
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +13 -13
- package/.docs/organized/code-examples/with-artifacts.md +13 -13
- package/.docs/organized/code-examples/with-assistant-transport.md +10 -10
- package/.docs/organized/code-examples/with-browser-extension.md +345 -0
- package/.docs/organized/code-examples/with-chain-of-thought.md +54 -17
- package/.docs/organized/code-examples/with-cloud-standalone.md +13 -13
- package/.docs/organized/code-examples/with-cloud.md +13 -13
- package/.docs/organized/code-examples/with-custom-thread-list.md +13 -13
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +17 -16
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +17 -16
- package/.docs/organized/code-examples/with-expo.md +24 -24
- package/.docs/organized/code-examples/with-external-store.md +10 -10
- package/.docs/organized/code-examples/with-ffmpeg.md +13 -13
- package/.docs/organized/code-examples/with-generative-ui.md +210 -13
- package/.docs/organized/code-examples/with-google-adk.md +10 -10
- package/.docs/organized/code-examples/with-heat-graph.md +8 -8
- package/.docs/organized/code-examples/with-image-generation.md +454 -0
- package/.docs/organized/code-examples/with-interactables.md +13 -13
- package/.docs/organized/code-examples/with-langchain.md +12 -12
- package/.docs/organized/code-examples/with-langgraph.md +15 -12
- package/.docs/organized/code-examples/with-livekit.md +18 -17
- package/.docs/organized/code-examples/with-mcp.md +748 -0
- package/.docs/organized/code-examples/with-opencode.md +11 -11
- package/.docs/organized/code-examples/with-parent-id-grouping.md +11 -11
- package/.docs/organized/code-examples/with-react-hook-form.md +14 -14
- package/.docs/organized/code-examples/with-react-ink.md +4 -4
- package/.docs/organized/code-examples/with-react-router.md +15 -15
- package/.docs/organized/code-examples/with-resumable-stream.md +660 -0
- package/.docs/organized/code-examples/with-store.md +8 -8
- package/.docs/organized/code-examples/with-tanstack.md +14 -14
- package/.docs/organized/code-examples/with-tap-runtime.md +11 -10
- package/.docs/raw/docs/(docs)/cli.mdx +1 -0
- package/.docs/raw/docs/(docs)/index.mdx +2 -2
- package/.docs/raw/docs/(docs)/installation.mdx +1 -1
- package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +26 -24
- package/.docs/raw/docs/(reference)/api-reference/adapters/feedback.mdx +20 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +20 -12
- package/.docs/raw/docs/(reference)/api-reference/adapters/model.mdx +44 -0
- package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +37 -16
- package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +12 -23
- package/.docs/raw/docs/(reference)/api-reference/adapters/suggestions.mdx +20 -0
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +37 -8
- package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +11 -9
- package/.docs/raw/docs/(reference)/api-reference/context-providers/scoped-providers.mdx +64 -0
- package/.docs/raw/docs/(reference)/api-reference/external-store/index.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +52 -0
- package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +36 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +98 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +18 -13
- package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +18 -57
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +640 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +15 -28
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +64 -18
- package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +434 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/cloud-ai-sdk.mdx +24 -0
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +11 -12
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +79 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +52 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/index.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/registry.mdx +20 -0
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +110 -131
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +78 -221
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +127 -242
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +39 -20
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +66 -87
- package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +50 -58
- package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +80 -48
- package/.docs/raw/docs/(reference)/api-reference/primitives/chain-of-thought.mdx +67 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +323 -461
- package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +36 -43
- package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +29 -24
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +63 -245
- package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +175 -591
- package/.docs/raw/docs/(reference)/api-reference/primitives/queue-item.mdx +65 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +35 -22
- package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +57 -140
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +70 -161
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +84 -108
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +77 -96
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +173 -349
- package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +9 -21
- package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +10 -21
- package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +15 -70
- package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +18 -13
- package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +25 -28
- package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +11 -63
- package/.docs/raw/docs/(reference)/api-reference/runtimes/queue-state.mdx +20 -0
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +11 -48
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +10 -47
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +18 -30
- package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +68 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +39 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +79 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +42 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +92 -0
- package/.docs/raw/docs/(reference)/api-reference/transport/assistant-transport.mdx +48 -0
- package/.docs/raw/docs/(reference)/api-reference/transport/frame.mdx +62 -0
- package/.docs/raw/docs/(reference)/api-reference/transport/index.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/utilities/index.mdx +19 -0
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +131 -0
- package/.docs/raw/docs/(reference)/api-reference/voice/index.mdx +22 -0
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +54 -0
- package/.docs/raw/docs/(reference)/api-reference/voice/speech-dictation.mdx +36 -0
- package/.docs/raw/docs/cloud/ai-sdk.mdx +1 -1
- package/.docs/raw/docs/cloud/index.mdx +2 -2
- package/.docs/raw/docs/guides/attachments.mdx +4 -4
- package/.docs/raw/docs/guides/branching.mdx +1 -1
- package/.docs/raw/docs/guides/chain-of-thought.mdx +5 -5
- package/.docs/raw/docs/guides/context-api.mdx +4 -4
- package/.docs/raw/docs/guides/dictation.mdx +2 -2
- package/.docs/raw/docs/guides/editing.mdx +1 -1
- package/.docs/raw/docs/guides/generative-ui.mdx +142 -0
- package/.docs/raw/docs/guides/image-generation.mdx +74 -0
- package/.docs/raw/docs/guides/index.mdx +2 -2
- package/.docs/raw/docs/guides/interactables.mdx +2 -2
- package/.docs/raw/docs/guides/latex.mdx +2 -2
- package/.docs/raw/docs/guides/mcp-apps.mdx +231 -0
- package/.docs/raw/docs/guides/mentions.mdx +2 -2
- package/.docs/raw/docs/guides/message-timing.mdx +38 -5
- package/.docs/raw/docs/guides/multi-agent.mdx +2 -2
- package/.docs/raw/docs/guides/quoting.mdx +1 -1
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +212 -0
- package/.docs/raw/docs/guides/resumable-stream-stores.mdx +152 -0
- package/.docs/raw/docs/guides/resumable-streams.mdx +210 -0
- package/.docs/raw/docs/guides/slash-commands.mdx +1 -1
- package/.docs/raw/docs/guides/speech.mdx +2 -2
- package/.docs/raw/docs/guides/suggestions.mdx +88 -4
- package/.docs/raw/docs/guides/tool-ui.mdx +2 -2
- package/.docs/raw/docs/guides/tools.mdx +66 -5
- package/.docs/raw/docs/guides/voice.mdx +2 -2
- package/.docs/raw/docs/ink/adapters.mdx +37 -1
- package/.docs/raw/docs/ink/custom-backend.mdx +59 -8
- package/.docs/raw/docs/ink/index.mdx +10 -11
- package/.docs/raw/docs/ink/primitives.mdx +349 -8
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/clerk.mdx +1 -1
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +2 -2
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +282 -0
- package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +2 -2
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
- package/.docs/raw/docs/integrations/gateways/index.mdx +9 -4
- package/.docs/raw/docs/integrations/index.mdx +15 -3
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +8 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +8 -4
- package/.docs/raw/docs/integrations/tools/react-mcp.mdx +337 -0
- package/.docs/raw/docs/primitives/composer.mdx +53 -0
- package/.docs/raw/docs/primitives/index.mdx +2 -2
- package/.docs/raw/docs/primitives/suggestion.mdx +9 -0
- package/.docs/raw/docs/react-native/hooks.mdx +2 -2
- package/.docs/raw/docs/react-native/index.mdx +4 -4
- package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +4 -4
- package/.docs/raw/docs/runtimes/a2a/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +32 -1
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +7 -2
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +1 -1
- package/.docs/raw/docs/runtimes/ai-sdk/v6.mdx +7 -0
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +27 -2
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +9 -1
- package/.docs/raw/docs/runtimes/custom/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/google-adk/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +1 -1
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +12 -5
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +11 -1
- package/.docs/raw/docs/ui/mcp-config.mdx +102 -0
- package/.docs/raw/docs/ui/model-selector.mdx +8 -8
- package/.docs/raw/docs/ui/sources.mdx +17 -0
- package/.docs/raw/docs/ui/streamdown.mdx +34 -2
- package/.docs/raw/docs/ui/thread-list.mdx +2 -2
- package/.docs/raw/docs/ui/thread.mdx +2 -2
- package/README.md +14 -72
- package/dist/constants.d.ts +12 -9
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +13 -9
- package/dist/constants.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -24
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.d.ts +4 -1
- package/dist/prepare-docs/code-examples.d.ts.map +1 -1
- package/dist/prepare-docs/code-examples.js +109 -121
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/copy-raw.d.ts +4 -1
- package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
- package/dist/prepare-docs/copy-raw.js +45 -42
- package/dist/prepare-docs/copy-raw.js.map +1 -1
- package/dist/prepare-docs/prepare.d.ts +1 -2
- package/dist/prepare-docs/prepare.js +17 -17
- package/dist/prepare-docs/prepare.js.map +1 -1
- package/dist/stdio.d.ts +1 -3
- package/dist/stdio.js +6 -3
- package/dist/stdio.js.map +1 -1
- package/dist/tools/docs.d.ts +20 -15
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +140 -161
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +20 -15
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +74 -86
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/tests/test-setup.d.ts +5 -2
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/tests/test-setup.js +21 -28
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/utils/logger.d.ts +8 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +17 -17
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/mcp-format.d.ts +8 -5
- package/dist/utils/mcp-format.d.ts.map +1 -1
- package/dist/utils/mcp-format.js +9 -9
- package/dist/utils/mcp-format.js.map +1 -1
- package/dist/utils/mdx.d.ts +8 -6
- package/dist/utils/mdx.d.ts.map +1 -1
- package/dist/utils/mdx.js +22 -22
- package/dist/utils/mdx.js.map +1 -1
- package/dist/utils/paths.d.ts +9 -6
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +66 -76
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/security.d.ts +4 -1
- package/dist/utils/security.d.ts.map +1 -1
- package/dist/utils/security.js +19 -40
- package/dist/utils/security.js.map +1 -1
- package/package.json +5 -5
- package/.docs/raw/docs/(reference)/api-reference/adapters/feedback-speech.mdx +0 -41
- package/.docs/raw/docs/(reference)/api-reference/context-providers/text-message-part-provider.mdx +0 -40
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +0 -260
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-hook-form.mdx +0 -103
- package/.docs/raw/docs/(reference)/api-reference/integrations/vercel-ai-sdk.mdx +0 -254
- package/dist/prepare-docs/prepare.d.ts.map +0 -1
- package/dist/stdio.d.ts.map +0 -1
- /package/.docs/raw/docs/{(reference)/migrations → migrations}/deprecation-policy.mdx +0 -0
- /package/.docs/raw/docs/{(reference) → migrations}/react-compatibility.mdx +0 -0
- /package/.docs/raw/docs/{(reference)/migrations → migrations}/react-langgraph-v0-7.mdx +0 -0
- /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-11.mdx +0 -0
- /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-12.mdx +0 -0
- /package/.docs/raw/docs/{(reference)/migrations → migrations}/v0-14.mdx +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Chain of Thought
|
|
3
|
-
description:
|
|
2
|
+
title: Chain of Thought UI
|
|
3
|
+
description: Show AI reasoning steps and tool calls in a collapsible thinking accordion. Build chain-of-thought visualizations in React chat with assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ LLMs often produce reasoning steps and tool calls in succession. Chain of Though
|
|
|
8
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
|
|
11
|
-
When a model
|
|
11
|
+
When a reasoning model responds, it may emit a sequence of reasoning tokens and tool calls before producing its final text answer. Use `MessagePrimitive.GroupedParts` to group those adjacent reasoning and tool-call parts into a single collapsible "thinking" section.
|
|
12
12
|
|
|
13
13
|
<Callout type="info">
|
|
14
14
|
The older `components.ChainOfThought` prop on `MessagePrimitive.Parts` and `components` prop on `ChainOfThoughtPrimitive.Parts` are legacy APIs. They still work for existing code, but new code should use `MessagePrimitive.GroupedParts`.
|
|
@@ -101,7 +101,7 @@ const AssistantMessage: FC = () => {
|
|
|
101
101
|
|
|
102
102
|
### Use a Reasoning Model
|
|
103
103
|
|
|
104
|
-
Chain of Thought is most useful with models that produce reasoning tokens
|
|
104
|
+
Chain of Thought is most useful with models that produce reasoning tokens. Here's an example backend route using the AI SDK:
|
|
105
105
|
|
|
106
106
|
```tsx title="app/api/chat/route.ts"
|
|
107
107
|
import { openai } from "@ai-sdk/openai";
|
|
@@ -111,7 +111,7 @@ export async function POST(req: Request) {
|
|
|
111
111
|
const { messages } = await req.json();
|
|
112
112
|
|
|
113
113
|
const result = streamText({
|
|
114
|
-
model: openai("
|
|
114
|
+
model: openai("gpt-5.4-mini"),
|
|
115
115
|
messages: await convertToModelMessages(messages),
|
|
116
116
|
});
|
|
117
117
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Context API
|
|
3
|
-
description: Read and update assistant state to build custom components.
|
|
2
|
+
title: Assistant Context API
|
|
3
|
+
description: Read and update assistant state to build custom React components in your chat UI — composable context API for thread, message, and runtime data via assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -258,8 +258,8 @@ useAuiEvent("composer.send", (event) => {
|
|
|
258
258
|
});
|
|
259
259
|
|
|
260
260
|
// Listen to thread events
|
|
261
|
-
useAuiEvent("thread.
|
|
262
|
-
console.log("
|
|
261
|
+
useAuiEvent("thread.modelContextUpdate", (event) => {
|
|
262
|
+
console.log("Model context updated in thread:", event.threadId);
|
|
263
263
|
});
|
|
264
264
|
|
|
265
265
|
// Listen to all events of a type across all scopes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Speech-to-Text
|
|
3
|
-
description:
|
|
2
|
+
title: Speech-to-Text Dictation
|
|
3
|
+
description: Add voice dictation to your AI chat composer with the Web Speech API or a custom adapter. Speech-to-text in React, integrated through assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Message Editing
|
|
3
|
-
description:
|
|
3
|
+
description: Let users edit their messages and regenerate AI responses with custom editor interfaces. Edit-and-resubmit patterns for React chat via assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Generative UI
|
|
3
|
+
description: Render agent-described React UI from a JSON spec with a consumer-provided component allowlist.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`MessagePrimitive.GenerativeUI` is a first-class primitive for rendering UI
|
|
7
|
+
described by the agent at runtime as a JSON spec. Instead of hard-coding a
|
|
8
|
+
component per tool, the agent emits a `generative-ui` message part containing
|
|
9
|
+
a tree of components by name. assistant-ui resolves each name against a
|
|
10
|
+
**consumer-provided allowlist** and renders the result.
|
|
11
|
+
|
|
12
|
+
> The allowlist controls **which** components the agent may render: any name
|
|
13
|
+
> not in it throws a typed `GenerativeUIRenderError` (no implicit fallback). It
|
|
14
|
+
> does not constrain the props passed to those components; see [Security](#security).
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
### 1. Define your component allowlist
|
|
19
|
+
|
|
20
|
+
```tsx title="components/gui.tsx"
|
|
21
|
+
const Card = ({ title, children }) => (
|
|
22
|
+
<div className="rounded-xl border bg-card p-4 shadow-sm">
|
|
23
|
+
<div className="text-base font-semibold">{title}</div>
|
|
24
|
+
<div className="mt-2">{children}</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const Button = ({ label }) => (
|
|
29
|
+
<button className="rounded-md bg-primary px-3 py-1.5 text-primary-foreground">
|
|
30
|
+
{label}
|
|
31
|
+
</button>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const componentsAllowlist = { Card, Button };
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Wire the primitive into your message renderer
|
|
38
|
+
|
|
39
|
+
```tsx title="components/assistant-message.tsx"
|
|
40
|
+
import { MessagePrimitive } from "@assistant-ui/react";
|
|
41
|
+
import { componentsAllowlist } from "./gui";
|
|
42
|
+
|
|
43
|
+
export function AssistantMessage() {
|
|
44
|
+
return (
|
|
45
|
+
<MessagePrimitive.Parts
|
|
46
|
+
components={{
|
|
47
|
+
generativeUI: { components: componentsAllowlist },
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You can also use the standalone primitive form:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<MessagePrimitive.GenerativeUI components={componentsAllowlist} />
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 3. Have the agent emit a `generative-ui` part
|
|
61
|
+
|
|
62
|
+
A `GenerativeUIMessagePart` carries a JSON spec:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
{
|
|
66
|
+
type: "generative-ui",
|
|
67
|
+
spec: {
|
|
68
|
+
root: {
|
|
69
|
+
component: "Card",
|
|
70
|
+
props: { title: "Welcome" },
|
|
71
|
+
children: [
|
|
72
|
+
{ component: "Button", props: { label: "Get started" } },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Bare strings act as inline text leaves.
|
|
80
|
+
|
|
81
|
+
## Spec shape
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
type GenerativeUINode =
|
|
85
|
+
| string
|
|
86
|
+
| {
|
|
87
|
+
component: string; // resolved against the allowlist
|
|
88
|
+
props?: Record<string, unknown>;
|
|
89
|
+
children?: GenerativeUINode[];
|
|
90
|
+
key?: string; // optional stable React key
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type GenerativeUISpec = {
|
|
94
|
+
root: GenerativeUINode | GenerativeUINode[];
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The spec is plain JSON — easy for any agent to emit, and easy to validate
|
|
99
|
+
on the server before delivery.
|
|
100
|
+
|
|
101
|
+
## Streaming
|
|
102
|
+
|
|
103
|
+
The primitive is stream-friendly: any partial spec renders progressively. As
|
|
104
|
+
new nodes arrive (filling in `children`, refining `props`), the rendered tree
|
|
105
|
+
updates without reflows or lost local state for already-mounted children.
|
|
106
|
+
|
|
107
|
+
## Security
|
|
108
|
+
|
|
109
|
+
The allowlist is the boundary on **which** components render: a spec can only instantiate components you put in the registry, with no `eval` and no dynamic import (names are looked up in the registry and nothing else). An unknown name throws `GenerativeUIRenderError` or invokes your `Fallback`.
|
|
110
|
+
|
|
111
|
+
It does **not** constrain the `props` the agent supplies. Spec props are spread directly onto your allowlisted components, so treat every allowlisted component as receiving untrusted input: never forward agent-supplied props into `dangerouslySetInnerHTML`, validate or reject `href` / `src` values (for example block `javascript:` URLs), and avoid passing spec props anywhere they become executable. The safest allowlisted components accept only primitive, display-oriented props.
|
|
112
|
+
|
|
113
|
+
## Error handling
|
|
114
|
+
|
|
115
|
+
Unknown component names throw `GenerativeUIRenderError` with a typed
|
|
116
|
+
`componentName` field. Catch it with a React error boundary, or pass a
|
|
117
|
+
`Fallback` component to opt into a soft-fail UX:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<MessagePrimitive.GenerativeUI
|
|
121
|
+
components={componentsAllowlist}
|
|
122
|
+
Fallback={({ component }) => (
|
|
123
|
+
<span className="rounded bg-muted px-1.5 py-0.5 font-mono text-xs">
|
|
124
|
+
unknown component: {component}
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Composing with other primitives
|
|
131
|
+
|
|
132
|
+
`generative-ui` is a regular `MessagePart` type, so it composes cleanly with
|
|
133
|
+
`MessagePrimitive.Parts`, `MessagePrimitive.PartByIndex`, and
|
|
134
|
+
`MessagePrimitive.GroupedParts`. Render it alongside text, tool calls, and
|
|
135
|
+
reasoning in the same message.
|
|
136
|
+
|
|
137
|
+
## Why a primitive (not just a tool)
|
|
138
|
+
|
|
139
|
+
Tool-call UI is great when the agent already invoked a known tool. Generative
|
|
140
|
+
UI flips it: the agent _composes_ UI from a vocabulary you ship. Useful for
|
|
141
|
+
forms, dashboards, status panels, multi-step flows, and anywhere the
|
|
142
|
+
component library you want is broader than a single tool's render surface.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Image Generation
|
|
3
|
+
description: Generate images in your backend and render them inline in an assistant-ui thread.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Image generation needs no dedicated primitive. Generate the image wherever you already run model calls (a route handler or a tool), store the result as an `ImageMessagePart`, and render it with the `@assistant-ui/ui` `Image` component.
|
|
7
|
+
|
|
8
|
+
<Callout type="info">
|
|
9
|
+
This covers non-streaming generation, rendering, and actions. Streaming partial images and multi-image galleries are out of scope.
|
|
10
|
+
</Callout>
|
|
11
|
+
|
|
12
|
+
## Generate in your backend
|
|
13
|
+
|
|
14
|
+
Call your provider from a server route. With the AI SDK that is `generateImage`; return the image as a data URI (or an object-store URL) plus any provider metadata you want to keep.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// app/api/image/route.ts
|
|
18
|
+
import { generateImage } from "ai";
|
|
19
|
+
import { openai } from "@ai-sdk/openai";
|
|
20
|
+
|
|
21
|
+
export async function POST(req: Request) {
|
|
22
|
+
const { prompt } = await req.json();
|
|
23
|
+
const result = await generateImage({
|
|
24
|
+
model: openai.image("gpt-image-1"),
|
|
25
|
+
prompt,
|
|
26
|
+
});
|
|
27
|
+
const revisedPrompt = (
|
|
28
|
+
result.providerMetadata as
|
|
29
|
+
| Record<string, Record<string, unknown>>
|
|
30
|
+
| undefined
|
|
31
|
+
)?.openai?.revisedPrompt;
|
|
32
|
+
return Response.json({
|
|
33
|
+
image: `data:${result.image.mediaType};base64,${result.image.base64}`,
|
|
34
|
+
mimeType: result.image.mediaType,
|
|
35
|
+
...(typeof revisedPrompt === "string" && { revisedPrompt }),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The model provider is irrelevant to rendering; swap `openai.image(...)` for any AI SDK image model.
|
|
41
|
+
|
|
42
|
+
## Store it as an `ImageMessagePart`
|
|
43
|
+
|
|
44
|
+
An `ImageMessagePart` only needs `image` (a `data:` URI, an `https://` URL, or a `blob:` URL) plus an optional `filename`. Keep any provenance you want to display, the prompt, a revised prompt, a model id, in your own component state or in message metadata; the part itself stays minimal.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const part: ImageMessagePart = {
|
|
48
|
+
type: "image",
|
|
49
|
+
image: result.image, // data:, https://, or blob: URL
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Render with the `Image` component
|
|
54
|
+
|
|
55
|
+
The `Image` component in `@assistant-ui/ui` handles the render states for you:
|
|
56
|
+
|
|
57
|
+
1. **Running** (`status.type === "running"`) renders a spinner.
|
|
58
|
+
2. **Content filter** (`status.type === "incomplete"` with `reason: "content-filter"`) renders an error card with no `<img src>`.
|
|
59
|
+
3. **Complete** renders a zoomable `<img>` with optional `Image.Actions`.
|
|
60
|
+
|
|
61
|
+
`Image.Actions` provides download and copy buttons, plus a regenerate button when you pass an `onRegenerate` callback. Wire it to the same generation flow you used above; debounce, rate limiting, and confirmation are your call.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { Image } from "@assistant-ui/ui";
|
|
65
|
+
|
|
66
|
+
<>
|
|
67
|
+
<Image {...imagePart} />
|
|
68
|
+
<Image.Actions part={imagePart} onRegenerate={() => regenerate(prompt)} />
|
|
69
|
+
</>;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Example
|
|
73
|
+
|
|
74
|
+
A complete Next.js example (with a mock fallback when `OPENAI_API_KEY` is unset) lives in [`examples/with-image-generation`](https://github.com/assistant-ui/assistant-ui/tree/main/examples/with-image-generation).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description: Practical
|
|
2
|
+
title: Guides
|
|
3
|
+
description: Practical recipes for building AI chat features in React with assistant-ui — attachments, branching, multi-agent, voice, slash commands, generative UI, and more.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description:
|
|
2
|
+
title: Interactable Components
|
|
3
|
+
description: Build persistent UI elements whose state the AI can read and update — copilot interactables in React with assistant-ui for forms, dashboards, and tools.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: LaTeX
|
|
3
|
-
description: Render
|
|
2
|
+
title: LaTeX in Chat Messages
|
|
3
|
+
description: Render LaTeX math expressions in AI chat messages with KaTeX — drop-in equation support for React chat UIs built on assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: MCP Apps
|
|
3
|
+
description: Render MCP App UI resources inline in chat. Native renderer for the Model Context Protocol Apps spec — sandboxed iframes, JSON-RPC bridge, AI SDK integration.
|
|
4
|
+
platforms: ["react"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[MCP Apps](https://apps.extensions.modelcontextprotocol.io/) lets a Model Context Protocol server ship a UI resource alongside a tool — a self-contained HTML widget that the chat host renders inline when the tool is called. assistant-ui ships a native renderer that mounts the widget in a sandboxed iframe via [`SafeContentFrame`](/safe-content-frame) and runs a JSON-RPC postMessage bridge so the widget can call tools, send messages, request a display mode, and read host context.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
When an MCP server attaches a `_meta.ui.resourceUri` (the [`text/html;profile=mcp-app`](https://apps.extensions.modelcontextprotocol.io/api/index.html) MIME) to a tool, AI SDK forwards that metadata through the message stream. assistant-ui's renderer picks it up off the `mcp` field on `ToolCallMessagePart`, fetches the resource through your backend route, and mounts it.
|
|
12
|
+
|
|
13
|
+
The renderer only acts on URIs that start with `ui://` (per the MCP Apps spec). Tools whose `resourceUri` uses any other scheme are treated as non-MCP-Apps tools and fall through to your regular tool UI.
|
|
14
|
+
|
|
15
|
+
The widget communicates back through a JSON-RPC bridge:
|
|
16
|
+
|
|
17
|
+
- **widget → host requests**: `ui/initialize`, `tools/call`, `resources/read`, `resources/list`, `openLink`, `sendMessage`, `requestDisplayMode`, `updateModelContext`
|
|
18
|
+
- **host → widget notifications**: tool input streaming, tool result, host context changes
|
|
19
|
+
- **widget → host notifications**: initialized, size changed, log, error, request teardown
|
|
20
|
+
|
|
21
|
+
Capability presence is determined at mount time by which handlers you provide. Unknown methods return JSON-RPC `-32601`; bad params return `-32602`.
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
The renderer talks to a backend route you expose — the MCP client lives server-side so credentials and transport stay out of the browser. The route receives `{ method, params }` POSTs and dispatches to your MCP client.
|
|
26
|
+
|
|
27
|
+
### Client
|
|
28
|
+
|
|
29
|
+
Compose `McpAppRenderer({...})` into your `Tools` resource. Provide `host.url` pointing at your route. Any tool-call part carrying `mcp.app` metadata renders the MCP App widget automatically.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import {
|
|
33
|
+
useAui,
|
|
34
|
+
Tools,
|
|
35
|
+
McpAppRenderer,
|
|
36
|
+
McpAppsRemoteHost,
|
|
37
|
+
} from "@assistant-ui/react";
|
|
38
|
+
|
|
39
|
+
function MyAssistant() {
|
|
40
|
+
useAui({
|
|
41
|
+
tools: Tools({
|
|
42
|
+
toolkit: myToolkit,
|
|
43
|
+
mcpApp: McpAppRenderer({
|
|
44
|
+
host: McpAppsRemoteHost({ url: "/api/mcp-apps" }),
|
|
45
|
+
hostInfo: { name: "my-app", version: "1.0.0" },
|
|
46
|
+
hostContext: { theme: "light" },
|
|
47
|
+
}),
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
// ...
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`McpAppsRemoteHost` is the default host strategy — it POSTs `{ method, params }` to your route. A different strategy (e.g. a client-side MCP client) can be plugged in by writing a custom resource that returns the same `McpAppsHost` shape (`{ loadResource, callTool, readResource, listResources }`).
|
|
55
|
+
|
|
56
|
+
`openLink` is auto-wired to `window.open(url, "_blank", "noopener,noreferrer")`. `sendMessage` is auto-wired to append a user message to the current thread (accepts `string`, `{ prompt }`, `{ text }`, or `{ message }`).
|
|
57
|
+
|
|
58
|
+
### Route handler
|
|
59
|
+
|
|
60
|
+
The route accepts `POST` requests with `{ method, params }` JSON bodies. Dispatch by method name and return the result as JSON. Example for Next.js App Router:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// app/api/mcp-apps/route.ts
|
|
64
|
+
import { experimental_createMCPClient } from "ai";
|
|
65
|
+
|
|
66
|
+
let clientPromise: ReturnType<typeof experimental_createMCPClient> | undefined;
|
|
67
|
+
const getClient = () => {
|
|
68
|
+
clientPromise ??= experimental_createMCPClient({
|
|
69
|
+
transport: { type: "sse", url: process.env.MCP_SERVER_URL! },
|
|
70
|
+
});
|
|
71
|
+
return clientPromise;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export async function POST(req: Request) {
|
|
75
|
+
const { method, params } = await req.json();
|
|
76
|
+
const client = await getClient();
|
|
77
|
+
|
|
78
|
+
switch (method) {
|
|
79
|
+
case "mcp-apps/read-resource": {
|
|
80
|
+
const { contents } = await client.readResource({ uri: params.uri });
|
|
81
|
+
const c = contents.find((x: { uri: string }) => x.uri === params.uri);
|
|
82
|
+
return Response.json({
|
|
83
|
+
uri: params.uri,
|
|
84
|
+
mimeType: "text/html;profile=mcp-app",
|
|
85
|
+
html: c?.text ?? "",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
case "tools/call": {
|
|
89
|
+
const tools = await client.tools();
|
|
90
|
+
const tool = tools[params.name];
|
|
91
|
+
if (!tool?.execute) {
|
|
92
|
+
return Response.json({ error: "Tool not callable" }, { status: 400 });
|
|
93
|
+
}
|
|
94
|
+
return Response.json(
|
|
95
|
+
await tool.execute(params.arguments ?? {}, {
|
|
96
|
+
toolCallId: `mcp-apps-bridge-${crypto.randomUUID()}`,
|
|
97
|
+
messages: [],
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
case "resources/read":
|
|
102
|
+
return Response.json(await client.readResource({ uri: params.uri }));
|
|
103
|
+
case "resources/list":
|
|
104
|
+
return Response.json(await client.listResources(params));
|
|
105
|
+
default:
|
|
106
|
+
return Response.json({ error: "Unsupported method" }, { status: 400 });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The renderer POSTs four method names: `mcp-apps/read-resource`, `tools/call`, `resources/read`, `resources/list`. Reject anything else server-side and apply your own auth / rate limiting in the route.
|
|
112
|
+
|
|
113
|
+
Per-name `setToolUI` registrations always win over the MCP fallback — you can still customize specific tools.
|
|
114
|
+
|
|
115
|
+
## AI SDK integration
|
|
116
|
+
|
|
117
|
+
`@assistant-ui/react-ai-sdk` forwards `callProviderMetadata.mcp.app` from AI SDK tool UI parts into `ToolCallMessagePart.mcp.app`. With AI SDK 5.x and an MCP-Apps-capable MCP server, no extra wiring is required on the part shape.
|
|
118
|
+
|
|
119
|
+
The rich UI comes from the MCP server's metadata, not from the model, so the path is identical whichever provider drives the conversation. Running Claude is just a different `model:` in `streamText` (`anthropic("claude-sonnet-4-6")` via `@ai-sdk/anthropic`); the MCP server, `splitMcpAppTools`, and the renderer are unchanged. MCP Apps is an open standard in the MCP ecosystem (Claude is one of its hosts), so a standard MCP-Apps server renders out of the box. The bridge below is only needed for servers that use OpenAI's `openai/outputTemplate` convention, again independent of which model you run.
|
|
120
|
+
|
|
121
|
+
On the chat route, use `splitMcpAppTools()` (from `@ai-sdk/mcp`) to keep app-only tools out of the model's view:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { splitMcpAppTools } from "@ai-sdk/mcp";
|
|
125
|
+
|
|
126
|
+
const tools = await client.listTools();
|
|
127
|
+
const { modelVisible } = splitMcpAppTools(tools);
|
|
128
|
+
|
|
129
|
+
const result = streamText({
|
|
130
|
+
model: openai("gpt-5.4-nano"),
|
|
131
|
+
tools: modelVisible.tools,
|
|
132
|
+
// ...
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### OpenAI Apps SDK servers
|
|
137
|
+
|
|
138
|
+
[OpenAI Apps SDK](https://developers.openai.com/apps-sdk) servers carry the same `ui://` template under a different convention: the pointer is `_meta["openai/outputTemplate"]` on the tool definition (not `_meta.ui.resourceUri`), and the resource is served as `text/html+skybridge` rather than `text/html;profile=mcp-app`. `@ai-sdk/mcp` does not recognize `openai/outputTemplate`, so it never populates `callProviderMetadata.mcp.app` and the renderer stays idle.
|
|
139
|
+
|
|
140
|
+
The renderer needs no change; you only have to surface the pointer. assistant-ui already reads `result._meta["ui/resourceUri"]` off tool results, so the smallest bridge is to copy the template onto the result by tool name. Build the map once from the tool listing, then stamp it inside each tool's `execute`:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import type { Tool } from "ai";
|
|
144
|
+
|
|
145
|
+
// reuse the listTools() result from the AI SDK integration step above; no second round-trip
|
|
146
|
+
const templateByTool = new Map(
|
|
147
|
+
tools.tools
|
|
148
|
+
.filter((t) => typeof t._meta?.["openai/outputTemplate"] === "string")
|
|
149
|
+
.map((t) => [t.name, t._meta["openai/outputTemplate"] as string]),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const withTemplateUri = (tool: Tool, name: string): Tool => {
|
|
153
|
+
const uri = templateByTool.get(name);
|
|
154
|
+
const exec = tool.execute;
|
|
155
|
+
if (!uri || !exec) return tool;
|
|
156
|
+
return {
|
|
157
|
+
...tool,
|
|
158
|
+
execute: async (args, options) => {
|
|
159
|
+
const result = (await exec(args, options)) as { _meta?: Record<string, unknown> };
|
|
160
|
+
return { ...result, _meta: { ...result._meta, "ui/resourceUri": uri } };
|
|
161
|
+
},
|
|
162
|
+
} satisfies Tool;
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Wrap the AI SDK tool objects before handing them to `streamText`:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const aiTools = await client.tools();
|
|
170
|
+
const wrappedTools = Object.fromEntries(
|
|
171
|
+
Object.entries(aiTools).map(([name, t]) => [name, withTemplateUri(t, name)]),
|
|
172
|
+
);
|
|
173
|
+
// pass wrappedTools to streamText
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Your `mcp-apps/read-resource` handler reads the `ui://` resource as in the route example above. Set the response `mimeType` to the `text/html;profile=mcp-app` literal that `McpAppResource` expects and keep the server's HTML in `html`; don't forward the raw `text/html+skybridge` value, which the type rejects.
|
|
177
|
+
|
|
178
|
+
The cleaner long-term fix is upstream: if `@ai-sdk/mcp`'s `getMCPAppToolMeta` also read `openai/outputTemplate`, then `callProviderMetadata.mcp.app` would populate automatically and this bridge would be unnecessary.
|
|
179
|
+
|
|
180
|
+
## Bridge protocol
|
|
181
|
+
|
|
182
|
+
The bridge implements the MCP UI JSON-RPC protocol over `window.postMessage`, filtered by both `event.source === frame.iframe.contentWindow` AND `event.origin === frame.origin` — the cross-origin domain `SafeContentFrame` issues per render. Messages from any other origin or window are dropped silently.
|
|
183
|
+
|
|
184
|
+
### Widget → host requests
|
|
185
|
+
|
|
186
|
+
| Method | Notes |
|
|
187
|
+
|---|---|
|
|
188
|
+
| `ui/initialize` | Returns `{ protocolVersion, host, hostContext, capabilities }`. Always supported. |
|
|
189
|
+
| `tools/call` | Routed to `host.url` with method `tools/call`. Optional `handlers.allowedTools` allowlist. Invalid `arguments` shape → `-32602`. |
|
|
190
|
+
| `resources/read` | Routed to `host.url` with method `resources/read`. |
|
|
191
|
+
| `resources/list` | Routed to `host.url` with method `resources/list`. |
|
|
192
|
+
| `openLink` | Requires `handlers.openLink`. Rejects non-`http(s)` URLs with `-32602`. |
|
|
193
|
+
| `sendMessage` | Requires `handlers.sendMessage`. |
|
|
194
|
+
| `requestDisplayMode` | Requires `handlers.requestDisplayMode`. Modes: `inline`, `fullscreen`, `pip`. |
|
|
195
|
+
| `updateModelContext` | Requires `handlers.updateModelContext`. |
|
|
196
|
+
|
|
197
|
+
When a handler isn't provided, the bridge returns JSON-RPC `-32601` (method not found) — which is also how `capabilities` is reported in the `ui/initialize` response.
|
|
198
|
+
|
|
199
|
+
### Host → widget notifications
|
|
200
|
+
|
|
201
|
+
- `notifications/tools/call/input` — sent whenever `part.args` (the streaming tool input) changes
|
|
202
|
+
- `notifications/tools/call/result` — sent when the tool result lands (including error envelopes)
|
|
203
|
+
- `notifications/host_context/changed` — sent when `hostContext` changes (e.g. user toggles theme)
|
|
204
|
+
|
|
205
|
+
### Widget → host notifications
|
|
206
|
+
|
|
207
|
+
`notifications/initialized`, `notifications/size_changed`, `notifications/log`, `notifications/error`, `notifications/request_teardown` — wire them via `handlers.onInitialized`, `onSizeChange`, `onLog`, `onError`, `onRequestTeardown` respectively.
|
|
208
|
+
|
|
209
|
+
If the widget never sends `notifications/initialized` (broken or non-spec-compliant), the host flushes its queued notifications after a 5-second safety timeout so the iframe doesn't appear hung.
|
|
210
|
+
|
|
211
|
+
## Sandboxing
|
|
212
|
+
|
|
213
|
+
The iframe is built with [`SafeContentFrame`](/safe-content-frame), which serves each widget from a content-hashed cross-origin so the host page is not reachable by `same-origin` references. Default sandbox flags are `allow-same-origin allow-scripts`. Tune via the `sandbox` field on `McpAppRendererOptions`:
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
McpAppRenderer({
|
|
217
|
+
// ...
|
|
218
|
+
sandbox: {
|
|
219
|
+
sandbox: ["allow-forms", "allow-popups"],
|
|
220
|
+
enableBrowserCaching: true,
|
|
221
|
+
className: "my-mcp-app",
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Security notes
|
|
227
|
+
|
|
228
|
+
- Widgets run cross-origin in a sandboxed iframe. The bridge filters incoming messages by both source window and origin.
|
|
229
|
+
- The host route is your auth boundary — apply session checks, rate limiting, and per-tool allowlists there. The renderer trusts whatever the route returns.
|
|
230
|
+
- `openLink` rejects non-`http(s)` URLs at the bridge layer, but your `openLink` handler should still treat the URL as untrusted (e.g. always use `noopener,noreferrer`).
|
|
231
|
+
- Keep `host` and `handlers` references stable across renders (e.g. module-scope constants or `useMemo`); an unstable identity will tear down and refetch the widget on every parent re-render.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Mentions
|
|
3
|
-
description: Let users @-mention tools or custom items in the composer to guide the LLM.
|
|
2
|
+
title: Mentions in Chat
|
|
3
|
+
description: Let users @-mention tools or custom items in the AI chat composer to guide the LLM. Mention picker built into assistant-ui's React composer.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Message Timing
|
|
3
|
-
description: Display stream
|
|
2
|
+
title: Message Timing & Token Stats
|
|
3
|
+
description: Display stream metadata in AI chat — generation duration, tokens per second, and time to first token, rendered via assistant-ui's React components.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -76,9 +76,9 @@ const AssistantMessage: FC = () => {
|
|
|
76
76
|
| AI SDK (`useChatRuntime`) | Yes | Automatic via client-side tracking |
|
|
77
77
|
| Local (`useLocalRuntime`) | Yes | Pass timing in `ChatModelRunResult.metadata` |
|
|
78
78
|
| ExternalStore | Yes | Pass timing in `ThreadMessageLike.metadata` |
|
|
79
|
-
| LangGraph |
|
|
80
|
-
| AG-UI |
|
|
81
|
-
| OpenCode |
|
|
79
|
+
| LangGraph | Yes | Automatic via client-side tracking |
|
|
80
|
+
| AG-UI | Yes | Automatic via client-side tracking |
|
|
81
|
+
| OpenCode | Yes | Automatic via client-side tracking |
|
|
82
82
|
|
|
83
83
|
### Data Stream
|
|
84
84
|
|
|
@@ -163,6 +163,39 @@ const message: ThreadMessageLike = {
|
|
|
163
163
|
};
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
+
### LangGraph (`useLangGraphRuntime`)
|
|
167
|
+
|
|
168
|
+
Timing is tracked automatically on the client side by observing streaming state transitions and `LangChainMessage` content changes. No setup required.
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { useLangGraphRuntime } from "@assistant-ui/react-langgraph";
|
|
172
|
+
|
|
173
|
+
const runtime = useLangGraphRuntime({ stream: myStream });
|
|
174
|
+
// useMessageTiming() works out of the box
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### AG-UI (`useAgUiThreadRuntime`)
|
|
178
|
+
|
|
179
|
+
Timing is tracked automatically on the client side by the AG-UI run aggregator. Each emitted message includes timing metadata computed from stream chunk observations.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
import { useAgUiThreadRuntime } from "@assistant-ui/react-ag-ui";
|
|
183
|
+
|
|
184
|
+
const runtime = useAgUiThreadRuntime({ runtimeUrl: "..." });
|
|
185
|
+
// useMessageTiming() works out of the box
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### OpenCode (`useOpenCodeRuntime`)
|
|
189
|
+
|
|
190
|
+
Timing is tracked automatically on the client side by observing `OpenCodeThreadState` transitions and assistant message content deltas. No setup required.
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { useOpenCodeRuntime } from "@assistant-ui/react-opencode";
|
|
194
|
+
|
|
195
|
+
const runtime = useOpenCodeRuntime();
|
|
196
|
+
// useMessageTiming() works out of the box
|
|
197
|
+
```
|
|
198
|
+
|
|
166
199
|
## API Reference
|
|
167
200
|
|
|
168
201
|
### `useMessageTiming()`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Multi-Agent
|
|
3
|
-
description: Render sub-agent conversations inside tool
|
|
2
|
+
title: Multi-Agent Chat UI
|
|
3
|
+
description: Render sub-agent conversations and handoffs inside tool calls. Build supervisor and multi-agent patterns in a React chat UI with assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Quote Selected Text
|
|
3
|
-
description: Let users select and quote
|
|
3
|
+
description: Let users select text from AI messages and quote it back into the composer. Full quoting flow with backend handling and programmatic API in assistant-ui.
|
|
4
4
|
platforms: ["react"]
|
|
5
5
|
---
|
|
6
6
|
|