@assistant-ui/mcp-docs-server 0.1.38 → 0.2.0
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 +11 -12
- package/.docs/organized/code-examples/with-a2a.md +18 -13
- package/.docs/organized/code-examples/with-ag-ui.md +19 -14
- package/.docs/organized/code-examples/{with-ai-sdk-v6.md → with-ai-sdk-v7.md} +34 -23
- package/.docs/organized/code-examples/with-artifacts.md +473 -141
- package/.docs/organized/code-examples/with-assistant-transport.md +17 -10
- package/.docs/organized/code-examples/with-browser-extension.md +17 -10
- package/.docs/organized/code-examples/with-chain-of-thought.md +21 -14
- package/.docs/organized/code-examples/with-cloud-standalone.md +12 -11
- package/.docs/organized/code-examples/with-cloud.md +20 -15
- package/.docs/organized/code-examples/with-custom-thread-list.md +19 -12
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +22 -15
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +22 -15
- package/.docs/organized/code-examples/with-eve.md +18 -11
- package/.docs/organized/code-examples/with-expo.md +35 -52
- package/.docs/organized/code-examples/with-external-store.md +18 -13
- package/.docs/organized/code-examples/with-ffmpeg.md +20 -15
- package/.docs/organized/code-examples/with-generative-ui.md +22 -17
- package/.docs/organized/code-examples/with-google-adk.md +18 -11
- package/.docs/organized/code-examples/with-heat-graph.md +10 -11
- package/.docs/organized/code-examples/with-image-generation.md +19 -12
- package/.docs/organized/code-examples/with-interactables.md +21 -17
- package/.docs/organized/code-examples/with-langchain.md +19 -12
- package/.docs/organized/code-examples/with-langgraph.md +19 -12
- package/.docs/organized/code-examples/with-livekit.md +23 -16
- package/.docs/organized/code-examples/with-mcp.md +46 -28
- package/.docs/organized/code-examples/with-opencode.md +25 -23
- package/.docs/organized/code-examples/with-pi.md +54 -19
- package/.docs/organized/code-examples/with-react-hook-form.md +21 -16
- package/.docs/organized/code-examples/with-react-ink-web.md +9 -9
- package/.docs/organized/code-examples/with-react-ink.md +4 -4
- package/.docs/organized/code-examples/with-react-router.md +22 -17
- package/.docs/organized/code-examples/with-resumable-stream.md +21 -14
- package/.docs/organized/code-examples/with-store.md +10 -11
- package/.docs/organized/code-examples/with-tanstack.md +19 -13
- package/.docs/organized/code-examples/with-tap-runtime.md +18 -13
- package/.docs/organized/code-examples/with-virtualized-thread.md +19 -14
- package/.docs/raw/docs/(docs)/base-ui.mdx +39 -0
- package/.docs/raw/docs/(docs)/cli.mdx +19 -1
- package/.docs/raw/docs/(docs)/devtools.mdx +7 -2
- package/.docs/raw/docs/(docs)/installation.mdx +15 -1
- package/.docs/raw/docs/(docs)/rtl.mdx +2 -4
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/a2ui.mdx +40 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/actions.mdx +56 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/components.mdx +86 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +22 -1
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/json-generative-ui.mdx +42 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +53 -2
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +81 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +86 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/tokens.mdx +62 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +19 -420
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +4 -1
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-ai-sdk.mdx +25 -2
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +37 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +1 -9
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +14 -31
- package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +1 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +3 -0
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +2 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +0 -2
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +12 -9
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +4 -0
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +7 -1
- package/.docs/raw/docs/cloud/langgraph.mdx +4 -2
- package/.docs/raw/docs/copilots/model-context.mdx +1 -1
- package/.docs/raw/docs/copilots/motivation.mdx +1 -1
- package/.docs/raw/docs/guides/attachments.mdx +3 -3
- package/.docs/raw/docs/guides/branching.mdx +2 -2
- package/.docs/raw/docs/guides/chatgpt-subscription.mdx +108 -0
- package/.docs/raw/docs/guides/context-api.mdx +89 -111
- package/.docs/raw/docs/guides/dictation.mdx +185 -257
- package/.docs/raw/docs/guides/editing.mdx +5 -5
- package/.docs/raw/docs/guides/electron.mdx +369 -0
- package/.docs/raw/docs/guides/index.mdx +20 -0
- package/.docs/raw/docs/guides/mentions.mdx +31 -3
- package/.docs/raw/docs/guides/quoting.mdx +3 -3
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +2 -2
- package/.docs/raw/docs/guides/resumable-streams.mdx +12 -1
- package/.docs/raw/docs/guides/speech.mdx +47 -29
- package/.docs/raw/docs/guides/suggestions.mdx +70 -1
- package/.docs/raw/docs/guides/voice.mdx +197 -267
- package/.docs/raw/docs/ink/hooks.mdx +3 -3
- package/.docs/raw/docs/ink/primitives.mdx +49 -8
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/clerk.mdx +2 -2
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +3 -3
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +10 -4
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents/overview.mdx +3 -3
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +1 -1
- package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +3 -3
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +1 -1
- package/.docs/raw/docs/integrations/gateways/index.mdx +2 -2
- package/.docs/raw/docs/integrations/observability/helicone.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +1 -1
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +2 -2
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +36 -9
- package/.docs/raw/docs/migrations/index.mdx +50 -0
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +4 -2
- package/.docs/raw/docs/migrations/v0-15.mdx +156 -0
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +6 -1
- package/.docs/raw/docs/primitives/composer.mdx +17 -1
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +25 -0
- package/.docs/raw/docs/primitives/thread-list.mdx +2 -2
- package/.docs/raw/docs/react-native/hooks.mdx +3 -3
- package/.docs/raw/docs/react-native/index.mdx +2 -2
- package/.docs/raw/docs/react-native/primitives.mdx +62 -5
- package/.docs/raw/docs/runtimes/ag-ui/agent-state.mdx +124 -0
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +10 -1
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +14 -5
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +15 -15
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +8 -8
- package/.docs/raw/docs/runtimes/ai-sdk/{v6.mdx → v6-legacy.mdx} +11 -9
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +717 -0
- package/.docs/raw/docs/runtimes/concepts/adapters.mdx +1 -1
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +1 -1
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +10 -10
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +10 -19
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +2 -2
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +5 -3
- package/.docs/raw/docs/runtimes/eve/overview.mdx +1 -1
- package/.docs/raw/docs/runtimes/langchain.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/agent-state.mdx +181 -0
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +1 -1
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +3 -1
- package/.docs/raw/docs/tools/a2ui.mdx +107 -0
- package/.docs/raw/docs/tools/backend.mdx +6 -3
- package/.docs/raw/docs/tools/defining-tools.mdx +7 -1
- package/.docs/raw/docs/tools/generative-ui.mdx +60 -2
- package/.docs/raw/docs/tools/interactables-legacy.mdx +4 -4
- package/.docs/raw/docs/tools/interactables.mdx +3 -3
- package/.docs/raw/docs/tools/mcp-apps.mdx +90 -13
- package/.docs/raw/docs/tools/mcp.mdx +100 -3
- package/.docs/raw/docs/tools/tool-ui.mdx +6 -4
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +77 -9
- package/.docs/raw/docs/ui/accordion.mdx +16 -10
- package/.docs/raw/docs/ui/assistant-modal.mdx +8 -4
- package/.docs/raw/docs/ui/attachment.mdx +5 -1
- package/.docs/raw/docs/ui/badge.mdx +23 -12
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +4 -2
- package/.docs/raw/docs/ui/model-selector.mdx +33 -3
- package/.docs/raw/docs/ui/part-grouping.mdx +0 -4
- package/.docs/raw/docs/ui/reasoning.mdx +1 -1
- package/.docs/raw/docs/ui/select.mdx +22 -14
- package/.docs/raw/docs/ui/sources.mdx +1 -1
- package/.docs/raw/docs/ui/tabs.mdx +25 -14
- package/.docs/raw/docs/utilities/heat-graph.mdx +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -2
- package/dist/index.js.map +1 -1
- package/dist/prepare-docs/code-examples.d.ts.map +1 -1
- package/dist/prepare-docs/code-examples.js.map +1 -1
- package/dist/prepare-docs/copy-raw.d.ts.map +1 -1
- package/dist/prepare-docs/prepare.d.ts +1 -1
- package/dist/prompts/xulux-playground.d.ts +12 -0
- package/dist/prompts/xulux-playground.d.ts.map +1 -0
- package/dist/prompts/xulux-playground.js +33 -0
- package/dist/prompts/xulux-playground.js.map +1 -0
- package/dist/stdio.d.ts +1 -1
- package/dist/tools/docs.d.ts +8 -14
- package/dist/tools/docs.d.ts.map +1 -1
- package/dist/tools/docs.js +26 -10
- package/dist/tools/docs.js.map +1 -1
- package/dist/tools/examples.d.ts +6 -12
- package/dist/tools/examples.d.ts.map +1 -1
- package/dist/tools/examples.js +11 -8
- package/dist/tools/examples.js.map +1 -1
- package/dist/tools/resources.d.ts +1 -2
- package/dist/tools/resources.d.ts.map +1 -1
- package/dist/tools/resources.js +1 -1
- package/dist/tools/resources.js.map +1 -1
- package/dist/tools/search.d.ts +6 -15
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +2 -2
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/tests/mcp-test-client.d.ts +15 -0
- package/dist/tools/tests/mcp-test-client.d.ts.map +1 -0
- package/dist/tools/tests/mcp-test-client.js +68 -0
- package/dist/tools/tests/mcp-test-client.js.map +1 -0
- package/dist/tools/tests/test-setup.d.ts.map +1 -1
- package/dist/tools/tests/test-setup.js +5 -1
- package/dist/tools/tests/test-setup.js.map +1 -1
- package/dist/tools/xulux-templates.d.ts +58 -0
- package/dist/tools/xulux-templates.d.ts.map +1 -0
- package/dist/tools/xulux-templates.js +82 -0
- package/dist/tools/xulux-templates.js.map +1 -0
- package/dist/utils/cache.d.ts +5 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +18 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/mcp-format.d.ts +1 -0
- package/dist/utils/mcp-format.d.ts.map +1 -1
- package/dist/utils/mcp-format.js +7 -4
- package/dist/utils/mcp-format.js.map +1 -1
- package/dist/utils/mdx.d.ts.map +1 -1
- package/dist/utils/paths.d.ts +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +3 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/search.d.ts.map +1 -1
- package/dist/utils/security.d.ts.map +1 -1
- package/dist/utils/security.js.map +1 -1
- package/dist/xulux/catalog-client.d.ts +14 -0
- package/dist/xulux/catalog-client.d.ts.map +1 -0
- package/dist/xulux/catalog-client.js +67 -0
- package/dist/xulux/catalog-client.js.map +1 -0
- package/dist/xulux/fallback-catalog.d.ts +7 -0
- package/dist/xulux/fallback-catalog.d.ts.map +1 -0
- package/dist/xulux/fallback-catalog.js +47 -0
- package/dist/xulux/fallback-catalog.js.map +1 -0
- package/dist/xulux/fetch-sandbox.d.ts +5 -0
- package/dist/xulux/fetch-sandbox.d.ts.map +1 -0
- package/dist/xulux/fetch-sandbox.js +40 -0
- package/dist/xulux/fetch-sandbox.js.map +1 -0
- package/dist/xulux/template-service.d.ts +84 -0
- package/dist/xulux/template-service.d.ts.map +1 -0
- package/dist/xulux/template-service.js +223 -0
- package/dist/xulux/template-service.js.map +1 -0
- package/dist/xulux/types.d.ts +55 -0
- package/dist/xulux/types.d.ts.map +1 -0
- package/dist/xulux/types.js +6 -0
- package/dist/xulux/types.js.map +1 -0
- package/package.json +7 -6
- package/src/index.ts +55 -2
- package/src/prompts/xulux-playground.ts +36 -0
- package/src/tools/docs.ts +27 -5
- package/src/tools/examples.ts +17 -12
- package/src/tools/resources.ts +1 -4
- package/src/tools/search.ts +2 -2
- package/src/tools/tests/completions.test.ts +40 -26
- package/src/tools/tests/docs.test.ts +20 -0
- package/src/tools/tests/examples.test.ts +5 -5
- package/src/tools/tests/integration.test.ts +3 -4
- package/src/tools/tests/listings-cache.test.ts +19 -0
- package/src/tools/tests/mcp-protocol.test.ts +173 -108
- package/src/tools/tests/mcp-test-client.ts +111 -0
- package/src/tools/tests/resources.test.ts +97 -66
- package/src/tools/tests/test-setup.ts +8 -0
- package/src/tools/tests/xulux-templates.test.ts +262 -0
- package/src/tools/xulux-templates.ts +141 -0
- package/src/utils/cache.ts +20 -0
- package/src/utils/mcp-format.ts +8 -6
- package/src/utils/paths.ts +4 -1
- package/src/utils/tests/cache.test.ts +51 -0
- package/src/utils/tests/mcp-format.test.ts +22 -0
- package/src/utils/tests/security.test.ts +1 -1
- package/src/xulux/catalog-client.ts +105 -0
- package/src/xulux/fallback-catalog.ts +63 -0
- package/src/xulux/fetch-sandbox.ts +56 -0
- package/src/xulux/template-service.ts +406 -0
- package/src/xulux/types.ts +60 -0
- package/.docs/raw/docs/(reference)/api-reference/hooks/utilities.mdx +0 -464
|
@@ -4,45 +4,43 @@
|
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { openai } from "@ai-sdk/openai";
|
|
7
|
-
import {
|
|
8
|
-
streamText,
|
|
9
|
-
convertToModelMessages,
|
|
10
|
-
tool,
|
|
11
|
-
stepCountIs,
|
|
12
|
-
zodSchema,
|
|
13
|
-
} from "ai";
|
|
7
|
+
import { convertToModelMessages, stepCountIs, streamText } from "ai";
|
|
14
8
|
import type { UIMessage } from "ai";
|
|
15
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
AISDKToolkit,
|
|
11
|
+
unstable_injectInteractableContext,
|
|
12
|
+
type AISDKToolkitToolsOptions,
|
|
13
|
+
} from "@assistant-ui/react-ai-sdk";
|
|
14
|
+
import toolkit from "../../toolkit";
|
|
16
15
|
|
|
17
16
|
export const maxDuration = 30;
|
|
18
17
|
|
|
18
|
+
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
19
|
+
|
|
20
|
+
type FrontendToolDefs = NonNullable<AISDKToolkitToolsOptions["frontend"]>;
|
|
21
|
+
|
|
19
22
|
export async function POST(req: Request) {
|
|
20
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
messages,
|
|
25
|
+
tools: clientTools,
|
|
26
|
+
}: {
|
|
27
|
+
messages: UIMessage[];
|
|
28
|
+
tools?: FrontendToolDefs;
|
|
29
|
+
} = await req.json();
|
|
30
|
+
|
|
31
|
+
const tools = await aiToolkit.tools({
|
|
32
|
+
...(clientTools && { frontend: clientTools }),
|
|
33
|
+
});
|
|
21
34
|
|
|
22
35
|
const result = streamText({
|
|
23
36
|
model: openai("gpt-5.4-nano"),
|
|
24
37
|
system:
|
|
25
|
-
"You
|
|
26
|
-
messages: await convertToModelMessages(
|
|
38
|
+
"You create functional HTML artifacts. When the user requests a webpage, interface, visualization, or other visual content, call the artifact tool with a short title and a complete HTML document. When an artifact already exists and the user requests a change, call update_artifact with its id and only the fields that changed. Do not put artifact HTML in a code block.",
|
|
39
|
+
messages: await convertToModelMessages(
|
|
40
|
+
unstable_injectInteractableContext(messages),
|
|
41
|
+
),
|
|
27
42
|
stopWhen: stepCountIs(10),
|
|
28
|
-
tools
|
|
29
|
-
render_html: tool({
|
|
30
|
-
description:
|
|
31
|
-
"Render HTML code in the user's browser. Use this whenever the user asks for HTML, a webpage, a UI component, or any visual content.",
|
|
32
|
-
inputSchema: zodSchema(
|
|
33
|
-
z.object({
|
|
34
|
-
code: z
|
|
35
|
-
.string()
|
|
36
|
-
.describe(
|
|
37
|
-
"The complete HTML code to render, including inline CSS and JavaScript if needed.",
|
|
38
|
-
),
|
|
39
|
-
}),
|
|
40
|
-
),
|
|
41
|
-
execute: async () => {
|
|
42
|
-
return { success: true };
|
|
43
|
-
},
|
|
44
|
-
}),
|
|
45
|
-
},
|
|
43
|
+
tools,
|
|
46
44
|
});
|
|
47
45
|
|
|
48
46
|
return result.toUIMessageStreamResponse();
|
|
@@ -50,6 +48,391 @@ export async function POST(req: Request) {
|
|
|
50
48
|
|
|
51
49
|
```
|
|
52
50
|
|
|
51
|
+
## app/artifact-state.ts
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { z } from "zod";
|
|
55
|
+
|
|
56
|
+
export const artifactSchema = z.object({
|
|
57
|
+
title: z.string().describe("A short title for the artifact."),
|
|
58
|
+
code: z
|
|
59
|
+
.string()
|
|
60
|
+
.describe(
|
|
61
|
+
"A complete HTML document with inline CSS and JavaScript when needed.",
|
|
62
|
+
),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export type ArtifactState = z.infer<typeof artifactSchema>;
|
|
66
|
+
|
|
67
|
+
export const emptyArtifact: ArtifactState = {
|
|
68
|
+
title: "Untitled artifact",
|
|
69
|
+
code: "",
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const artifactDescription =
|
|
73
|
+
"Create an interactive HTML artifact when the user asks for a webpage, interface, visualization, or other visual content. Provide a short title and a complete HTML document.";
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## app/artifact-surface.tsx
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
"use client";
|
|
81
|
+
|
|
82
|
+
import {
|
|
83
|
+
createContext,
|
|
84
|
+
useContext,
|
|
85
|
+
useEffect,
|
|
86
|
+
useMemo,
|
|
87
|
+
useRef,
|
|
88
|
+
useState,
|
|
89
|
+
type ReactNode,
|
|
90
|
+
} from "react";
|
|
91
|
+
import {
|
|
92
|
+
unstable_useInteractable,
|
|
93
|
+
unstable_useInteractableVersions,
|
|
94
|
+
useAuiState,
|
|
95
|
+
type Unstable_InteractableToolRenderProps,
|
|
96
|
+
} from "@assistant-ui/react";
|
|
97
|
+
import {
|
|
98
|
+
ArrowLeftIcon,
|
|
99
|
+
CheckIcon,
|
|
100
|
+
Code2Icon,
|
|
101
|
+
EyeIcon,
|
|
102
|
+
FileCode2Icon,
|
|
103
|
+
HistoryIcon,
|
|
104
|
+
Loader2Icon,
|
|
105
|
+
PanelRightOpenIcon,
|
|
106
|
+
SparklesIcon,
|
|
107
|
+
XIcon,
|
|
108
|
+
} from "lucide-react";
|
|
109
|
+
import {
|
|
110
|
+
artifactDescription,
|
|
111
|
+
artifactSchema,
|
|
112
|
+
emptyArtifact,
|
|
113
|
+
type ArtifactState,
|
|
114
|
+
} from "./artifact-state";
|
|
115
|
+
|
|
116
|
+
type ArtifactSurfaceTarget = {
|
|
117
|
+
id: string;
|
|
118
|
+
name: "artifact";
|
|
119
|
+
messageId: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type ArtifactSurfaceContextValue = {
|
|
123
|
+
active: ArtifactSurfaceTarget | null;
|
|
124
|
+
open: (target: ArtifactSurfaceTarget) => void;
|
|
125
|
+
close: () => void;
|
|
126
|
+
returnToOrigin: () => void;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const ArtifactSurfaceContext =
|
|
130
|
+
createContext<ArtifactSurfaceContextValue | null>(null);
|
|
131
|
+
|
|
132
|
+
export function ArtifactSurfaceProvider({ children }: { children: ReactNode }) {
|
|
133
|
+
const [active, setActive] = useState<ArtifactSurfaceTarget | null>(null);
|
|
134
|
+
|
|
135
|
+
const value = useMemo<ArtifactSurfaceContextValue>(
|
|
136
|
+
() => ({
|
|
137
|
+
active,
|
|
138
|
+
open: setActive,
|
|
139
|
+
close: () => setActive(null),
|
|
140
|
+
returnToOrigin: () => {
|
|
141
|
+
const messageId = active?.messageId;
|
|
142
|
+
setActive(null);
|
|
143
|
+
if (!messageId) return;
|
|
144
|
+
requestAnimationFrame(() => {
|
|
145
|
+
const message = Array.from(
|
|
146
|
+
document.querySelectorAll<HTMLElement>("[data-message-id]"),
|
|
147
|
+
).find((element) => element.dataset.messageId === messageId);
|
|
148
|
+
message?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
[active],
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<ArtifactSurfaceContext.Provider value={value}>
|
|
157
|
+
{children}
|
|
158
|
+
</ArtifactSurfaceContext.Provider>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function useArtifactSurface() {
|
|
163
|
+
const value = useContext(ArtifactSurfaceContext);
|
|
164
|
+
if (!value) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
"useArtifactSurface must be used within ArtifactSurfaceProvider",
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function ArtifactTrigger({
|
|
173
|
+
state,
|
|
174
|
+
version,
|
|
175
|
+
id,
|
|
176
|
+
streaming,
|
|
177
|
+
}: Unstable_InteractableToolRenderProps<ArtifactState>) {
|
|
178
|
+
const messageId = useAuiState((s) => s.message.id);
|
|
179
|
+
const { active, open } = useArtifactSurface();
|
|
180
|
+
const displayState = version && !version.isLatest ? version.state : state;
|
|
181
|
+
const title = displayState.title || "Untitled artifact";
|
|
182
|
+
const lineCount = displayState.code
|
|
183
|
+
? displayState.code.split(/\r?\n/).length
|
|
184
|
+
: 0;
|
|
185
|
+
const isOpen = active?.id === id;
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<div className="bg-card my-3 overflow-hidden rounded-xl border shadow-[0_10px_30px_-22px_rgba(24,24,27,0.5)]">
|
|
189
|
+
<div className="bg-muted text-muted-foreground flex items-center gap-2 border-b px-3 py-2 font-mono text-[10px] tracking-[0.16em] uppercase">
|
|
190
|
+
<FileCode2Icon className="size-3.5" />
|
|
191
|
+
HTML artifact
|
|
192
|
+
{streaming ? (
|
|
193
|
+
<span className="ml-auto inline-flex items-center gap-1.5 text-amber-700">
|
|
194
|
+
<Loader2Icon className="size-3 animate-spin" />
|
|
195
|
+
Writing
|
|
196
|
+
</span>
|
|
197
|
+
) : (
|
|
198
|
+
<span className="ml-auto inline-flex items-center gap-1.5 text-emerald-700">
|
|
199
|
+
<CheckIcon className="size-3" />
|
|
200
|
+
Ready
|
|
201
|
+
</span>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
<div className="flex items-center gap-4 p-3">
|
|
205
|
+
<div className="min-w-0 flex-1">
|
|
206
|
+
<p className="truncate text-sm font-semibold">{title}</p>
|
|
207
|
+
<p className="text-muted-foreground mt-0.5 text-xs">
|
|
208
|
+
{lineCount > 0 ? `${lineCount} lines` : "Preparing document"}
|
|
209
|
+
{version && !version.isLatest ? " · historical version" : ""}
|
|
210
|
+
</p>
|
|
211
|
+
</div>
|
|
212
|
+
<button
|
|
213
|
+
type="button"
|
|
214
|
+
data-testid="artifact-trigger"
|
|
215
|
+
disabled={streaming}
|
|
216
|
+
onClick={() =>
|
|
217
|
+
open({
|
|
218
|
+
id,
|
|
219
|
+
name: "artifact",
|
|
220
|
+
messageId,
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
className="bg-primary text-primary-foreground hover:bg-primary/90 inline-flex h-9 shrink-0 items-center gap-2 rounded-lg px-3 text-xs font-medium transition-colors disabled:cursor-wait disabled:opacity-50"
|
|
224
|
+
>
|
|
225
|
+
<PanelRightOpenIcon className="size-3.5" />
|
|
226
|
+
{isOpen ? "In workbench" : "Open workbench"}
|
|
227
|
+
</button>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function ArtifactSurface() {
|
|
234
|
+
const { active } = useArtifactSurface();
|
|
235
|
+
if (!active) return null;
|
|
236
|
+
return <ArtifactWorkbench key={active.id} target={active} />;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function ArtifactWorkbench({ target }: { target: ArtifactSurfaceTarget }) {
|
|
240
|
+
const [state, { setState }] = unstable_useInteractable("artifact", {
|
|
241
|
+
id: target.id,
|
|
242
|
+
description: artifactDescription,
|
|
243
|
+
stateSchema: artifactSchema,
|
|
244
|
+
initialState: emptyArtifact,
|
|
245
|
+
});
|
|
246
|
+
const versions = unstable_useInteractableVersions<ArtifactState>(
|
|
247
|
+
target.id,
|
|
248
|
+
target.name,
|
|
249
|
+
);
|
|
250
|
+
const { close, returnToOrigin } = useArtifactSurface();
|
|
251
|
+
const [view, setView] = useState<"preview" | "code">("preview");
|
|
252
|
+
const [historyOpen, setHistoryOpen] = useState(false);
|
|
253
|
+
const historyRef = useRef<HTMLDivElement>(null);
|
|
254
|
+
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!historyOpen) return;
|
|
257
|
+
const dismissPointer = (event: PointerEvent) => {
|
|
258
|
+
if (!historyRef.current?.contains(event.target as Node)) {
|
|
259
|
+
setHistoryOpen(false);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
const dismissKey = (event: KeyboardEvent) => {
|
|
263
|
+
if (event.key === "Escape") setHistoryOpen(false);
|
|
264
|
+
};
|
|
265
|
+
const dismissBlur = () => setHistoryOpen(false);
|
|
266
|
+
document.addEventListener("pointerdown", dismissPointer);
|
|
267
|
+
document.addEventListener("keydown", dismissKey);
|
|
268
|
+
window.addEventListener("blur", dismissBlur);
|
|
269
|
+
return () => {
|
|
270
|
+
document.removeEventListener("pointerdown", dismissPointer);
|
|
271
|
+
document.removeEventListener("keydown", dismissKey);
|
|
272
|
+
window.removeEventListener("blur", dismissBlur);
|
|
273
|
+
};
|
|
274
|
+
}, [historyOpen]);
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<aside
|
|
278
|
+
data-testid="artifact-surface"
|
|
279
|
+
className="bg-muted fixed inset-0 z-30 flex min-w-0 flex-1 flex-col md:static md:z-0 md:border-l"
|
|
280
|
+
>
|
|
281
|
+
<header className="border-border bg-background/90 flex h-14 shrink-0 items-center gap-3 border-b px-3 backdrop-blur md:px-5">
|
|
282
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
283
|
+
<span className="grid size-7 shrink-0 place-items-center rounded-lg bg-amber-300 text-zinc-950 shadow-[inset_0_0_0_1px_rgba(24,24,27,0.12)]">
|
|
284
|
+
<SparklesIcon className="size-3.5" />
|
|
285
|
+
</span>
|
|
286
|
+
<div className="min-w-0">
|
|
287
|
+
<p className="truncate text-sm font-semibold">
|
|
288
|
+
{state.title || "Untitled artifact"}
|
|
289
|
+
</p>
|
|
290
|
+
<p className="text-muted-foreground font-mono text-[9px] tracking-[0.14em] uppercase">
|
|
291
|
+
Opened from conversation
|
|
292
|
+
</p>
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<div className="ml-auto flex items-center gap-1.5">
|
|
297
|
+
<div className="relative" ref={historyRef}>
|
|
298
|
+
<button
|
|
299
|
+
type="button"
|
|
300
|
+
data-testid="artifact-version-select"
|
|
301
|
+
aria-label="Artifact version history"
|
|
302
|
+
aria-expanded={historyOpen}
|
|
303
|
+
onClick={() => setHistoryOpen((open) => !open)}
|
|
304
|
+
className="border-border bg-card text-foreground hover:bg-muted inline-flex h-8 items-center gap-1.5 rounded-md border px-2.5 text-xs font-medium"
|
|
305
|
+
>
|
|
306
|
+
<HistoryIcon className="size-3.5" />
|
|
307
|
+
{versions.length} {versions.length === 1 ? "version" : "versions"}
|
|
308
|
+
</button>
|
|
309
|
+
{historyOpen && (
|
|
310
|
+
<div className="border-border bg-card absolute top-9 right-0 z-10 flex w-44 flex-col overflow-hidden rounded-md border py-1 shadow-lg">
|
|
311
|
+
{versions.map((version, index) => (
|
|
312
|
+
<button
|
|
313
|
+
key={`${version.origin}-${index}`}
|
|
314
|
+
type="button"
|
|
315
|
+
onClick={() => {
|
|
316
|
+
version.restore();
|
|
317
|
+
setHistoryOpen(false);
|
|
318
|
+
}}
|
|
319
|
+
className="text-foreground hover:bg-muted flex items-center justify-between px-3 py-1.5 text-left text-xs"
|
|
320
|
+
>
|
|
321
|
+
<span>
|
|
322
|
+
v{index + 1} ·{" "}
|
|
323
|
+
{version.origin === "user-edit" ? "you" : "assistant"}
|
|
324
|
+
</span>
|
|
325
|
+
{index === versions.length - 1 && (
|
|
326
|
+
<span className="text-muted-foreground font-mono text-[9px] uppercase">
|
|
327
|
+
latest
|
|
328
|
+
</span>
|
|
329
|
+
)}
|
|
330
|
+
</button>
|
|
331
|
+
))}
|
|
332
|
+
</div>
|
|
333
|
+
)}
|
|
334
|
+
</div>
|
|
335
|
+
<button
|
|
336
|
+
type="button"
|
|
337
|
+
data-testid="artifact-return"
|
|
338
|
+
aria-label="Return to conversation"
|
|
339
|
+
onClick={returnToOrigin}
|
|
340
|
+
className="border-border bg-card text-foreground hover:bg-muted inline-flex h-8 items-center gap-1.5 rounded-md border px-2.5 text-xs font-medium"
|
|
341
|
+
>
|
|
342
|
+
<ArrowLeftIcon className="size-3.5" />
|
|
343
|
+
<span className="hidden sm:inline">Conversation</span>
|
|
344
|
+
</button>
|
|
345
|
+
<button
|
|
346
|
+
type="button"
|
|
347
|
+
data-testid="artifact-close"
|
|
348
|
+
onClick={close}
|
|
349
|
+
className="text-muted-foreground hover:bg-muted hover:text-foreground grid size-8 place-items-center rounded-md"
|
|
350
|
+
aria-label="Close artifact"
|
|
351
|
+
>
|
|
352
|
+
<XIcon className="size-4" />
|
|
353
|
+
</button>
|
|
354
|
+
</div>
|
|
355
|
+
</header>
|
|
356
|
+
|
|
357
|
+
<div className="flex min-h-0 flex-1 flex-col p-2 md:p-4">
|
|
358
|
+
<div className="border-border bg-card flex min-h-0 flex-1 flex-col overflow-hidden rounded-xl border shadow-[0_24px_70px_-44px_rgba(24,24,27,0.55)]">
|
|
359
|
+
<div className="bg-muted/80 flex shrink-0 items-center gap-1 border-b p-1.5">
|
|
360
|
+
<button
|
|
361
|
+
type="button"
|
|
362
|
+
aria-pressed={view === "preview"}
|
|
363
|
+
onClick={() => setView("preview")}
|
|
364
|
+
className={`inline-flex h-8 items-center gap-2 rounded-md px-3 text-xs font-medium transition-colors ${
|
|
365
|
+
view === "preview"
|
|
366
|
+
? "bg-card text-foreground ring-border shadow-sm ring-1"
|
|
367
|
+
: "text-muted-foreground hover:text-foreground"
|
|
368
|
+
}`}
|
|
369
|
+
>
|
|
370
|
+
<EyeIcon className="size-3.5" />
|
|
371
|
+
Preview
|
|
372
|
+
</button>
|
|
373
|
+
<button
|
|
374
|
+
type="button"
|
|
375
|
+
aria-pressed={view === "code"}
|
|
376
|
+
onClick={() => setView("code")}
|
|
377
|
+
className={`inline-flex h-8 items-center gap-2 rounded-md px-3 text-xs font-medium transition-colors ${
|
|
378
|
+
view === "code"
|
|
379
|
+
? "bg-card text-foreground ring-border shadow-sm ring-1"
|
|
380
|
+
: "text-muted-foreground hover:text-foreground"
|
|
381
|
+
}`}
|
|
382
|
+
>
|
|
383
|
+
<Code2Icon className="size-3.5" />
|
|
384
|
+
Source
|
|
385
|
+
</button>
|
|
386
|
+
<span className="text-muted-foreground ml-auto pr-2 font-mono text-[9px] tracking-[0.14em] uppercase">
|
|
387
|
+
Live document
|
|
388
|
+
</span>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
{view === "preview" ? (
|
|
392
|
+
<iframe
|
|
393
|
+
data-testid="artifact-preview"
|
|
394
|
+
title={`Preview of ${state.title || "artifact"}`}
|
|
395
|
+
srcDoc={state.code}
|
|
396
|
+
sandbox="allow-scripts allow-forms"
|
|
397
|
+
className="min-h-0 flex-1 bg-white"
|
|
398
|
+
/>
|
|
399
|
+
) : (
|
|
400
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
401
|
+
<input
|
|
402
|
+
aria-label="Artifact title"
|
|
403
|
+
value={state.title}
|
|
404
|
+
onChange={(event) =>
|
|
405
|
+
setState((previous) => ({
|
|
406
|
+
...previous,
|
|
407
|
+
title: event.target.value,
|
|
408
|
+
}))
|
|
409
|
+
}
|
|
410
|
+
className="placeholder:text-muted-foreground h-11 shrink-0 border-b px-4 text-sm font-semibold outline-none"
|
|
411
|
+
placeholder="Artifact title"
|
|
412
|
+
/>
|
|
413
|
+
<textarea
|
|
414
|
+
data-testid="artifact-code-editor"
|
|
415
|
+
aria-label="Artifact HTML source"
|
|
416
|
+
value={state.code}
|
|
417
|
+
onChange={(event) =>
|
|
418
|
+
setState((previous) => ({
|
|
419
|
+
...previous,
|
|
420
|
+
code: event.target.value,
|
|
421
|
+
}))
|
|
422
|
+
}
|
|
423
|
+
spellCheck={false}
|
|
424
|
+
className="min-h-0 flex-1 resize-none bg-zinc-950 p-4 font-mono text-[13px] leading-6 text-zinc-100 outline-none selection:bg-amber-300 selection:text-zinc-950"
|
|
425
|
+
/>
|
|
426
|
+
</div>
|
|
427
|
+
)}
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
</aside>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
|
|
53
436
|
## app/globals.css
|
|
54
437
|
|
|
55
438
|
```css
|
|
@@ -211,90 +594,44 @@ export default function RootLayout({
|
|
|
211
594
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
212
595
|
import {
|
|
213
596
|
AssistantRuntimeProvider,
|
|
214
|
-
Tools,
|
|
215
|
-
useAui,
|
|
216
|
-
useAuiState,
|
|
217
597
|
AuiProvider,
|
|
218
598
|
Suggestions,
|
|
599
|
+
Tools,
|
|
600
|
+
unstable_Interactables,
|
|
601
|
+
useAui,
|
|
219
602
|
} from "@assistant-ui/react";
|
|
220
603
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
221
|
-
import
|
|
222
|
-
import {
|
|
223
|
-
|
|
604
|
+
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
605
|
+
import {
|
|
606
|
+
ArtifactSurface,
|
|
607
|
+
ArtifactSurfaceProvider,
|
|
608
|
+
useArtifactSurface,
|
|
609
|
+
} from "./artifact-surface";
|
|
224
610
|
import toolkit from "./toolkit";
|
|
225
611
|
|
|
226
|
-
function
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
const lastToolCall = useAuiState((s) => {
|
|
230
|
-
const messages = s.thread.messages;
|
|
231
|
-
return messages
|
|
232
|
-
.flatMap((m) =>
|
|
233
|
-
m.content.filter(
|
|
234
|
-
(c): c is ToolCallMessagePart =>
|
|
235
|
-
c.type === "tool-call" && c.toolName === "render_html",
|
|
236
|
-
),
|
|
237
|
-
)
|
|
238
|
-
.at(-1);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const code = lastToolCall?.args.code as string | undefined;
|
|
242
|
-
const isComplete = lastToolCall?.result !== undefined;
|
|
243
|
-
|
|
244
|
-
if (!code) return null;
|
|
612
|
+
function ArtifactExperience() {
|
|
613
|
+
const { active } = useArtifactSurface();
|
|
245
614
|
|
|
246
615
|
return (
|
|
247
|
-
<
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
<CodeIcon className="size-4" />
|
|
260
|
-
Source Code
|
|
261
|
-
</button>
|
|
262
|
-
<button
|
|
263
|
-
type="button"
|
|
264
|
-
onClick={() => isComplete && setTab("preview")}
|
|
265
|
-
disabled={!isComplete}
|
|
266
|
-
className={`inline-flex flex-1 items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium transition-colors ${
|
|
267
|
-
!isComplete
|
|
268
|
-
? "cursor-not-allowed opacity-50"
|
|
269
|
-
: tab === "preview"
|
|
270
|
-
? "bg-background text-foreground"
|
|
271
|
-
: "text-muted-foreground hover:text-foreground"
|
|
272
|
-
}`}
|
|
273
|
-
>
|
|
274
|
-
<EyeIcon className="size-4" />
|
|
275
|
-
Preview
|
|
276
|
-
</button>
|
|
277
|
-
</div>
|
|
278
|
-
{tab === "source" || !isComplete ? (
|
|
279
|
-
<div className="h-full overflow-y-auto px-4 py-2 font-mono text-sm break-words whitespace-pre-line">
|
|
280
|
-
{code}
|
|
281
|
-
</div>
|
|
282
|
-
) : (
|
|
283
|
-
<div className="flex h-full flex-grow px-4 py-2">
|
|
284
|
-
<iframe
|
|
285
|
-
className="h-full w-full"
|
|
286
|
-
title="Artifact Preview"
|
|
287
|
-
srcDoc={code}
|
|
288
|
-
/>
|
|
289
|
-
</div>
|
|
290
|
-
)}
|
|
291
|
-
</div>
|
|
292
|
-
</div>
|
|
616
|
+
<main className="bg-background flex h-full min-h-0 overflow-hidden">
|
|
617
|
+
<section
|
|
618
|
+
className={
|
|
619
|
+
active
|
|
620
|
+
? "bg-background hidden min-w-0 md:block md:w-[min(44vw,42rem)] md:shrink-0"
|
|
621
|
+
: "bg-background min-w-0 flex-1"
|
|
622
|
+
}
|
|
623
|
+
>
|
|
624
|
+
<Thread />
|
|
625
|
+
</section>
|
|
626
|
+
<ArtifactSurface />
|
|
627
|
+
</main>
|
|
293
628
|
);
|
|
294
629
|
}
|
|
295
630
|
|
|
296
|
-
function
|
|
631
|
+
function ArtifactScopes() {
|
|
297
632
|
const aui = useAui({
|
|
633
|
+
tools: Tools({ toolkit }),
|
|
634
|
+
unstable_interactables: unstable_Interactables(),
|
|
298
635
|
suggestions: Suggestions([
|
|
299
636
|
{
|
|
300
637
|
title: "Build a landing page",
|
|
@@ -310,27 +647,24 @@ function ThreadWithSuggestions() {
|
|
|
310
647
|
},
|
|
311
648
|
]),
|
|
312
649
|
});
|
|
650
|
+
|
|
313
651
|
return (
|
|
314
652
|
<AuiProvider value={aui}>
|
|
315
|
-
<
|
|
653
|
+
<ArtifactSurfaceProvider>
|
|
654
|
+
<ArtifactExperience />
|
|
655
|
+
</ArtifactSurfaceProvider>
|
|
316
656
|
</AuiProvider>
|
|
317
657
|
);
|
|
318
658
|
}
|
|
319
659
|
|
|
320
660
|
export default function Home() {
|
|
321
|
-
const runtime = useChatRuntime(
|
|
322
|
-
|
|
323
|
-
tools: Tools({ toolkit }),
|
|
661
|
+
const runtime = useChatRuntime({
|
|
662
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
324
663
|
});
|
|
325
664
|
|
|
326
665
|
return (
|
|
327
|
-
<AssistantRuntimeProvider
|
|
328
|
-
<
|
|
329
|
-
<div className="flex-grow basis-full">
|
|
330
|
-
<ThreadWithSuggestions />
|
|
331
|
-
</div>
|
|
332
|
-
<ArtifactsView />
|
|
333
|
-
</main>
|
|
666
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
667
|
+
<ArtifactScopes />
|
|
334
668
|
</AssistantRuntimeProvider>
|
|
335
669
|
);
|
|
336
670
|
}
|
|
@@ -342,25 +676,16 @@ export default function Home() {
|
|
|
342
676
|
```tsx
|
|
343
677
|
"use generative";
|
|
344
678
|
|
|
345
|
-
import { defineToolkit,
|
|
346
|
-
import {
|
|
347
|
-
import {
|
|
679
|
+
import { defineToolkit, unstable_interactableTool } from "@assistant-ui/react";
|
|
680
|
+
import { ArtifactTrigger } from "./artifact-surface";
|
|
681
|
+
import { artifactDescription, artifactSchema } from "./artifact-state";
|
|
348
682
|
|
|
349
683
|
export default defineToolkit({
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
render: () => {
|
|
356
|
-
return (
|
|
357
|
-
<div className="bg-primary text-primary-foreground my-2 inline-flex items-center gap-2 rounded-full border px-4 py-2">
|
|
358
|
-
<TerminalIcon className="size-4" />
|
|
359
|
-
render_html({ code: "..." })
|
|
360
|
-
</div>
|
|
361
|
-
);
|
|
362
|
-
},
|
|
363
|
-
},
|
|
684
|
+
artifact: unstable_interactableTool({
|
|
685
|
+
description: artifactDescription,
|
|
686
|
+
stateSchema: artifactSchema,
|
|
687
|
+
render: (props) => <ArtifactTrigger {...props} />,
|
|
688
|
+
}),
|
|
364
689
|
});
|
|
365
690
|
|
|
366
691
|
```
|
|
@@ -426,32 +751,33 @@ export default withAui(nextConfig);
|
|
|
426
751
|
"start": "next start"
|
|
427
752
|
},
|
|
428
753
|
"dependencies": {
|
|
429
|
-
"@ai-sdk/openai": "^
|
|
754
|
+
"@ai-sdk/openai": "^4.0.20",
|
|
430
755
|
"@assistant-ui/react": "workspace:*",
|
|
431
756
|
"@assistant-ui/react-ai-sdk": "workspace:*",
|
|
432
757
|
"@assistant-ui/react-markdown": "workspace:*",
|
|
433
758
|
"@assistant-ui/ui": "workspace:*",
|
|
434
|
-
"ai": "^
|
|
759
|
+
"ai": "^7.0.37",
|
|
435
760
|
"class-variance-authority": "^0.7.1",
|
|
436
761
|
"clsx": "^2.1.1",
|
|
437
|
-
"lucide-react": "^1.
|
|
438
|
-
"next": "^16.2.
|
|
439
|
-
"react": "^19.2.
|
|
440
|
-
"react-dom": "^19.2.
|
|
762
|
+
"lucide-react": "^1.26.0",
|
|
763
|
+
"next": "^16.2.11",
|
|
764
|
+
"react": "^19.2.8",
|
|
765
|
+
"react-dom": "^19.2.8",
|
|
441
766
|
"tailwind-merge": "^3.6.0",
|
|
442
767
|
"zod": "^4.4.3"
|
|
443
768
|
},
|
|
444
769
|
"devDependencies": {
|
|
445
770
|
"@assistant-ui/next": "workspace:*",
|
|
446
771
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
447
|
-
"@tailwindcss/postcss": "^4.3.
|
|
448
|
-
"@types/node": "^26.
|
|
772
|
+
"@tailwindcss/postcss": "^4.3.3",
|
|
773
|
+
"@types/node": "^26.1.1",
|
|
449
774
|
"@types/react": "^19.2.17",
|
|
450
775
|
"@types/react-dom": "^19.2.3",
|
|
451
|
-
"postcss": "^8.5.
|
|
452
|
-
"tailwindcss": "^4.3.
|
|
776
|
+
"postcss": "^8.5.23",
|
|
777
|
+
"tailwindcss": "^4.3.3",
|
|
453
778
|
"tw-animate-css": "^1.4.0",
|
|
454
|
-
"typescript": "
|
|
779
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
780
|
+
"typescript-7": "npm:typescript@^7.0.2"
|
|
455
781
|
}
|
|
456
782
|
}
|
|
457
783
|
|
|
@@ -468,7 +794,13 @@ export default withAui(nextConfig);
|
|
|
468
794
|
"@/components/assistant-ui/*": [
|
|
469
795
|
"../../packages/ui/src/components/assistant-ui/*"
|
|
470
796
|
],
|
|
471
|
-
"@/components/ui/*": [
|
|
797
|
+
"@/components/ui/*": [
|
|
798
|
+
"../../packages/ui/src/components/ui/base/*",
|
|
799
|
+
"../../packages/ui/src/components/ui/radix/*"
|
|
800
|
+
],
|
|
801
|
+
"@/components/ui/radix/*": [
|
|
802
|
+
"../../packages/ui/src/components/ui/radix/*"
|
|
803
|
+
],
|
|
472
804
|
"@/lib/utils": ["../../packages/ui/src/lib/utils"],
|
|
473
805
|
"@assistant-ui/ui/*": ["../../packages/ui/src/*"]
|
|
474
806
|
}
|