@assistant-ui/mcp-docs-server 0.1.31 → 0.1.33
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 +23 -25
- package/.docs/organized/code-examples/with-a2a.md +28 -28
- package/.docs/organized/code-examples/with-ag-ui.md +35 -30
- package/.docs/organized/code-examples/with-ai-sdk-v6.md +16 -14
- package/.docs/organized/code-examples/with-artifacts.md +44 -38
- package/.docs/organized/code-examples/with-assistant-transport.md +68 -56
- package/.docs/organized/code-examples/with-browser-extension.md +357 -0
- package/.docs/organized/code-examples/with-chain-of-thought.md +425 -90
- package/.docs/organized/code-examples/with-cloud-standalone.md +30 -29
- package/.docs/organized/code-examples/with-cloud.md +16 -14
- package/.docs/organized/code-examples/with-custom-thread-list.md +19 -17
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +29 -26
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +20 -18
- package/.docs/organized/code-examples/with-expo.md +37 -31
- package/.docs/organized/code-examples/with-external-store.md +13 -11
- package/.docs/organized/code-examples/with-ffmpeg.md +327 -290
- package/.docs/organized/code-examples/with-generative-ui.md +1195 -194
- package/.docs/organized/code-examples/with-google-adk.md +13 -11
- package/.docs/organized/code-examples/with-heat-graph.md +16 -14
- package/.docs/organized/code-examples/with-image-generation.md +456 -0
- package/.docs/organized/code-examples/with-interactables.md +322 -244
- package/.docs/organized/code-examples/with-langchain.md +18 -16
- package/.docs/organized/code-examples/with-langgraph.md +95 -88
- package/.docs/organized/code-examples/with-livekit.md +30 -27
- package/.docs/organized/code-examples/with-mcp.md +754 -0
- package/.docs/organized/code-examples/with-opencode.md +70 -70
- package/.docs/organized/code-examples/with-react-hook-form.md +24 -22
- package/.docs/organized/code-examples/with-react-ink.md +4 -4
- package/.docs/organized/code-examples/with-react-router.md +20 -18
- package/.docs/organized/code-examples/with-resumable-stream.md +661 -0
- package/.docs/organized/code-examples/with-store.md +22 -20
- package/.docs/organized/code-examples/with-tanstack.md +18 -19
- package/.docs/organized/code-examples/with-tap-runtime.md +31 -28
- package/.docs/raw/docs/(docs)/architecture.mdx +43 -2
- package/.docs/raw/docs/(docs)/cli.mdx +2 -2
- package/.docs/raw/docs/(docs)/copilots/model-context.mdx +34 -26
- package/.docs/raw/docs/(docs)/copilots/motivation.mdx +32 -26
- package/.docs/raw/docs/(docs)/index.mdx +2 -2
- package/.docs/raw/docs/(docs)/installation.mdx +2 -2
- 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 +41 -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 +46 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +18 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +33 -0
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/spec.mdx +45 -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 +31 -52
- 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 +109 -0
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +58 -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 +109 -132
- 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 +202 -588
- 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 +85 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +39 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +127 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +42 -0
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +91 -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 +143 -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 -3
- 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 +12 -14
- package/.docs/raw/docs/guides/context-api.mdx +6 -5
- package/.docs/raw/docs/guides/dictation.mdx +2 -2
- package/.docs/raw/docs/guides/editing.mdx +1 -1
- package/.docs/raw/docs/guides/image-generation.mdx +74 -0
- package/.docs/raw/docs/guides/index.mdx +5 -14
- package/.docs/raw/docs/guides/latex.mdx +2 -2
- package/.docs/raw/docs/guides/mentions.mdx +6 -6
- package/.docs/raw/docs/guides/message-timing.mdx +38 -5
- 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 +2 -2
- package/.docs/raw/docs/guides/speech.mdx +2 -2
- package/.docs/raw/docs/guides/suggestions.mdx +89 -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/hooks.mdx +98 -85
- package/.docs/raw/docs/ink/index.mdx +10 -11
- package/.docs/raw/docs/ink/migration.mdx +1 -1
- package/.docs/raw/docs/ink/primitives.mdx +350 -9
- 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 +3 -3
- 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 +17 -5
- 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/persistence/custom-adapter.mdx +17 -2
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +226 -0
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +10 -16
- package/.docs/raw/docs/primitives/composer.mdx +53 -0
- package/.docs/raw/docs/primitives/index.mdx +2 -2
- package/.docs/raw/docs/primitives/message.mdx +9 -10
- package/.docs/raw/docs/primitives/suggestion.mdx +9 -0
- package/.docs/raw/docs/react-native/hooks.mdx +57 -82
- package/.docs/raw/docs/react-native/index.mdx +4 -4
- package/.docs/raw/docs/react-native/migration.mdx +1 -1
- package/.docs/raw/docs/react-native/primitives.mdx +2 -2
- package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +7 -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 +129 -1
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +7 -1
- 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/local-runtime.mdx +18 -7
- package/.docs/raw/docs/runtimes/custom/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +108 -38
- 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/generative-ui.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +2 -2
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +1 -1
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +64 -50
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +98 -86
- 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/tools/backend.mdx +136 -0
- package/.docs/raw/docs/tools/defining-tools.mdx +413 -0
- package/.docs/raw/docs/tools/dynamic-tools.mdx +110 -0
- package/.docs/raw/docs/tools/generative-ui.mdx +214 -0
- package/.docs/raw/docs/tools/index.mdx +76 -0
- package/.docs/raw/docs/{guides → tools}/interactables.mdx +3 -3
- package/.docs/raw/docs/tools/mcp-apps.mdx +231 -0
- package/.docs/raw/docs/{integrations/tools → tools}/mcp.mdx +77 -50
- package/.docs/raw/docs/{guides → tools}/multi-agent.mdx +19 -21
- package/.docs/raw/docs/tools/tool-ui.mdx +967 -0
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +337 -0
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +11 -1
- package/.docs/raw/docs/ui/directive-text.mdx +3 -3
- 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/part-grouping.mdx +84 -50
- package/.docs/raw/docs/ui/reasoning.mdx +4 -5
- 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/.docs/raw/docs/ui/tool-group.mdx +5 -6
- package/.docs/raw/docs/utilities/heat-graph.mdx +1 -1
- 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/organized/code-examples/with-parent-id-grouping.md +0 -596
- package/.docs/raw/docs/(docs)/copilots/make-assistant-tool-ui.mdx +0 -151
- package/.docs/raw/docs/(docs)/copilots/make-assistant-tool.mdx +0 -230
- 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/.docs/raw/docs/guides/tool-ui.mdx +0 -858
- package/.docs/raw/docs/guides/tools.mdx +0 -675
- 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
|
@@ -29,7 +29,7 @@ export async function POST(req: Request) {
|
|
|
29
29
|
|
|
30
30
|
// Convert client-defined tools (forwarded from model context) to AI SDK format.
|
|
31
31
|
// These have no `execute` — they are frontend tools executed on the client
|
|
32
|
-
// via
|
|
32
|
+
// via Tools({ toolkit }) / useAssistantInteractable.
|
|
33
33
|
const tools = clientTools
|
|
34
34
|
? Object.fromEntries(
|
|
35
35
|
Object.entries(clientTools).map(([name, def]) => [
|
|
@@ -43,7 +43,7 @@ export async function POST(req: Request) {
|
|
|
43
43
|
: undefined;
|
|
44
44
|
|
|
45
45
|
const result = streamText({
|
|
46
|
-
model: openai("gpt-
|
|
46
|
+
model: openai("gpt-5.4-nano"),
|
|
47
47
|
messages: await convertToModelMessages(messages),
|
|
48
48
|
stopWhen: stepCountIs(10),
|
|
49
49
|
...(system ? { system } : {}),
|
|
@@ -214,20 +214,28 @@ export default function RootLayout({
|
|
|
214
214
|
```tsx
|
|
215
215
|
"use client";
|
|
216
216
|
|
|
217
|
-
import {
|
|
217
|
+
import {
|
|
218
|
+
useRef,
|
|
219
|
+
useState,
|
|
220
|
+
useCallback,
|
|
221
|
+
useEffect,
|
|
222
|
+
type Dispatch,
|
|
223
|
+
type SetStateAction,
|
|
224
|
+
} from "react";
|
|
218
225
|
import { Thread } from "@/components/assistant-ui/thread";
|
|
219
226
|
import {
|
|
220
227
|
AssistantRuntimeProvider,
|
|
228
|
+
AuiProvider,
|
|
221
229
|
Interactables,
|
|
222
230
|
Suggestions,
|
|
231
|
+
Tools,
|
|
223
232
|
useAui,
|
|
233
|
+
useAuiToolOverrides,
|
|
224
234
|
useAssistantInteractable,
|
|
225
235
|
useInteractableState,
|
|
226
|
-
useAssistantTool,
|
|
227
236
|
} from "@assistant-ui/react";
|
|
228
237
|
import { useChatRuntime } from "@assistant-ui/react-ai-sdk";
|
|
229
238
|
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
230
|
-
import { z } from "zod";
|
|
231
239
|
import {
|
|
232
240
|
CheckCircle2Icon,
|
|
233
241
|
CircleIcon,
|
|
@@ -237,23 +245,15 @@ import {
|
|
|
237
245
|
Trash2Icon,
|
|
238
246
|
PlusIcon,
|
|
239
247
|
} from "lucide-react";
|
|
240
|
-
|
|
241
|
-
type
|
|
242
|
-
type TaskBoardState
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
done: z.boolean(),
|
|
250
|
-
}),
|
|
251
|
-
),
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
const taskBoardInitialState: TaskBoardState = { tasks: [] };
|
|
255
|
-
|
|
256
|
-
let nextTaskId = 0;
|
|
248
|
+
import {
|
|
249
|
+
type NoteState,
|
|
250
|
+
type TaskBoardState,
|
|
251
|
+
noteInitialState,
|
|
252
|
+
noteSchema,
|
|
253
|
+
taskBoardInitialState,
|
|
254
|
+
taskBoardSchema,
|
|
255
|
+
} from "./state";
|
|
256
|
+
import toolkit from "./toolkits";
|
|
257
257
|
|
|
258
258
|
function TaskBoard() {
|
|
259
259
|
const id = useAssistantInteractable("taskBoard", {
|
|
@@ -267,140 +267,128 @@ function TaskBoard() {
|
|
|
267
267
|
taskBoardInitialState,
|
|
268
268
|
);
|
|
269
269
|
|
|
270
|
-
const
|
|
271
|
-
setStateRef.current = setState;
|
|
272
|
-
|
|
273
|
-
useAssistantTool({
|
|
274
|
-
toolName: "manage_tasks",
|
|
275
|
-
description:
|
|
276
|
-
'Manage tasks on the task board. Actions: "add" (requires title), "toggle" (requires id), "remove" (requires id), "clear" (no extra fields).',
|
|
277
|
-
parameters: z.object({
|
|
278
|
-
action: z.enum(["add", "toggle", "remove", "clear"]),
|
|
279
|
-
title: z.string().optional(),
|
|
280
|
-
id: z.string().optional(),
|
|
281
|
-
}),
|
|
282
|
-
execute: async (args) => {
|
|
283
|
-
const set = setStateRef.current;
|
|
284
|
-
switch (args.action) {
|
|
285
|
-
case "add": {
|
|
286
|
-
const id = `task-${++nextTaskId}`;
|
|
287
|
-
set((prev) => ({
|
|
288
|
-
tasks: [
|
|
289
|
-
...prev.tasks,
|
|
290
|
-
{ id, title: args.title ?? "Untitled", done: false },
|
|
291
|
-
],
|
|
292
|
-
}));
|
|
293
|
-
return { success: true, id };
|
|
294
|
-
}
|
|
295
|
-
case "toggle": {
|
|
296
|
-
if (!args.id) return { success: false, error: "id is required" };
|
|
297
|
-
set((prev) => ({
|
|
298
|
-
tasks: prev.tasks.map((t) =>
|
|
299
|
-
t.id === args.id ? { ...t, done: !t.done } : t,
|
|
300
|
-
),
|
|
301
|
-
}));
|
|
302
|
-
return { success: true };
|
|
303
|
-
}
|
|
304
|
-
case "remove": {
|
|
305
|
-
if (!args.id) return { success: false, error: "id is required" };
|
|
306
|
-
set((prev) => ({
|
|
307
|
-
tasks: prev.tasks.filter((t) => t.id !== args.id),
|
|
308
|
-
}));
|
|
309
|
-
return { success: true };
|
|
310
|
-
}
|
|
311
|
-
case "clear": {
|
|
312
|
-
set({ tasks: [] });
|
|
313
|
-
return { success: true };
|
|
314
|
-
}
|
|
315
|
-
default:
|
|
316
|
-
return { success: false, error: "Unknown action" };
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
});
|
|
270
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
320
271
|
|
|
321
272
|
const doneCount = state.tasks.filter((t) => t.done).length;
|
|
322
273
|
|
|
323
274
|
return (
|
|
324
|
-
<
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
<
|
|
328
|
-
|
|
329
|
-
<
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
type="button"
|
|
351
|
-
onClick={() =>
|
|
352
|
-
setState((prev) => ({
|
|
353
|
-
tasks: prev.tasks.map((t) =>
|
|
354
|
-
t.id === task.id ? { ...t, done: !t.done } : t,
|
|
355
|
-
),
|
|
356
|
-
}))
|
|
357
|
-
}
|
|
358
|
-
className="shrink-0"
|
|
359
|
-
>
|
|
360
|
-
{task.done ? (
|
|
361
|
-
<CheckCircle2Icon className="size-4 text-primary" />
|
|
362
|
-
) : (
|
|
363
|
-
<CircleIcon className="size-4 text-muted-foreground" />
|
|
364
|
-
)}
|
|
365
|
-
</button>
|
|
366
|
-
<span
|
|
367
|
-
className={`flex-1 text-sm ${task.done ? "text-muted-foreground line-through" : ""}`}
|
|
368
|
-
>
|
|
369
|
-
{task.title}
|
|
370
|
-
</span>
|
|
371
|
-
<button
|
|
372
|
-
type="button"
|
|
373
|
-
onClick={() =>
|
|
374
|
-
setState((prev) => ({
|
|
375
|
-
tasks: prev.tasks.filter((t) => t.id !== task.id),
|
|
376
|
-
}))
|
|
377
|
-
}
|
|
378
|
-
className="shrink-0 opacity-0 transition-opacity group-hover:opacity-100"
|
|
275
|
+
<AuiProvider value={aui}>
|
|
276
|
+
<TaskBoardToolOverrides setState={setState} />
|
|
277
|
+
<div className="flex flex-col">
|
|
278
|
+
<div className="flex items-center gap-2 border-b px-4 py-3">
|
|
279
|
+
<ListTodoIcon className="text-muted-foreground size-4" />
|
|
280
|
+
<span className="text-sm font-semibold">Task Board</span>
|
|
281
|
+
{isPending && (
|
|
282
|
+
<Loader2Icon className="text-muted-foreground size-3 animate-spin" />
|
|
283
|
+
)}
|
|
284
|
+
{state.tasks.length > 0 && (
|
|
285
|
+
<span className="bg-primary/10 text-primary ml-auto rounded-full px-2 py-0.5 text-xs font-medium">
|
|
286
|
+
{doneCount}/{state.tasks.length}
|
|
287
|
+
</span>
|
|
288
|
+
)}
|
|
289
|
+
</div>
|
|
290
|
+
<div className="flex-1 overflow-y-auto p-3">
|
|
291
|
+
{state.tasks.length === 0 ? (
|
|
292
|
+
<p className="text-muted-foreground py-6 text-center text-xs">
|
|
293
|
+
No tasks yet. Ask the assistant!
|
|
294
|
+
</p>
|
|
295
|
+
) : (
|
|
296
|
+
<ul className="space-y-1">
|
|
297
|
+
{state.tasks.map((task) => (
|
|
298
|
+
<li
|
|
299
|
+
key={task.id}
|
|
300
|
+
className="group hover:bg-muted flex items-center gap-2 rounded-lg px-3 py-2 transition-colors"
|
|
379
301
|
>
|
|
380
|
-
<
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
302
|
+
<button
|
|
303
|
+
type="button"
|
|
304
|
+
onClick={() =>
|
|
305
|
+
setState((prev) => ({
|
|
306
|
+
tasks: prev.tasks.map((t) =>
|
|
307
|
+
t.id === task.id ? { ...t, done: !t.done } : t,
|
|
308
|
+
),
|
|
309
|
+
}))
|
|
310
|
+
}
|
|
311
|
+
className="shrink-0"
|
|
312
|
+
>
|
|
313
|
+
{task.done ? (
|
|
314
|
+
<CheckCircle2Icon className="text-primary size-4" />
|
|
315
|
+
) : (
|
|
316
|
+
<CircleIcon className="text-muted-foreground size-4" />
|
|
317
|
+
)}
|
|
318
|
+
</button>
|
|
319
|
+
<span
|
|
320
|
+
className={`flex-1 text-sm ${task.done ? "text-muted-foreground line-through" : ""}`}
|
|
321
|
+
>
|
|
322
|
+
{task.title}
|
|
323
|
+
</span>
|
|
324
|
+
<button
|
|
325
|
+
type="button"
|
|
326
|
+
onClick={() =>
|
|
327
|
+
setState((prev) => ({
|
|
328
|
+
tasks: prev.tasks.filter((t) => t.id !== task.id),
|
|
329
|
+
}))
|
|
330
|
+
}
|
|
331
|
+
className="shrink-0 opacity-0 transition-opacity group-hover:opacity-100"
|
|
332
|
+
>
|
|
333
|
+
<Trash2Icon className="text-muted-foreground hover:text-destructive size-3.5" />
|
|
334
|
+
</button>
|
|
335
|
+
</li>
|
|
336
|
+
))}
|
|
337
|
+
</ul>
|
|
338
|
+
)}
|
|
339
|
+
</div>
|
|
386
340
|
</div>
|
|
387
|
-
</
|
|
341
|
+
</AuiProvider>
|
|
388
342
|
);
|
|
389
343
|
}
|
|
390
344
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
345
|
+
function TaskBoardToolOverrides({
|
|
346
|
+
setState,
|
|
347
|
+
}: {
|
|
348
|
+
setState: Dispatch<SetStateAction<TaskBoardState>>;
|
|
349
|
+
}) {
|
|
350
|
+
useAuiToolOverrides({
|
|
351
|
+
manage_tasks: {
|
|
352
|
+
execute: async (args) => {
|
|
353
|
+
switch (args.action) {
|
|
354
|
+
case "add": {
|
|
355
|
+
const id = crypto.randomUUID();
|
|
356
|
+
setState((prev) => ({
|
|
357
|
+
tasks: [
|
|
358
|
+
...prev.tasks,
|
|
359
|
+
{ id, title: args.title ?? "Untitled", done: false },
|
|
360
|
+
],
|
|
361
|
+
}));
|
|
362
|
+
return { success: true, id };
|
|
363
|
+
}
|
|
364
|
+
case "toggle": {
|
|
365
|
+
if (!args.id) return { success: false, error: "id is required" };
|
|
366
|
+
setState((prev) => ({
|
|
367
|
+
tasks: prev.tasks.map((t) =>
|
|
368
|
+
t.id === args.id ? { ...t, done: !t.done } : t,
|
|
369
|
+
),
|
|
370
|
+
}));
|
|
371
|
+
return { success: true };
|
|
372
|
+
}
|
|
373
|
+
case "remove": {
|
|
374
|
+
if (!args.id) return { success: false, error: "id is required" };
|
|
375
|
+
setState((prev) => ({
|
|
376
|
+
tasks: prev.tasks.filter((t) => t.id !== args.id),
|
|
377
|
+
}));
|
|
378
|
+
return { success: true };
|
|
379
|
+
}
|
|
380
|
+
case "clear": {
|
|
381
|
+
setState({ tasks: [] });
|
|
382
|
+
return { success: true };
|
|
383
|
+
}
|
|
384
|
+
default:
|
|
385
|
+
return { success: false, error: "Unknown action" };
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
404
392
|
|
|
405
393
|
const COLORS: Record<string, string> = {
|
|
406
394
|
yellow: "bg-yellow-100 border-yellow-300",
|
|
@@ -441,20 +429,19 @@ function NoteCard({
|
|
|
441
429
|
};
|
|
442
430
|
|
|
443
431
|
return (
|
|
444
|
-
// biome-ignore lint/a11y/useSemanticElements: styled interactive card
|
|
445
432
|
<div
|
|
446
433
|
role="button"
|
|
447
434
|
tabIndex={0}
|
|
448
435
|
onClick={handleClick}
|
|
449
436
|
onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && handleClick()}
|
|
450
|
-
className={`group relative flex w-full cursor-pointer flex-col gap-1 rounded-lg border-2 p-3 text-left transition-all ${COLORS[state.color] ?? COLORS.yellow} ${isSelected ? "ring-
|
|
437
|
+
className={`group relative flex w-full cursor-pointer flex-col gap-1 rounded-lg border-2 p-3 text-left transition-all ${COLORS[state.color] ?? COLORS.yellow} ${isSelected ? "ring-primary ring-2 ring-offset-1" : "hover:shadow-sm"}`}
|
|
451
438
|
>
|
|
452
439
|
{isSelected && (
|
|
453
|
-
<span className="absolute top-1.5 right-2 rounded
|
|
440
|
+
<span className="bg-primary text-primary-foreground absolute top-1.5 right-2 rounded px-1.5 py-0.5 text-[10px] leading-none font-medium">
|
|
454
441
|
SELECTED
|
|
455
442
|
</span>
|
|
456
443
|
)}
|
|
457
|
-
<span className="pr-16 font-semibold text-
|
|
444
|
+
<span className="pr-16 text-sm font-semibold text-zinc-800">
|
|
458
445
|
{state.title}
|
|
459
446
|
</span>
|
|
460
447
|
<span className="line-clamp-3 text-xs text-zinc-600">
|
|
@@ -466,7 +453,7 @@ function NoteCard({
|
|
|
466
453
|
e.stopPropagation();
|
|
467
454
|
onRemove(noteId);
|
|
468
455
|
}}
|
|
469
|
-
className="absolute right-2 bottom-2 rounded p-0.5 opacity-0 transition-opacity hover:bg-black/10
|
|
456
|
+
className="absolute right-2 bottom-2 rounded p-0.5 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-black/10"
|
|
470
457
|
>
|
|
471
458
|
<Trash2Icon className="size-3 text-zinc-500" />
|
|
472
459
|
</button>
|
|
@@ -500,46 +487,7 @@ function NotesPanel() {
|
|
|
500
487
|
localStorage.setItem(NOTE_IDS_KEY, JSON.stringify(noteIds));
|
|
501
488
|
}, [noteIds]);
|
|
502
489
|
|
|
503
|
-
const
|
|
504
|
-
noteIdsRef.current = noteIds;
|
|
505
|
-
const setNoteIdsRef = useRef(setNoteIds);
|
|
506
|
-
setNoteIdsRef.current = setNoteIds;
|
|
507
|
-
const setSelectedIdRef = useRef(setSelectedId);
|
|
508
|
-
setSelectedIdRef.current = setSelectedId;
|
|
509
|
-
|
|
510
|
-
useAssistantTool({
|
|
511
|
-
toolName: "manage_notes",
|
|
512
|
-
description:
|
|
513
|
-
'Manage sticky notes. Actions: "add" (creates a new note, returns its id), "remove" (requires noteId), "clear" (removes all notes). After adding, use the update_note_{id} tool to set its content.',
|
|
514
|
-
parameters: z.object({
|
|
515
|
-
action: z.enum(["add", "remove", "clear"]),
|
|
516
|
-
noteId: z.string().optional(),
|
|
517
|
-
}),
|
|
518
|
-
execute: async (args) => {
|
|
519
|
-
switch (args.action) {
|
|
520
|
-
case "add": {
|
|
521
|
-
const id = `note-${Date.now().toString(36)}`;
|
|
522
|
-
setNoteIdsRef.current((prev) => [...prev, id]);
|
|
523
|
-
return { success: true, noteId: id };
|
|
524
|
-
}
|
|
525
|
-
case "remove": {
|
|
526
|
-
if (args.noteId) {
|
|
527
|
-
setNoteIdsRef.current((prev) =>
|
|
528
|
-
prev.filter((id) => id !== args.noteId),
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
return { success: true };
|
|
532
|
-
}
|
|
533
|
-
case "clear": {
|
|
534
|
-
setNoteIdsRef.current([]);
|
|
535
|
-
setSelectedIdRef.current(null);
|
|
536
|
-
return { success: true };
|
|
537
|
-
}
|
|
538
|
-
default:
|
|
539
|
-
return { success: false, error: "Unknown action" };
|
|
540
|
-
}
|
|
541
|
-
},
|
|
542
|
-
});
|
|
490
|
+
const aui = useAui({ tools: Tools({ toolkit }) });
|
|
543
491
|
|
|
544
492
|
const handleSelect = useCallback((id: string) => {
|
|
545
493
|
setSelectedId(id);
|
|
@@ -551,47 +499,89 @@ function NotesPanel() {
|
|
|
551
499
|
}, []);
|
|
552
500
|
|
|
553
501
|
return (
|
|
554
|
-
<
|
|
555
|
-
<
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
502
|
+
<AuiProvider value={aui}>
|
|
503
|
+
<NotesToolOverrides
|
|
504
|
+
setNoteIds={setNoteIds}
|
|
505
|
+
setSelectedId={setSelectedId}
|
|
506
|
+
/>
|
|
507
|
+
<div className="flex flex-col">
|
|
508
|
+
<div className="flex items-center gap-2 border-b px-4 py-3">
|
|
509
|
+
<StickyNoteIcon className="text-muted-foreground size-4" />
|
|
510
|
+
<span className="text-sm font-semibold">Notes</span>
|
|
511
|
+
<span className="text-muted-foreground ml-auto text-xs">
|
|
512
|
+
{noteIds.length}
|
|
513
|
+
</span>
|
|
514
|
+
<button
|
|
515
|
+
type="button"
|
|
516
|
+
onClick={() => {
|
|
517
|
+
const id = `note-${crypto.randomUUID()}`;
|
|
518
|
+
setNoteIds((prev) => [...prev, id]);
|
|
519
|
+
}}
|
|
520
|
+
className="hover:bg-muted rounded p-1 transition-colors"
|
|
521
|
+
>
|
|
522
|
+
<PlusIcon className="text-muted-foreground size-3.5" />
|
|
523
|
+
</button>
|
|
524
|
+
</div>
|
|
525
|
+
<div className="flex-1 overflow-y-auto p-3">
|
|
526
|
+
{noteIds.length === 0 ? (
|
|
527
|
+
<p className="text-muted-foreground py-6 text-center text-xs">
|
|
528
|
+
No notes yet. Ask the assistant!
|
|
529
|
+
</p>
|
|
530
|
+
) : (
|
|
531
|
+
<div className="grid gap-2">
|
|
532
|
+
{noteIds.map((noteId) => (
|
|
533
|
+
<NoteCard
|
|
534
|
+
key={noteId}
|
|
535
|
+
noteId={noteId}
|
|
536
|
+
selectedId={selectedId}
|
|
537
|
+
onSelect={handleSelect}
|
|
538
|
+
onRemove={handleRemove}
|
|
539
|
+
/>
|
|
540
|
+
))}
|
|
541
|
+
</div>
|
|
542
|
+
)}
|
|
543
|
+
</div>
|
|
590
544
|
</div>
|
|
591
|
-
</
|
|
545
|
+
</AuiProvider>
|
|
592
546
|
);
|
|
593
547
|
}
|
|
594
548
|
|
|
549
|
+
function NotesToolOverrides({
|
|
550
|
+
setNoteIds,
|
|
551
|
+
setSelectedId,
|
|
552
|
+
}: {
|
|
553
|
+
setNoteIds: Dispatch<SetStateAction<string[]>>;
|
|
554
|
+
setSelectedId: Dispatch<SetStateAction<string | null>>;
|
|
555
|
+
}) {
|
|
556
|
+
useAuiToolOverrides({
|
|
557
|
+
manage_notes: {
|
|
558
|
+
execute: async (args) => {
|
|
559
|
+
switch (args.action) {
|
|
560
|
+
case "add": {
|
|
561
|
+
const id = `note-${crypto.randomUUID()}`;
|
|
562
|
+
setNoteIds((prev) => [...prev, id]);
|
|
563
|
+
return { success: true, noteId: id };
|
|
564
|
+
}
|
|
565
|
+
case "remove": {
|
|
566
|
+
if (args.noteId) {
|
|
567
|
+
setNoteIds((prev) => prev.filter((id) => id !== args.noteId));
|
|
568
|
+
}
|
|
569
|
+
return { success: true };
|
|
570
|
+
}
|
|
571
|
+
case "clear": {
|
|
572
|
+
setNoteIds([]);
|
|
573
|
+
setSelectedId(null);
|
|
574
|
+
return { success: true };
|
|
575
|
+
}
|
|
576
|
+
default:
|
|
577
|
+
return { success: false, error: "Unknown action" };
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
|
|
595
585
|
const STORAGE_KEY = "interactables-example";
|
|
596
586
|
|
|
597
587
|
function useInteractablePersistence(aui: ReturnType<typeof useAui>) {
|
|
@@ -663,6 +653,92 @@ export default function Home() {
|
|
|
663
653
|
|
|
664
654
|
```
|
|
665
655
|
|
|
656
|
+
## app/state.ts
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
import { z } from "zod";
|
|
660
|
+
|
|
661
|
+
export type Task = { id: string; title: string; done: boolean };
|
|
662
|
+
export type TaskBoardState = { tasks: Task[] };
|
|
663
|
+
|
|
664
|
+
export const taskBoardSchema = z.object({
|
|
665
|
+
tasks: z.array(
|
|
666
|
+
z.object({
|
|
667
|
+
id: z.string(),
|
|
668
|
+
title: z.string(),
|
|
669
|
+
done: z.boolean(),
|
|
670
|
+
}),
|
|
671
|
+
),
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
export const taskBoardInitialState: TaskBoardState = { tasks: [] };
|
|
675
|
+
|
|
676
|
+
export const manageTasksParameters = z.object({
|
|
677
|
+
action: z.enum(["add", "toggle", "remove", "clear"]),
|
|
678
|
+
title: z.string().optional(),
|
|
679
|
+
id: z.string().optional(),
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
export type ManageTasksArgs = z.infer<typeof manageTasksParameters>;
|
|
683
|
+
|
|
684
|
+
export type NoteState = { title: string; content: string; color: string };
|
|
685
|
+
|
|
686
|
+
export const noteSchema = z.object({
|
|
687
|
+
title: z.string(),
|
|
688
|
+
content: z.string(),
|
|
689
|
+
color: z.enum(["yellow", "blue", "green", "pink"]),
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
export const noteInitialState: NoteState = {
|
|
693
|
+
title: "New Note",
|
|
694
|
+
content: "",
|
|
695
|
+
color: "yellow",
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
export const manageNotesParameters = z.object({
|
|
699
|
+
action: z.enum(["add", "remove", "clear"]),
|
|
700
|
+
noteId: z.string().optional(),
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
export type ManageNotesArgs = z.infer<typeof manageNotesParameters>;
|
|
704
|
+
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
## app/toolkits.ts
|
|
708
|
+
|
|
709
|
+
```typescript
|
|
710
|
+
"use generative";
|
|
711
|
+
|
|
712
|
+
import { defineToolkit, stubTool } from "@assistant-ui/react";
|
|
713
|
+
import { manageNotesParameters, manageTasksParameters } from "./state";
|
|
714
|
+
|
|
715
|
+
export default defineToolkit({
|
|
716
|
+
manage_tasks: {
|
|
717
|
+
description:
|
|
718
|
+
'Manage tasks on the task board. Actions: "add" (requires title), "toggle" (requires id), "remove" (requires id), "clear" (no extra fields).',
|
|
719
|
+
parameters: manageTasksParameters,
|
|
720
|
+
// The generative compiler strips this stub; TaskBoardToolOverrides provides the real executor.
|
|
721
|
+
execute: stubTool(),
|
|
722
|
+
renderText: {
|
|
723
|
+
running: ({ args }) => `Updating tasks: ${args.action}`,
|
|
724
|
+
complete: "Tasks updated",
|
|
725
|
+
},
|
|
726
|
+
},
|
|
727
|
+
manage_notes: {
|
|
728
|
+
description:
|
|
729
|
+
'Manage sticky notes. Actions: "add" (creates a new note, returns its id), "remove" (requires noteId), "clear" (removes all notes). After adding, use the update_note_{id} tool to set its content.',
|
|
730
|
+
parameters: manageNotesParameters,
|
|
731
|
+
// The generative compiler strips this stub; NotesToolOverrides provides the real executor.
|
|
732
|
+
execute: stubTool(),
|
|
733
|
+
renderText: {
|
|
734
|
+
running: ({ args }) => `Updating notes: ${args.action}`,
|
|
735
|
+
complete: "Notes updated",
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
```
|
|
741
|
+
|
|
666
742
|
## components.json
|
|
667
743
|
|
|
668
744
|
```json
|
|
@@ -696,13 +772,14 @@ export default function Home() {
|
|
|
696
772
|
## next.config.ts
|
|
697
773
|
|
|
698
774
|
```typescript
|
|
775
|
+
import { withAui } from "@assistant-ui/next";
|
|
699
776
|
import type { NextConfig } from "next";
|
|
700
777
|
|
|
701
778
|
const nextConfig: NextConfig = {
|
|
702
779
|
/* config options here */
|
|
703
780
|
};
|
|
704
781
|
|
|
705
|
-
export default nextConfig;
|
|
782
|
+
export default withAui(nextConfig);
|
|
706
783
|
|
|
707
784
|
```
|
|
708
785
|
|
|
@@ -720,28 +797,29 @@ export default nextConfig;
|
|
|
720
797
|
"start": "next start"
|
|
721
798
|
},
|
|
722
799
|
"dependencies": {
|
|
723
|
-
"@ai-sdk/openai": "^3.0.
|
|
800
|
+
"@ai-sdk/openai": "^3.0.67",
|
|
724
801
|
"@assistant-ui/react": "workspace:*",
|
|
725
802
|
"@assistant-ui/react-ai-sdk": "workspace:*",
|
|
726
803
|
"@assistant-ui/ui": "workspace:*",
|
|
727
|
-
"ai": "^6.0.
|
|
804
|
+
"ai": "^6.0.193",
|
|
728
805
|
"class-variance-authority": "^0.7.1",
|
|
729
806
|
"clsx": "^2.1.1",
|
|
730
|
-
"lucide-react": "^1.
|
|
731
|
-
"next": "^16.2.
|
|
732
|
-
"react": "^19.2.
|
|
733
|
-
"react-dom": "^19.2.
|
|
734
|
-
"tailwind-merge": "^3.
|
|
807
|
+
"lucide-react": "^1.17.0",
|
|
808
|
+
"next": "^16.2.6",
|
|
809
|
+
"react": "^19.2.6",
|
|
810
|
+
"react-dom": "^19.2.6",
|
|
811
|
+
"tailwind-merge": "^3.6.0",
|
|
735
812
|
"zod": "^4.4.3"
|
|
736
813
|
},
|
|
737
814
|
"devDependencies": {
|
|
815
|
+
"@assistant-ui/next": "workspace:*",
|
|
738
816
|
"@assistant-ui/x-buildutils": "workspace:*",
|
|
739
|
-
"@tailwindcss/postcss": "^4.
|
|
740
|
-
"@types/node": "^25.
|
|
741
|
-
"@types/react": "^19.2.
|
|
817
|
+
"@tailwindcss/postcss": "^4.3.0",
|
|
818
|
+
"@types/node": "^25.9.1",
|
|
819
|
+
"@types/react": "^19.2.15",
|
|
742
820
|
"@types/react-dom": "^19.2.3",
|
|
743
|
-
"postcss": "^8.5.
|
|
744
|
-
"tailwindcss": "^4.
|
|
821
|
+
"postcss": "^8.5.15",
|
|
822
|
+
"tailwindcss": "^4.3.0",
|
|
745
823
|
"tw-animate-css": "^1.4.0",
|
|
746
824
|
"typescript": "^6.0.3"
|
|
747
825
|
}
|
|
@@ -760,7 +838,7 @@ Demonstrates **interactable components** — persistent UI components whose stat
|
|
|
760
838
|
|
|
761
839
|
### Task Board (single instance + custom tool)
|
|
762
840
|
- `useInteractable("taskBoard", config)` — registers a single interactable
|
|
763
|
-
- `
|
|
841
|
+
- `Tools({ toolkit })` — custom tool for incremental add/toggle/remove/clear
|
|
764
842
|
- Auto-generated `update_taskBoard` tool with **partial updates** (AI only sends changed fields)
|
|
765
843
|
|
|
766
844
|
### Sticky Notes (multi-instance + selection + partial updates)
|
|
@@ -792,7 +870,7 @@ Open [http://localhost:3000](http://localhost:3000) to see the example.
|
|
|
792
870
|
- **Partial updates** — auto-generated tools use partial schemas; AI only sends changed fields
|
|
793
871
|
- **Multi-instance** — same `name`, different `id`; tools named `update_{name}_{id}`
|
|
794
872
|
- **Selection** — `setSelected(true)` marks a component as focused for the AI
|
|
795
|
-
- **`
|
|
873
|
+
- **`Tools({ toolkit })`** — custom frontend tools for fine-grained control
|
|
796
874
|
- **`sendAutomaticallyWhen`** — auto-sends follow-up messages when tool calls complete
|
|
797
875
|
|
|
798
876
|
```
|