@assistant-ui/mcp-docs-server 0.2.3 → 0.3.1
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/README.md +16 -43
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -91
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +9 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +91 -0
- package/dist/proxy.js.map +1 -0
- package/package.json +8 -12
- package/src/index.ts +3 -115
- package/src/proxy.test.ts +385 -0
- package/src/proxy.ts +126 -0
- package/.docs/organized/code-examples/waterfall.md +0 -807
- package/.docs/organized/code-examples/with-a2a.md +0 -675
- package/.docs/organized/code-examples/with-ag-ui.md +0 -553
- package/.docs/organized/code-examples/with-ai-sdk-v7.md +0 -466
- package/.docs/organized/code-examples/with-artifacts.md +0 -815
- package/.docs/organized/code-examples/with-assistant-transport.md +0 -576
- package/.docs/organized/code-examples/with-browser-extension.md +0 -371
- package/.docs/organized/code-examples/with-chain-of-thought.md +0 -962
- package/.docs/organized/code-examples/with-cloud-standalone.md +0 -681
- package/.docs/organized/code-examples/with-cloud.md +0 -439
- package/.docs/organized/code-examples/with-custom-thread-list.md +0 -569
- package/.docs/organized/code-examples/with-elevenlabs-conversational.md +0 -527
- package/.docs/organized/code-examples/with-elevenlabs-scribe.md +0 -697
- package/.docs/organized/code-examples/with-eve.md +0 -405
- package/.docs/organized/code-examples/with-expo.md +0 -2246
- package/.docs/organized/code-examples/with-external-store.md +0 -421
- package/.docs/organized/code-examples/with-ffmpeg.md +0 -829
- package/.docs/organized/code-examples/with-generative-ui.md +0 -1810
- package/.docs/organized/code-examples/with-google-adk.md +0 -368
- package/.docs/organized/code-examples/with-heat-graph.md +0 -304
- package/.docs/organized/code-examples/with-image-generation.md +0 -463
- package/.docs/organized/code-examples/with-interactables.md +0 -733
- package/.docs/organized/code-examples/with-langchain.md +0 -446
- package/.docs/organized/code-examples/with-langgraph.md +0 -855
- package/.docs/organized/code-examples/with-livekit.md +0 -643
- package/.docs/organized/code-examples/with-mcp.md +0 -782
- package/.docs/organized/code-examples/with-nuxt.md +0 -2428
- package/.docs/organized/code-examples/with-opencode.md +0 -1974
- package/.docs/organized/code-examples/with-openui.md +0 -450
- package/.docs/organized/code-examples/with-pi.md +0 -2084
- package/.docs/organized/code-examples/with-react-hook-form.md +0 -727
- package/.docs/organized/code-examples/with-react-ink-web.md +0 -740
- package/.docs/organized/code-examples/with-react-ink.md +0 -473
- package/.docs/organized/code-examples/with-react-router.md +0 -936
- package/.docs/organized/code-examples/with-resumable-stream.md +0 -668
- package/.docs/organized/code-examples/with-store.md +0 -679
- package/.docs/organized/code-examples/with-svelte.md +0 -415
- package/.docs/organized/code-examples/with-sveltekit.md +0 -1061
- package/.docs/organized/code-examples/with-tanstack.md +0 -812
- package/.docs/organized/code-examples/with-tap-runtime.md +0 -813
- package/.docs/organized/code-examples/with-virtualized-thread.md +0 -681
- package/.docs/organized/code-examples/with-vue.md +0 -408
- package/.docs/raw/docs/(getting-started)/architecture.mdx +0 -146
- package/.docs/raw/docs/(getting-started)/base-ui.mdx +0 -39
- package/.docs/raw/docs/(getting-started)/cli.mdx +0 -542
- package/.docs/raw/docs/(getting-started)/devtools.mdx +0 -79
- package/.docs/raw/docs/(getting-started)/index.mdx +0 -23
- package/.docs/raw/docs/(getting-started)/installation.mdx +0 -483
- package/.docs/raw/docs/(getting-started)/llm.mdx +0 -211
- package/.docs/raw/docs/(getting-started)/rtl.mdx +0 -78
- package/.docs/raw/docs/(reference)/api-reference/adapters/attachments.mdx +0 -36
- package/.docs/raw/docs/(reference)/api-reference/adapters/feedback.mdx +0 -20
- package/.docs/raw/docs/(reference)/api-reference/adapters/index.mdx +0 -34
- package/.docs/raw/docs/(reference)/api-reference/adapters/model.mdx +0 -44
- package/.docs/raw/docs/(reference)/api-reference/adapters/persistence.mdx +0 -59
- package/.docs/raw/docs/(reference)/api-reference/adapters/runtime.mdx +0 -20
- package/.docs/raw/docs/(reference)/api-reference/adapters/suggestions.mdx +0 -26
- package/.docs/raw/docs/(reference)/api-reference/context-providers/assistant-runtime-provider.mdx +0 -84
- package/.docs/raw/docs/(reference)/api-reference/context-providers/index.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/context-providers/scoped-providers.mdx +0 -64
- package/.docs/raw/docs/(reference)/api-reference/external-store/index.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/external-store/message-conversion.mdx +0 -57
- package/.docs/raw/docs/(reference)/api-reference/external-store/runtime.mdx +0 -49
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/a2ui.mdx +0 -40
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/actions.mdx +0 -56
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/components.mdx +0 -86
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/index.mdx +0 -39
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/json-generative-ui.mdx +0 -42
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/rendering.mdx +0 -84
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/slack.mdx +0 -85
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/spec.mdx +0 -45
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/teams.mdx +0 -93
- package/.docs/raw/docs/(reference)/api-reference/generative-ui/tokens.mdx +0 -62
- package/.docs/raw/docs/(reference)/api-reference/hooks/composer-triggers.mdx +0 -129
- package/.docs/raw/docs/(reference)/api-reference/hooks/index.mdx +0 -31
- package/.docs/raw/docs/(reference)/api-reference/hooks/model-context.mdx +0 -34
- package/.docs/raw/docs/(reference)/api-reference/hooks/primitives.mdx +0 -350
- package/.docs/raw/docs/(reference)/api-reference/hooks/runtimes.mdx +0 -28
- package/.docs/raw/docs/(reference)/api-reference/hooks/state.mdx +0 -97
- package/.docs/raw/docs/(reference)/api-reference/integrations/ai-sdk.mdx +0 -200
- package/.docs/raw/docs/(reference)/api-reference/integrations/cloud-ai-sdk.mdx +0 -24
- package/.docs/raw/docs/(reference)/api-reference/integrations/eve.mdx +0 -118
- package/.docs/raw/docs/(reference)/api-reference/integrations/index.mdx +0 -28
- package/.docs/raw/docs/(reference)/api-reference/integrations/react-data-stream.mdx +0 -37
- package/.docs/raw/docs/(reference)/api-reference/model-context/context.mdx +0 -50
- package/.docs/raw/docs/(reference)/api-reference/model-context/index.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/model-context/registry.mdx +0 -20
- package/.docs/raw/docs/(reference)/api-reference/overview.mdx +0 -566
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar-more.mdx +0 -152
- package/.docs/raw/docs/(reference)/api-reference/primitives/action-bar.mdx +0 -239
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-if.mdx +0 -208
- package/.docs/raw/docs/(reference)/api-reference/primitives/assistant-modal.mdx +0 -108
- package/.docs/raw/docs/(reference)/api-reference/primitives/attachment.mdx +0 -99
- package/.docs/raw/docs/(reference)/api-reference/primitives/branch-picker.mdx +0 -145
- package/.docs/raw/docs/(reference)/api-reference/primitives/chain-of-thought.mdx +0 -82
- package/.docs/raw/docs/(reference)/api-reference/primitives/composer.mdx +0 -637
- package/.docs/raw/docs/(reference)/api-reference/primitives/composition.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/primitives/error.mdx +0 -65
- package/.docs/raw/docs/(reference)/api-reference/primitives/index.mdx +0 -73
- package/.docs/raw/docs/(reference)/api-reference/primitives/message-part.mdx +0 -117
- package/.docs/raw/docs/(reference)/api-reference/primitives/message.mdx +0 -339
- package/.docs/raw/docs/(reference)/api-reference/primitives/queue-item.mdx +0 -77
- package/.docs/raw/docs/(reference)/api-reference/primitives/selection-toolbar.mdx +0 -88
- package/.docs/raw/docs/(reference)/api-reference/primitives/suggestion.mdx +0 -81
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item-more.mdx +0 -129
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list-item.mdx +0 -138
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread-list.mdx +0 -122
- package/.docs/raw/docs/(reference)/api-reference/primitives/thread.mdx +0 -289
- package/.docs/raw/docs/(reference)/api-reference/runtimes/assistant-runtime.mdx +0 -20
- package/.docs/raw/docs/(reference)/api-reference/runtimes/attachment-runtime.mdx +0 -24
- package/.docs/raw/docs/(reference)/api-reference/runtimes/composer-runtime.mdx +0 -32
- package/.docs/raw/docs/(reference)/api-reference/runtimes/index.mdx +0 -43
- package/.docs/raw/docs/(reference)/api-reference/runtimes/message-part-runtime.mdx +0 -43
- package/.docs/raw/docs/(reference)/api-reference/runtimes/message-runtime.mdx +0 -24
- package/.docs/raw/docs/(reference)/api-reference/runtimes/queue-state.mdx +0 -20
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-item-runtime.mdx +0 -24
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-list-runtime.mdx +0 -24
- package/.docs/raw/docs/(reference)/api-reference/runtimes/thread-runtime.mdx +0 -36
- package/.docs/raw/docs/(reference)/api-reference/tools/component-tools.mdx +0 -85
- package/.docs/raw/docs/(reference)/api-reference/tools/index.mdx +0 -45
- package/.docs/raw/docs/(reference)/api-reference/tools/interactables-legacy.mdx +0 -55
- package/.docs/raw/docs/(reference)/api-reference/tools/interactables.mdx +0 -151
- package/.docs/raw/docs/(reference)/api-reference/tools/rendering.mdx +0 -106
- package/.docs/raw/docs/(reference)/api-reference/tools/status.mdx +0 -62
- package/.docs/raw/docs/(reference)/api-reference/tools/toolkits.mdx +0 -178
- package/.docs/raw/docs/(reference)/api-reference/transport/assistant-transport.mdx +0 -48
- package/.docs/raw/docs/(reference)/api-reference/transport/frame.mdx +0 -62
- package/.docs/raw/docs/(reference)/api-reference/transport/index.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/utilities/index.mdx +0 -19
- package/.docs/raw/docs/(reference)/api-reference/utilities/miscellaneous.mdx +0 -152
- package/.docs/raw/docs/(reference)/api-reference/voice/index.mdx +0 -22
- package/.docs/raw/docs/(reference)/api-reference/voice/session.mdx +0 -54
- package/.docs/raw/docs/(reference)/api-reference/voice/speech-dictation.mdx +0 -36
- package/.docs/raw/docs/cloud/ai-sdk-assistant-ui.mdx +0 -527
- package/.docs/raw/docs/cloud/ai-sdk.mdx +0 -604
- package/.docs/raw/docs/cloud/authorization.mdx +0 -252
- package/.docs/raw/docs/cloud/index.mdx +0 -46
- package/.docs/raw/docs/cloud/langgraph.mdx +0 -554
- package/.docs/raw/docs/copilots/assistant-frame.mdx +0 -411
- package/.docs/raw/docs/copilots/make-assistant-visible.mdx +0 -82
- package/.docs/raw/docs/copilots/model-context.mdx +0 -156
- package/.docs/raw/docs/copilots/motivation.mdx +0 -202
- package/.docs/raw/docs/copilots/use-assistant-instructions.mdx +0 -64
- package/.docs/raw/docs/guides/attachments.mdx +0 -619
- package/.docs/raw/docs/guides/branching.mdx +0 -76
- package/.docs/raw/docs/guides/chain-of-thought.mdx +0 -164
- package/.docs/raw/docs/guides/chatgpt-subscription.mdx +0 -108
- package/.docs/raw/docs/guides/context-api.mdx +0 -619
- package/.docs/raw/docs/guides/dictation.mdx +0 -298
- package/.docs/raw/docs/guides/editing.mdx +0 -102
- package/.docs/raw/docs/guides/electron.mdx +0 -369
- package/.docs/raw/docs/guides/headless-composer-input.mdx +0 -113
- package/.docs/raw/docs/guides/image-generation.mdx +0 -74
- package/.docs/raw/docs/guides/index.mdx +0 -117
- package/.docs/raw/docs/guides/input-history.mdx +0 -55
- package/.docs/raw/docs/guides/latex.mdx +0 -158
- package/.docs/raw/docs/guides/mentions.mdx +0 -575
- package/.docs/raw/docs/guides/message-timing.mdx +0 -215
- package/.docs/raw/docs/guides/quoting.mdx +0 -169
- package/.docs/raw/docs/guides/resumable-stream-deployment.mdx +0 -212
- package/.docs/raw/docs/guides/resumable-stream-stores.mdx +0 -152
- package/.docs/raw/docs/guides/resumable-streams.mdx +0 -292
- package/.docs/raw/docs/guides/slash-commands.mdx +0 -358
- package/.docs/raw/docs/guides/speech.mdx +0 -172
- package/.docs/raw/docs/guides/suggestions.mdx +0 -384
- package/.docs/raw/docs/guides/virtualization.mdx +0 -133
- package/.docs/raw/docs/guides/voice.mdx +0 -310
- package/.docs/raw/docs/ink/adapters.mdx +0 -99
- package/.docs/raw/docs/ink/custom-backend.mdx +0 -254
- package/.docs/raw/docs/ink/hooks.mdx +0 -469
- package/.docs/raw/docs/ink/index.mdx +0 -237
- package/.docs/raw/docs/ink/migration.mdx +0 -138
- package/.docs/raw/docs/ink/primitives.mdx +0 -1259
- package/.docs/raw/docs/integrations/attachments/custom-adapter.mdx +0 -528
- package/.docs/raw/docs/integrations/auth/better-auth.mdx +0 -188
- package/.docs/raw/docs/integrations/auth/clerk.mdx +0 -166
- package/.docs/raw/docs/integrations/auth/next-auth.mdx +0 -191
- package/.docs/raw/docs/integrations/frameworks/ai-sdk.mdx +0 -88
- package/.docs/raw/docs/integrations/frameworks/cloudflare-agents.mdx +0 -283
- package/.docs/raw/docs/integrations/frameworks/mastra/full-stack.mdx +0 -188
- package/.docs/raw/docs/integrations/frameworks/mastra/overview.mdx +0 -57
- package/.docs/raw/docs/integrations/frameworks/mastra/separate-server.mdx +0 -201
- package/.docs/raw/docs/integrations/gateways/index.mdx +0 -162
- package/.docs/raw/docs/integrations/index.mdx +0 -178
- package/.docs/raw/docs/integrations/observability/helicone.mdx +0 -129
- package/.docs/raw/docs/integrations/observability/langfuse.mdx +0 -161
- package/.docs/raw/docs/integrations/observability/langsmith.mdx +0 -151
- package/.docs/raw/docs/integrations/persistence/custom-adapter.mdx +0 -773
- package/.docs/raw/docs/migrations/deprecation-policy.mdx +0 -42
- package/.docs/raw/docs/migrations/index.mdx +0 -50
- package/.docs/raw/docs/migrations/react-compatibility.mdx +0 -74
- package/.docs/raw/docs/migrations/react-langgraph-v0-7.mdx +0 -328
- package/.docs/raw/docs/migrations/toolkit-tools.mdx +0 -236
- package/.docs/raw/docs/migrations/v0-11.mdx +0 -172
- package/.docs/raw/docs/migrations/v0-12.mdx +0 -302
- package/.docs/raw/docs/migrations/v0-14.mdx +0 -297
- package/.docs/raw/docs/migrations/v0-15.mdx +0 -270
- package/.docs/raw/docs/primitives/action-bar.mdx +0 -352
- package/.docs/raw/docs/primitives/assistant-modal.mdx +0 -216
- package/.docs/raw/docs/primitives/attachment.mdx +0 -217
- package/.docs/raw/docs/primitives/branch-picker.mdx +0 -222
- package/.docs/raw/docs/primitives/chain-of-thought.mdx +0 -315
- package/.docs/raw/docs/primitives/composer.mdx +0 -659
- package/.docs/raw/docs/primitives/error.mdx +0 -142
- package/.docs/raw/docs/primitives/index.mdx +0 -99
- package/.docs/raw/docs/primitives/message.mdx +0 -618
- package/.docs/raw/docs/primitives/selection-toolbar.mdx +0 -191
- package/.docs/raw/docs/primitives/suggestion.mdx +0 -254
- package/.docs/raw/docs/primitives/thread-list.mdx +0 -467
- package/.docs/raw/docs/primitives/thread.mdx +0 -509
- package/.docs/raw/docs/react-native/adapters.mdx +0 -94
- package/.docs/raw/docs/react-native/custom-backend.mdx +0 -207
- package/.docs/raw/docs/react-native/hooks.mdx +0 -339
- package/.docs/raw/docs/react-native/index.mdx +0 -289
- package/.docs/raw/docs/react-native/migration.mdx +0 -142
- package/.docs/raw/docs/react-native/primitives.mdx +0 -976
- package/.docs/raw/docs/runtimes/a2a/client-and-hooks.mdx +0 -399
- package/.docs/raw/docs/runtimes/a2a/overview.mdx +0 -60
- package/.docs/raw/docs/runtimes/a2a/quickstart.mdx +0 -216
- package/.docs/raw/docs/runtimes/ag-ui/agent-state.mdx +0 -124
- package/.docs/raw/docs/runtimes/ag-ui/overview.mdx +0 -70
- package/.docs/raw/docs/runtimes/ag-ui/quickstart.mdx +0 -243
- package/.docs/raw/docs/runtimes/ag-ui/runtime-options.mdx +0 -267
- package/.docs/raw/docs/runtimes/ai-sdk/overview.mdx +0 -61
- package/.docs/raw/docs/runtimes/ai-sdk/v4-legacy.mdx +0 -122
- package/.docs/raw/docs/runtimes/ai-sdk/v5-legacy.mdx +0 -135
- package/.docs/raw/docs/runtimes/ai-sdk/v6-legacy.mdx +0 -636
- package/.docs/raw/docs/runtimes/ai-sdk/v7.mdx +0 -731
- package/.docs/raw/docs/runtimes/claude-managed-agents.mdx +0 -118
- package/.docs/raw/docs/runtimes/concepts/adapters.mdx +0 -265
- package/.docs/raw/docs/runtimes/concepts/architecture.mdx +0 -167
- package/.docs/raw/docs/runtimes/concepts/stability.mdx +0 -68
- package/.docs/raw/docs/runtimes/concepts/threads.mdx +0 -513
- package/.docs/raw/docs/runtimes/custom/assistant-transport.mdx +0 -763
- package/.docs/raw/docs/runtimes/custom/data-stream.mdx +0 -339
- package/.docs/raw/docs/runtimes/custom/external-store.mdx +0 -957
- package/.docs/raw/docs/runtimes/custom/local-runtime.mdx +0 -902
- package/.docs/raw/docs/runtimes/custom/overview.mdx +0 -71
- package/.docs/raw/docs/runtimes/eve/overview.mdx +0 -151
- package/.docs/raw/docs/runtimes/eve/quickstart.mdx +0 -192
- package/.docs/raw/docs/runtimes/google-adk/api.mdx +0 -256
- package/.docs/raw/docs/runtimes/google-adk/hooks.mdx +0 -784
- package/.docs/raw/docs/runtimes/google-adk/overview.mdx +0 -69
- package/.docs/raw/docs/runtimes/google-adk/quickstart.mdx +0 -229
- package/.docs/raw/docs/runtimes/langchain.mdx +0 -901
- package/.docs/raw/docs/runtimes/langgraph/agent-state.mdx +0 -181
- package/.docs/raw/docs/runtimes/langgraph/generative-ui.mdx +0 -305
- package/.docs/raw/docs/runtimes/langgraph/interrupts.mdx +0 -104
- package/.docs/raw/docs/runtimes/langgraph/overview.mdx +0 -84
- package/.docs/raw/docs/runtimes/langgraph/quickstart.mdx +0 -496
- package/.docs/raw/docs/runtimes/langgraph/streaming.mdx +0 -144
- package/.docs/raw/docs/runtimes/langgraph/threads.mdx +0 -113
- package/.docs/raw/docs/runtimes/langgraph/tutorial/introduction.mdx +0 -29
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-1.mdx +0 -93
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-2.mdx +0 -347
- package/.docs/raw/docs/runtimes/langgraph/tutorial/part-3.mdx +0 -393
- package/.docs/raw/docs/runtimes/opencode/hooks.mdx +0 -194
- package/.docs/raw/docs/runtimes/opencode/overview.mdx +0 -58
- package/.docs/raw/docs/runtimes/opencode/quickstart.mdx +0 -119
- package/.docs/raw/docs/runtimes/pick-a-runtime.mdx +0 -133
- package/.docs/raw/docs/tools/a2ui.mdx +0 -107
- package/.docs/raw/docs/tools/backend.mdx +0 -147
- package/.docs/raw/docs/tools/defining-tools.mdx +0 -574
- package/.docs/raw/docs/tools/dynamic-tools.mdx +0 -112
- package/.docs/raw/docs/tools/generative-ui-primitive.mdx +0 -180
- package/.docs/raw/docs/tools/generative-ui-slack.mdx +0 -167
- package/.docs/raw/docs/tools/generative-ui-teams.mdx +0 -160
- package/.docs/raw/docs/tools/generative-ui.mdx +0 -322
- package/.docs/raw/docs/tools/index.mdx +0 -72
- package/.docs/raw/docs/tools/interactables.mdx +0 -1084
- package/.docs/raw/docs/tools/mcp-apps.mdx +0 -363
- package/.docs/raw/docs/tools/mcp.mdx +0 -466
- package/.docs/raw/docs/tools/multi-agent.mdx +0 -237
- package/.docs/raw/docs/tools/openui.mdx +0 -175
- package/.docs/raw/docs/tools/tool-ui.mdx +0 -1020
- package/.docs/raw/docs/tools/user-managed-mcp.mdx +0 -428
- package/.docs/raw/docs/ui/assistant-modal.mdx +0 -166
- package/.docs/raw/docs/ui/assistant-sidebar.mdx +0 -89
- package/.docs/raw/docs/ui/attachment.mdx +0 -279
- package/.docs/raw/docs/ui/composer-trigger-popover.mdx +0 -247
- package/.docs/raw/docs/ui/context-display.mdx +0 -148
- package/.docs/raw/docs/ui/directive-text.mdx +0 -114
- package/.docs/raw/docs/ui/file.mdx +0 -159
- package/.docs/raw/docs/ui/follow-up-suggestions.mdx +0 -82
- package/.docs/raw/docs/ui/image.mdx +0 -102
- package/.docs/raw/docs/ui/markdown.mdx +0 -103
- package/.docs/raw/docs/ui/mcp-config.mdx +0 -107
- package/.docs/raw/docs/ui/mermaid.mdx +0 -92
- package/.docs/raw/docs/ui/message-timing.mdx +0 -93
- package/.docs/raw/docs/ui/model-selector.mdx +0 -455
- package/.docs/raw/docs/ui/part-grouping.mdx +0 -614
- package/.docs/raw/docs/ui/quote.mdx +0 -211
- package/.docs/raw/docs/ui/reasoning.mdx +0 -214
- package/.docs/raw/docs/ui/scrollbar.mdx +0 -77
- package/.docs/raw/docs/ui/sources.mdx +0 -186
- package/.docs/raw/docs/ui/streamdown.mdx +0 -392
- package/.docs/raw/docs/ui/syntax-highlighting.mdx +0 -205
- package/.docs/raw/docs/ui/thread-list.mdx +0 -411
- package/.docs/raw/docs/ui/thread.mdx +0 -559
- package/.docs/raw/docs/ui/tool-fallback.mdx +0 -141
- package/.docs/raw/docs/ui/tool-group.mdx +0 -240
- package/.docs/raw/docs/ui/voice.mdx +0 -173
- package/.docs/raw/docs/utilities/heat-graph.mdx +0 -237
- package/.docs/raw/docs/utilities/react-o11y.mdx +0 -362
- package/.docs/raw/docs/utilities/tw-shimmer.mdx +0 -212
- package/dist/constants.d.ts +0 -14
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -19
- package/dist/constants.js.map +0 -1
- package/dist/prepare-docs/code-examples.d.ts +0 -5
- package/dist/prepare-docs/code-examples.d.ts.map +0 -1
- package/dist/prepare-docs/code-examples.js +0 -117
- package/dist/prepare-docs/code-examples.js.map +0 -1
- package/dist/prepare-docs/copy-raw.d.ts +0 -5
- package/dist/prepare-docs/copy-raw.d.ts.map +0 -1
- package/dist/prepare-docs/copy-raw.js +0 -49
- package/dist/prepare-docs/copy-raw.js.map +0 -1
- package/dist/prepare-docs/prepare.d.ts +0 -1
- package/dist/prepare-docs/prepare.js +0 -22
- package/dist/prepare-docs/prepare.js.map +0 -1
- package/dist/prompts/xulux-playground.d.ts +0 -12
- package/dist/prompts/xulux-playground.d.ts.map +0 -1
- package/dist/prompts/xulux-playground.js +0 -33
- package/dist/prompts/xulux-playground.js.map +0 -1
- package/dist/tools/docs.d.ts +0 -22
- package/dist/tools/docs.d.ts.map +0 -1
- package/dist/tools/docs.js +0 -177
- package/dist/tools/docs.js.map +0 -1
- package/dist/tools/examples.d.ts +0 -24
- package/dist/tools/examples.d.ts.map +0 -1
- package/dist/tools/examples.js +0 -87
- package/dist/tools/examples.js.map +0 -1
- package/dist/tools/resources.d.ts +0 -6
- package/dist/tools/resources.d.ts.map +0 -1
- package/dist/tools/resources.js +0 -75
- package/dist/tools/resources.js.map +0 -1
- package/dist/tools/search.d.ts +0 -24
- package/dist/tools/search.d.ts.map +0 -1
- package/dist/tools/search.js +0 -39
- package/dist/tools/search.js.map +0 -1
- package/dist/tools/tests/mcp-test-client.d.ts +0 -15
- package/dist/tools/tests/mcp-test-client.d.ts.map +0 -1
- package/dist/tools/tests/mcp-test-client.js +0 -68
- package/dist/tools/tests/mcp-test-client.js.map +0 -1
- package/dist/tools/tests/test-setup.d.ts +0 -7
- package/dist/tools/tests/test-setup.d.ts.map +0 -1
- package/dist/tools/tests/test-setup.js +0 -36
- package/dist/tools/tests/test-setup.js.map +0 -1
- package/dist/tools/xulux-templates.d.ts +0 -58
- package/dist/tools/xulux-templates.d.ts.map +0 -1
- package/dist/tools/xulux-templates.js +0 -84
- package/dist/tools/xulux-templates.js.map +0 -1
- package/dist/utils/cache.d.ts +0 -5
- package/dist/utils/cache.d.ts.map +0 -1
- package/dist/utils/cache.js +0 -18
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -10
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -20
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/mcp-format.d.ts +0 -11
- package/dist/utils/mcp-format.d.ts.map +0 -1
- package/dist/utils/mcp-format.js +0 -14
- package/dist/utils/mcp-format.js.map +0 -1
- package/dist/utils/mdx.d.ts +0 -12
- package/dist/utils/mdx.d.ts.map +0 -1
- package/dist/utils/mdx.js +0 -45
- package/dist/utils/mdx.js.map +0 -1
- package/dist/utils/paths.d.ts +0 -12
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js +0 -93
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/search.d.ts +0 -10
- package/dist/utils/search.d.ts.map +0 -1
- package/dist/utils/search.js +0 -97
- package/dist/utils/search.js.map +0 -1
- package/dist/utils/security.d.ts +0 -5
- package/dist/utils/security.d.ts.map +0 -1
- package/dist/utils/security.js +0 -22
- package/dist/utils/security.js.map +0 -1
- package/dist/xulux/catalog-client.d.ts +0 -14
- package/dist/xulux/catalog-client.d.ts.map +0 -1
- package/dist/xulux/catalog-client.js +0 -112
- package/dist/xulux/catalog-client.js.map +0 -1
- package/dist/xulux/fallback-catalog.d.ts +0 -7
- package/dist/xulux/fallback-catalog.d.ts.map +0 -1
- package/dist/xulux/fallback-catalog.js +0 -47
- package/dist/xulux/fallback-catalog.js.map +0 -1
- package/dist/xulux/fetch-sandbox.d.ts +0 -5
- package/dist/xulux/fetch-sandbox.d.ts.map +0 -1
- package/dist/xulux/fetch-sandbox.js +0 -40
- package/dist/xulux/fetch-sandbox.js.map +0 -1
- package/dist/xulux/template-service.d.ts +0 -84
- package/dist/xulux/template-service.d.ts.map +0 -1
- package/dist/xulux/template-service.js +0 -223
- package/dist/xulux/template-service.js.map +0 -1
- package/dist/xulux/types.d.ts +0 -55
- package/dist/xulux/types.d.ts.map +0 -1
- package/dist/xulux/types.js +0 -6
- package/dist/xulux/types.js.map +0 -1
- package/src/constants.ts +0 -24
- package/src/prepare-docs/code-examples.ts +0 -158
- package/src/prepare-docs/copy-raw.ts +0 -50
- package/src/prepare-docs/prepare.ts +0 -24
- package/src/prompts/xulux-playground.ts +0 -36
- package/src/tools/docs.ts +0 -255
- package/src/tools/examples.ts +0 -114
- package/src/tools/resources.ts +0 -111
- package/src/tools/search.ts +0 -46
- package/src/tools/tests/completions.test.ts +0 -60
- package/src/tools/tests/directory-size-cap.test.ts +0 -50
- package/src/tools/tests/docs.test.ts +0 -147
- package/src/tools/tests/examples.test.ts +0 -94
- package/src/tools/tests/integration.test.ts +0 -45
- package/src/tools/tests/json-parsing.test.ts +0 -23
- package/src/tools/tests/listings-cache.test.ts +0 -19
- package/src/tools/tests/mcp-protocol.test.ts +0 -216
- package/src/tools/tests/mcp-test-client.ts +0 -111
- package/src/tools/tests/path-traversal.test.ts +0 -84
- package/src/tools/tests/resources.test.ts +0 -133
- package/src/tools/tests/search.test.ts +0 -37
- package/src/tools/tests/test-setup.ts +0 -50
- package/src/tools/tests/xulux-templates.test.ts +0 -325
- package/src/tools/xulux-templates.ts +0 -141
- package/src/utils/cache.ts +0 -20
- package/src/utils/logger.ts +0 -20
- package/src/utils/mcp-format.ts +0 -14
- package/src/utils/mdx.ts +0 -59
- package/src/utils/paths.ts +0 -139
- package/src/utils/search.ts +0 -131
- package/src/utils/security.ts +0 -52
- package/src/utils/tests/cache.test.ts +0 -51
- package/src/utils/tests/mcp-format.test.ts +0 -22
- package/src/utils/tests/security.test.ts +0 -119
- package/src/xulux/catalog-client.ts +0 -150
- package/src/xulux/fallback-catalog.ts +0 -63
- package/src/xulux/fetch-sandbox.ts +0 -56
- package/src/xulux/template-service.ts +0 -406
- package/src/xulux/types.ts +0 -64
|
@@ -1,1810 +0,0 @@
|
|
|
1
|
-
# Example: with-generative-ui
|
|
2
|
-
|
|
3
|
-
## app/api/chat/route.ts
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
import { openai } from "@ai-sdk/openai";
|
|
7
|
-
import {
|
|
8
|
-
streamText,
|
|
9
|
-
convertToModelMessages,
|
|
10
|
-
stepCountIs,
|
|
11
|
-
tool,
|
|
12
|
-
zodSchema,
|
|
13
|
-
} from "ai";
|
|
14
|
-
import type { UIMessage } from "ai";
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
import {
|
|
17
|
-
AISDKToolkit,
|
|
18
|
-
type AISDKToolkitToolsOptions,
|
|
19
|
-
} from "@assistant-ui/ai-sdk";
|
|
20
|
-
import {
|
|
21
|
-
renderGuiToolDescription,
|
|
22
|
-
renderGuiToolInputSchema,
|
|
23
|
-
} from "../../../lib/render-gui-tool";
|
|
24
|
-
import toolkit from "../../toolkit";
|
|
25
|
-
|
|
26
|
-
export const maxDuration = 30;
|
|
27
|
-
|
|
28
|
-
const aiToolkit = new AISDKToolkit({ toolkit });
|
|
29
|
-
|
|
30
|
-
type FrontendToolDefs = NonNullable<AISDKToolkitToolsOptions["frontend"]>;
|
|
31
|
-
|
|
32
|
-
export async function POST(req: Request) {
|
|
33
|
-
const {
|
|
34
|
-
messages,
|
|
35
|
-
system,
|
|
36
|
-
tools: clientTools,
|
|
37
|
-
}: {
|
|
38
|
-
messages: UIMessage[];
|
|
39
|
-
system?: string;
|
|
40
|
-
tools?: FrontendToolDefs;
|
|
41
|
-
} = await req.json();
|
|
42
|
-
|
|
43
|
-
const toolkitTools = await aiToolkit.tools({
|
|
44
|
-
...(clientTools && { frontend: clientTools }),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const result = streamText({
|
|
48
|
-
model: openai("gpt-5.6-luna"),
|
|
49
|
-
messages: await convertToModelMessages(messages),
|
|
50
|
-
stopWhen: stepCountIs(10),
|
|
51
|
-
...(system ? { system } : {}),
|
|
52
|
-
tools: {
|
|
53
|
-
...toolkitTools,
|
|
54
|
-
|
|
55
|
-
render_gui: tool({
|
|
56
|
-
description: renderGuiToolDescription,
|
|
57
|
-
inputSchema: zodSchema(renderGuiToolInputSchema),
|
|
58
|
-
execute: async (input) => ({
|
|
59
|
-
spec: input.spec,
|
|
60
|
-
}),
|
|
61
|
-
}),
|
|
62
|
-
|
|
63
|
-
// Backend tool: generate chart data
|
|
64
|
-
generate_chart: tool({
|
|
65
|
-
description:
|
|
66
|
-
"Generate a chart. Return structured data for rendering a bar, line, or pie chart. Use this when the user asks for data visualization, charts, graphs, or comparisons.",
|
|
67
|
-
inputSchema: zodSchema(
|
|
68
|
-
z.object({
|
|
69
|
-
title: z.string().describe("Chart title"),
|
|
70
|
-
type: z
|
|
71
|
-
.enum(["bar", "line", "pie"])
|
|
72
|
-
.describe("Chart type to render"),
|
|
73
|
-
data: z
|
|
74
|
-
.array(z.record(z.string(), z.union([z.string(), z.number()])))
|
|
75
|
-
.describe(
|
|
76
|
-
"Array of data objects, e.g. [{month: 'Jan', revenue: 100}]",
|
|
77
|
-
),
|
|
78
|
-
xKey: z
|
|
79
|
-
.string()
|
|
80
|
-
.describe("Key in each data object to use for the x-axis/labels"),
|
|
81
|
-
dataKeys: z
|
|
82
|
-
.array(z.string())
|
|
83
|
-
.describe("Keys in each data object to chart as series/values"),
|
|
84
|
-
}),
|
|
85
|
-
),
|
|
86
|
-
execute: async () => {
|
|
87
|
-
return { success: true };
|
|
88
|
-
},
|
|
89
|
-
}),
|
|
90
|
-
|
|
91
|
-
// Backend tool: show location on map
|
|
92
|
-
show_location: tool({
|
|
93
|
-
description:
|
|
94
|
-
"Show a location on a map. Use this when the user asks about a place, wants to see directions, or needs to see a location.",
|
|
95
|
-
inputSchema: zodSchema(
|
|
96
|
-
z.object({
|
|
97
|
-
name: z.string().describe("Name of the place"),
|
|
98
|
-
address: z.string().optional().describe("Street address"),
|
|
99
|
-
lat: z.number().describe("Latitude"),
|
|
100
|
-
lng: z.number().describe("Longitude"),
|
|
101
|
-
}),
|
|
102
|
-
),
|
|
103
|
-
execute: async () => {
|
|
104
|
-
return { success: true };
|
|
105
|
-
},
|
|
106
|
-
}),
|
|
107
|
-
},
|
|
108
|
-
} as Parameters<typeof streamText>[0]);
|
|
109
|
-
|
|
110
|
-
return result.toUIMessageStreamResponse();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## app/api/present/route.ts
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { openai } from "@ai-sdk/openai";
|
|
119
|
-
import { streamText, convertToModelMessages, stepCountIs } from "ai";
|
|
120
|
-
import type { UIMessage } from "ai";
|
|
121
|
-
import {
|
|
122
|
-
AISDKToolkit,
|
|
123
|
-
type AISDKToolkitToolsOptions,
|
|
124
|
-
} from "@assistant-ui/ai-sdk";
|
|
125
|
-
import presentToolkit from "../../present-toolkit";
|
|
126
|
-
|
|
127
|
-
export const maxDuration = 30;
|
|
128
|
-
|
|
129
|
-
const aiToolkit = new AISDKToolkit({ toolkit: presentToolkit });
|
|
130
|
-
|
|
131
|
-
type FrontendToolDefs = NonNullable<AISDKToolkitToolsOptions["frontend"]>;
|
|
132
|
-
|
|
133
|
-
export async function POST(req: Request) {
|
|
134
|
-
const {
|
|
135
|
-
messages,
|
|
136
|
-
system,
|
|
137
|
-
tools: clientTools,
|
|
138
|
-
}: {
|
|
139
|
-
messages: UIMessage[];
|
|
140
|
-
system?: string;
|
|
141
|
-
tools?: FrontendToolDefs;
|
|
142
|
-
} = await req.json();
|
|
143
|
-
|
|
144
|
-
const result = streamText({
|
|
145
|
-
model: openai("gpt-5.6-luna"),
|
|
146
|
-
messages: await convertToModelMessages(messages),
|
|
147
|
-
stopWhen: stepCountIs(10),
|
|
148
|
-
...(system ? { system } : {}),
|
|
149
|
-
tools: await aiToolkit.tools({
|
|
150
|
-
...(clientTools && { frontend: clientTools }),
|
|
151
|
-
}),
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return result.toUIMessageStreamResponse();
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## app/globals.css
|
|
160
|
-
|
|
161
|
-
```css
|
|
162
|
-
@import "tailwindcss";
|
|
163
|
-
@import "tw-animate-css";
|
|
164
|
-
|
|
165
|
-
@source "../../../packages/ui/src";
|
|
166
|
-
|
|
167
|
-
@custom-variant dark (&:is(.dark *));
|
|
168
|
-
|
|
169
|
-
@theme inline {
|
|
170
|
-
--radius-sm: calc(var(--radius) - 4px);
|
|
171
|
-
--radius-md: calc(var(--radius) - 2px);
|
|
172
|
-
--radius-lg: var(--radius);
|
|
173
|
-
--radius-xl: calc(var(--radius) + 4px);
|
|
174
|
-
--color-background: var(--background);
|
|
175
|
-
--color-foreground: var(--foreground);
|
|
176
|
-
--color-card: var(--card);
|
|
177
|
-
--color-card-foreground: var(--card-foreground);
|
|
178
|
-
--color-popover: var(--popover);
|
|
179
|
-
--color-popover-foreground: var(--popover-foreground);
|
|
180
|
-
--color-primary: var(--primary);
|
|
181
|
-
--color-primary-foreground: var(--primary-foreground);
|
|
182
|
-
--color-secondary: var(--secondary);
|
|
183
|
-
--color-secondary-foreground: var(--secondary-foreground);
|
|
184
|
-
--color-muted: var(--muted);
|
|
185
|
-
--color-muted-foreground: var(--muted-foreground);
|
|
186
|
-
--color-accent: var(--accent);
|
|
187
|
-
--color-accent-foreground: var(--accent-foreground);
|
|
188
|
-
--color-destructive: var(--destructive);
|
|
189
|
-
--color-border: var(--border);
|
|
190
|
-
--color-input: var(--input);
|
|
191
|
-
--color-ring: var(--ring);
|
|
192
|
-
--color-chart-1: var(--chart-1);
|
|
193
|
-
--color-chart-2: var(--chart-2);
|
|
194
|
-
--color-chart-3: var(--chart-3);
|
|
195
|
-
--color-chart-4: var(--chart-4);
|
|
196
|
-
--color-chart-5: var(--chart-5);
|
|
197
|
-
--color-sidebar: var(--sidebar);
|
|
198
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
199
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
200
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
201
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
202
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
203
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
204
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
:root {
|
|
208
|
-
--radius: 0.625rem;
|
|
209
|
-
--background: oklch(1 0 0);
|
|
210
|
-
--foreground: oklch(0.141 0.005 285.823);
|
|
211
|
-
--card: oklch(1 0 0);
|
|
212
|
-
--card-foreground: oklch(0.141 0.005 285.823);
|
|
213
|
-
--popover: oklch(1 0 0);
|
|
214
|
-
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
215
|
-
--primary: oklch(0.21 0.006 285.885);
|
|
216
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
217
|
-
--secondary: oklch(0.967 0.001 286.375);
|
|
218
|
-
--secondary-foreground: oklch(0.21 0.006 285.885);
|
|
219
|
-
--muted: oklch(0.967 0.001 286.375);
|
|
220
|
-
--muted-foreground: oklch(0.552 0.016 285.938);
|
|
221
|
-
--accent: oklch(0.967 0.001 286.375);
|
|
222
|
-
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
223
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
224
|
-
--border: oklch(0.92 0.004 286.32);
|
|
225
|
-
--input: oklch(0.92 0.004 286.32);
|
|
226
|
-
--ring: oklch(0.705 0.015 286.067);
|
|
227
|
-
--chart-1: oklch(0.646 0.222 41.116);
|
|
228
|
-
--chart-2: oklch(0.6 0.118 184.704);
|
|
229
|
-
--chart-3: oklch(0.398 0.07 227.392);
|
|
230
|
-
--chart-4: oklch(0.828 0.189 84.429);
|
|
231
|
-
--chart-5: oklch(0.769 0.188 70.08);
|
|
232
|
-
--sidebar: oklch(0.985 0 0);
|
|
233
|
-
--sidebar-foreground: oklch(0.141 0.005 285.823);
|
|
234
|
-
--sidebar-primary: oklch(0.21 0.006 285.885);
|
|
235
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
236
|
-
--sidebar-accent: oklch(0.967 0.001 286.375);
|
|
237
|
-
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
|
|
238
|
-
--sidebar-border: oklch(0.92 0.004 286.32);
|
|
239
|
-
--sidebar-ring: oklch(0.705 0.015 286.067);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.dark {
|
|
243
|
-
--background: oklch(0.141 0.005 285.823);
|
|
244
|
-
--foreground: oklch(0.985 0 0);
|
|
245
|
-
--card: oklch(0.21 0.006 285.885);
|
|
246
|
-
--card-foreground: oklch(0.985 0 0);
|
|
247
|
-
--popover: oklch(0.21 0.006 285.885);
|
|
248
|
-
--popover-foreground: oklch(0.985 0 0);
|
|
249
|
-
--primary: oklch(0.92 0.004 286.32);
|
|
250
|
-
--primary-foreground: oklch(0.21 0.006 285.885);
|
|
251
|
-
--secondary: oklch(0.274 0.006 286.033);
|
|
252
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
253
|
-
--muted: oklch(0.274 0.006 286.033);
|
|
254
|
-
--muted-foreground: oklch(0.705 0.015 286.067);
|
|
255
|
-
--accent: oklch(0.274 0.006 286.033);
|
|
256
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
257
|
-
--destructive: oklch(0.704 0.191 22.216);
|
|
258
|
-
--border: oklch(1 0 0 / 10%);
|
|
259
|
-
--input: oklch(1 0 0 / 15%);
|
|
260
|
-
--ring: oklch(0.552 0.016 285.938);
|
|
261
|
-
--chart-1: oklch(0.488 0.243 264.376);
|
|
262
|
-
--chart-2: oklch(0.696 0.17 162.48);
|
|
263
|
-
--chart-3: oklch(0.769 0.188 70.08);
|
|
264
|
-
--chart-4: oklch(0.627 0.265 303.9);
|
|
265
|
-
--chart-5: oklch(0.645 0.246 16.439);
|
|
266
|
-
--sidebar: oklch(0.21 0.006 285.885);
|
|
267
|
-
--sidebar-foreground: oklch(0.985 0 0);
|
|
268
|
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
269
|
-
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
270
|
-
--sidebar-accent: oklch(0.274 0.006 286.033);
|
|
271
|
-
--sidebar-accent-foreground: oklch(0.985 0 0);
|
|
272
|
-
--sidebar-border: oklch(1 0 0 / 10%);
|
|
273
|
-
--sidebar-ring: oklch(0.552 0.016 285.938);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
@layer base {
|
|
277
|
-
* {
|
|
278
|
-
@apply border-border outline-ring/50;
|
|
279
|
-
}
|
|
280
|
-
body {
|
|
281
|
-
@apply bg-background text-foreground;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
## app/gui-chat/page.tsx
|
|
288
|
-
|
|
289
|
-
```tsx
|
|
290
|
-
"use client";
|
|
291
|
-
|
|
292
|
-
import { ExampleNav } from "@/components/example-nav";
|
|
293
|
-
import { AssistantMessageGui } from "@/components/assistant-message-gui";
|
|
294
|
-
import {
|
|
295
|
-
Thread,
|
|
296
|
-
type ThreadComponents,
|
|
297
|
-
} from "@/components/assistant-ui/thread";
|
|
298
|
-
import {
|
|
299
|
-
AssistantRuntimeProvider,
|
|
300
|
-
AuiConfig,
|
|
301
|
-
Suggestions,
|
|
302
|
-
useAssistantInstructions,
|
|
303
|
-
} from "@assistant-ui/react";
|
|
304
|
-
import { useChatRuntime } from "@assistant-ui/ai-sdk";
|
|
305
|
-
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
306
|
-
import { renderGuiChatInstructions } from "@/lib/render-gui-tool";
|
|
307
|
-
|
|
308
|
-
const GuiChatInstructions = () => {
|
|
309
|
-
useAssistantInstructions(renderGuiChatInstructions);
|
|
310
|
-
return null;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
const GuiWelcome = () => {
|
|
314
|
-
return (
|
|
315
|
-
<div className="aui-thread-welcome-root mb-6 flex flex-col items-center gap-1 px-4 text-center">
|
|
316
|
-
<h1 className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-semibold duration-200">
|
|
317
|
-
Compose UI from a spec
|
|
318
|
-
</h1>
|
|
319
|
-
<p className="aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-muted-foreground text-xl delay-75 duration-200">
|
|
320
|
-
Ask the agent to call render_gui with Card, Button, and Stack.
|
|
321
|
-
</p>
|
|
322
|
-
</div>
|
|
323
|
-
);
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const THREAD_COMPONENTS: ThreadComponents = {
|
|
327
|
-
AssistantMessage: AssistantMessageGui,
|
|
328
|
-
Welcome: GuiWelcome,
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
export default function GuiChatPage() {
|
|
332
|
-
const runtime = useChatRuntime({
|
|
333
|
-
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
const config = AuiConfig({
|
|
337
|
-
suggestions: Suggestions([
|
|
338
|
-
{
|
|
339
|
-
title: "Welcome card",
|
|
340
|
-
label: "with a Get started button",
|
|
341
|
-
prompt:
|
|
342
|
-
"Show me a welcome card with a Get started button using render_gui.",
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
title: "Stats dashboard",
|
|
346
|
-
label: "revenue and users",
|
|
347
|
-
prompt:
|
|
348
|
-
"Use render_gui to show a stats card with Revenue $124k and Active Users 8.2k.",
|
|
349
|
-
},
|
|
350
|
-
]),
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
return (
|
|
354
|
-
<AssistantRuntimeProvider config={config} runtime={runtime}>
|
|
355
|
-
<GuiChatInstructions />
|
|
356
|
-
<div className="flex h-full flex-col">
|
|
357
|
-
<ExampleNav />
|
|
358
|
-
<main className="min-h-0 flex-1">
|
|
359
|
-
<Thread components={THREAD_COMPONENTS} />
|
|
360
|
-
</main>
|
|
361
|
-
</div>
|
|
362
|
-
</AssistantRuntimeProvider>
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
## app/layout.tsx
|
|
369
|
-
|
|
370
|
-
```tsx
|
|
371
|
-
import type { Metadata } from "next";
|
|
372
|
-
import { GenerativeUIStyle } from "@/components/generative-ui-style";
|
|
373
|
-
import "./globals.css";
|
|
374
|
-
|
|
375
|
-
export const metadata: Metadata = {
|
|
376
|
-
title: "assistant-ui Generative UI Example",
|
|
377
|
-
description:
|
|
378
|
-
"Example showcasing model-composed interfaces with the present tool and a custom component vocabulary",
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
export default function RootLayout({
|
|
382
|
-
children,
|
|
383
|
-
}: Readonly<{
|
|
384
|
-
children: React.ReactNode;
|
|
385
|
-
}>) {
|
|
386
|
-
return (
|
|
387
|
-
<html lang="en">
|
|
388
|
-
<head>
|
|
389
|
-
<GenerativeUIStyle />
|
|
390
|
-
</head>
|
|
391
|
-
<body className="h-dvh">{children}</body>
|
|
392
|
-
</html>
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
## app/page.tsx
|
|
399
|
-
|
|
400
|
-
```tsx
|
|
401
|
-
"use client";
|
|
402
|
-
|
|
403
|
-
import { Thread } from "@/components/assistant-ui/thread";
|
|
404
|
-
import {
|
|
405
|
-
AssistantRuntimeProvider,
|
|
406
|
-
AuiConfig,
|
|
407
|
-
Suggestions,
|
|
408
|
-
Tools,
|
|
409
|
-
} from "@assistant-ui/react";
|
|
410
|
-
import { AssistantChatTransport, useChatRuntime } from "@assistant-ui/ai-sdk";
|
|
411
|
-
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
412
|
-
import { ExampleNav } from "@/components/example-nav";
|
|
413
|
-
import toolkit from "./present-toolkit";
|
|
414
|
-
|
|
415
|
-
export default function Home() {
|
|
416
|
-
const runtime = useChatRuntime({
|
|
417
|
-
transport: new AssistantChatTransport({ api: "/api/present" }),
|
|
418
|
-
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
const config = AuiConfig({
|
|
422
|
-
tools: Tools({ toolkit }),
|
|
423
|
-
suggestions: Suggestions([
|
|
424
|
-
{
|
|
425
|
-
title: "Sales dashboard",
|
|
426
|
-
label: "for last quarter",
|
|
427
|
-
prompt:
|
|
428
|
-
"Show me a Q2 2026 sales dashboard. Revenue was $412k in April, $488k in May and $551k in June, on 1,284 orders, at a 3.4% conversion rate.",
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
title: "Product analytics",
|
|
432
|
-
label: "activation and retention",
|
|
433
|
-
prompt:
|
|
434
|
-
"How did we trend over the last six weeks? Activation went 41%, 44%, 43%, 48%, 52%, 55%, and week-4 retention went 22%, 24%, 23%, 27%, 29%, 31%.",
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
title: "Support overview",
|
|
438
|
-
label: "tickets and response time",
|
|
439
|
-
prompt:
|
|
440
|
-
"Give me a support overview. Open tickets: 12 urgent, 38 high, 91 normal, 24 low. Median first response is 47 minutes, down from 62 last week.",
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
title: "Channel performance",
|
|
444
|
-
label: "compare acquisition sources",
|
|
445
|
-
prompt:
|
|
446
|
-
"Compare our acquisition channels. Search: $18k spend, 420 conversions. Social: $11k, 260. Email: $3k, 190. Referral: $6k, 150.",
|
|
447
|
-
},
|
|
448
|
-
]),
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
return (
|
|
452
|
-
<AssistantRuntimeProvider config={config} runtime={runtime}>
|
|
453
|
-
<div className="flex h-full flex-col">
|
|
454
|
-
<ExampleNav />
|
|
455
|
-
<main className="min-h-0 flex-1">
|
|
456
|
-
<Thread />
|
|
457
|
-
</main>
|
|
458
|
-
</div>
|
|
459
|
-
</AssistantRuntimeProvider>
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
## app/present-toolkit.tsx
|
|
466
|
-
|
|
467
|
-
```tsx
|
|
468
|
-
"use generative";
|
|
469
|
-
|
|
470
|
-
import { defineToolkit } from "@assistant-ui/react";
|
|
471
|
-
import {
|
|
472
|
-
JSONGenerativeUI,
|
|
473
|
-
defaultGenerativeUILibrary,
|
|
474
|
-
defineGenerativeComponents,
|
|
475
|
-
} from "@assistant-ui/react-generative-ui";
|
|
476
|
-
import { styledGenerativeUILibrary } from "@/components/assistant-ui/generative-ui";
|
|
477
|
-
import { DashboardHeader } from "@/components/dashboard-header";
|
|
478
|
-
import { z } from "zod";
|
|
479
|
-
|
|
480
|
-
const markdown = defaultGenerativeUILibrary.Markdown!;
|
|
481
|
-
|
|
482
|
-
const generative = new JSONGenerativeUI({
|
|
483
|
-
library: {
|
|
484
|
-
...defaultGenerativeUILibrary,
|
|
485
|
-
...defineGenerativeComponents({
|
|
486
|
-
Markdown: {
|
|
487
|
-
properties: markdown.properties,
|
|
488
|
-
streamProperties: markdown.streamProperties,
|
|
489
|
-
description:
|
|
490
|
-
"A markdown string, rendered with GitHub-flavored markdown.",
|
|
491
|
-
render: styledGenerativeUILibrary.Markdown!.render,
|
|
492
|
-
},
|
|
493
|
-
DashboardHeader: {
|
|
494
|
-
description:
|
|
495
|
-
"A heading for a dashboard, with an optional description and reporting period.",
|
|
496
|
-
properties: z.object({
|
|
497
|
-
title: z.string().describe("The dashboard title."),
|
|
498
|
-
description: z
|
|
499
|
-
.string()
|
|
500
|
-
.optional()
|
|
501
|
-
.describe("A short description of the dashboard."),
|
|
502
|
-
period: z
|
|
503
|
-
.string()
|
|
504
|
-
.optional()
|
|
505
|
-
.describe("The reporting period shown beside the title."),
|
|
506
|
-
}),
|
|
507
|
-
render: (props) => <DashboardHeader {...props} />,
|
|
508
|
-
},
|
|
509
|
-
}),
|
|
510
|
-
},
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
export default defineToolkit({
|
|
514
|
-
present: generative.present({ display: "standalone" }),
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
## app/primitive/page.tsx
|
|
520
|
-
|
|
521
|
-
```tsx
|
|
522
|
-
"use client";
|
|
523
|
-
|
|
524
|
-
import { GenerativeUIRender, type GenerativeUISpec } from "@assistant-ui/react";
|
|
525
|
-
import {
|
|
526
|
-
UnknownComponentFallback,
|
|
527
|
-
componentsAllowlist,
|
|
528
|
-
} from "@/components/gui";
|
|
529
|
-
import { ExampleNav } from "@/components/example-nav";
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Self-contained demo of the GenerativeUI primitive.
|
|
533
|
-
*
|
|
534
|
-
* Renders a hand-written `GenerativeUISpec` directly via `GenerativeUIRender`,
|
|
535
|
-
* the same renderer that backs `MessagePrimitive.GenerativeUI` when a
|
|
536
|
-
* `generative-ui` part flows through `MessagePrimitive.Parts`.
|
|
537
|
-
*
|
|
538
|
-
* In a real integration the spec arrives as a `generative-ui` message part
|
|
539
|
-
* from the agent; the consumer-provided allowlist is the security boundary.
|
|
540
|
-
*/
|
|
541
|
-
const exampleSpec: GenerativeUISpec = {
|
|
542
|
-
root: [
|
|
543
|
-
{
|
|
544
|
-
component: "Card",
|
|
545
|
-
props: {
|
|
546
|
-
title: "Welcome",
|
|
547
|
-
description: "An agent-described card with a primary CTA.",
|
|
548
|
-
},
|
|
549
|
-
children: [
|
|
550
|
-
{
|
|
551
|
-
component: "Stack",
|
|
552
|
-
props: { gap: "sm" },
|
|
553
|
-
children: [
|
|
554
|
-
{
|
|
555
|
-
component: "Text",
|
|
556
|
-
children: [
|
|
557
|
-
"This card was rendered from a JSON spec emitted by the agent.",
|
|
558
|
-
],
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
component: "Button",
|
|
562
|
-
props: {
|
|
563
|
-
label: "Get started",
|
|
564
|
-
variant: "primary",
|
|
565
|
-
onClickPrompt: "open onboarding",
|
|
566
|
-
},
|
|
567
|
-
},
|
|
568
|
-
],
|
|
569
|
-
},
|
|
570
|
-
],
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
component: "Card",
|
|
574
|
-
props: { title: "Stats" },
|
|
575
|
-
children: [
|
|
576
|
-
{
|
|
577
|
-
component: "Stack",
|
|
578
|
-
props: { direction: "row", gap: "md" },
|
|
579
|
-
children: [
|
|
580
|
-
{ component: "Stat", props: { label: "Revenue", value: "$124k" } },
|
|
581
|
-
{
|
|
582
|
-
component: "Stat",
|
|
583
|
-
props: { label: "Active Users", value: "8.2k" },
|
|
584
|
-
},
|
|
585
|
-
{ component: "Stat", props: { label: "Latency", value: "42ms" } },
|
|
586
|
-
],
|
|
587
|
-
},
|
|
588
|
-
],
|
|
589
|
-
},
|
|
590
|
-
],
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
export default function GenerativeUIPrimitivePage() {
|
|
594
|
-
return (
|
|
595
|
-
<div className="flex h-full flex-col">
|
|
596
|
-
<ExampleNav />
|
|
597
|
-
<main className="mx-auto flex h-full max-w-2xl flex-col gap-6 overflow-y-auto p-8">
|
|
598
|
-
<header>
|
|
599
|
-
<h1 className="text-2xl font-bold">MessagePrimitive.GenerativeUI</h1>
|
|
600
|
-
<p className="text-muted-foreground mt-1 text-sm">
|
|
601
|
-
Agent-described React UI rendered from a JSON spec via a
|
|
602
|
-
consumer-provided component allowlist.
|
|
603
|
-
</p>
|
|
604
|
-
</header>
|
|
605
|
-
|
|
606
|
-
<section className="flex flex-col gap-4">
|
|
607
|
-
<GenerativeUIRender
|
|
608
|
-
spec={exampleSpec}
|
|
609
|
-
components={componentsAllowlist}
|
|
610
|
-
Fallback={UnknownComponentFallback}
|
|
611
|
-
/>
|
|
612
|
-
</section>
|
|
613
|
-
</main>
|
|
614
|
-
</div>
|
|
615
|
-
);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
## app/tool-ui/page.tsx
|
|
621
|
-
|
|
622
|
-
```tsx
|
|
623
|
-
"use client";
|
|
624
|
-
|
|
625
|
-
import { Thread } from "@/components/assistant-ui/thread";
|
|
626
|
-
import {
|
|
627
|
-
AssistantRuntimeProvider,
|
|
628
|
-
AuiConfig,
|
|
629
|
-
Suggestions,
|
|
630
|
-
Tools,
|
|
631
|
-
} from "@assistant-ui/react";
|
|
632
|
-
import { useChatRuntime } from "@assistant-ui/ai-sdk";
|
|
633
|
-
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
634
|
-
import { ExampleNav } from "@/components/example-nav";
|
|
635
|
-
import toolkit from "../toolkit";
|
|
636
|
-
|
|
637
|
-
export default function Home() {
|
|
638
|
-
const runtime = useChatRuntime({
|
|
639
|
-
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
const config = AuiConfig({
|
|
643
|
-
tools: Tools({ toolkit }),
|
|
644
|
-
suggestions: Suggestions([
|
|
645
|
-
{
|
|
646
|
-
title: "Show a bar chart",
|
|
647
|
-
label: "of quarterly revenue",
|
|
648
|
-
prompt:
|
|
649
|
-
"Create a bar chart showing quarterly revenue: Q1 $45k, Q2 $52k, Q3 $61k, Q4 $58k",
|
|
650
|
-
},
|
|
651
|
-
{
|
|
652
|
-
title: "Pick a date",
|
|
653
|
-
label: "for a meeting",
|
|
654
|
-
prompt: "I need to schedule a meeting. Ask me to pick a date.",
|
|
655
|
-
},
|
|
656
|
-
{
|
|
657
|
-
title: "Collect my contact info",
|
|
658
|
-
label: "name, email, phone",
|
|
659
|
-
prompt:
|
|
660
|
-
"I want to sign up for the newsletter. Ask for my name, email, and phone number.",
|
|
661
|
-
},
|
|
662
|
-
{
|
|
663
|
-
title: "Show me on the map",
|
|
664
|
-
label: "the Eiffel Tower",
|
|
665
|
-
prompt: "Show me the Eiffel Tower on a map",
|
|
666
|
-
},
|
|
667
|
-
]),
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
return (
|
|
671
|
-
<AssistantRuntimeProvider config={config} runtime={runtime}>
|
|
672
|
-
<div className="flex h-full flex-col">
|
|
673
|
-
<ExampleNav />
|
|
674
|
-
<main className="min-h-0 flex-1">
|
|
675
|
-
<Thread />
|
|
676
|
-
</main>
|
|
677
|
-
</div>
|
|
678
|
-
</AssistantRuntimeProvider>
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
## app/toolkit.tsx
|
|
685
|
-
|
|
686
|
-
```tsx
|
|
687
|
-
"use generative";
|
|
688
|
-
|
|
689
|
-
import { defineToolkit, externalTool, humanTool } from "@assistant-ui/react";
|
|
690
|
-
import { ChartToolUI } from "@/components/chart-tool-ui";
|
|
691
|
-
import { DatePickerToolUI } from "@/components/date-picker-tool-ui";
|
|
692
|
-
import { ContactFormToolUI } from "@/components/contact-form-tool-ui";
|
|
693
|
-
import { LocationToolUI } from "@/components/location-tool-ui";
|
|
694
|
-
import { z } from "zod";
|
|
695
|
-
|
|
696
|
-
export default defineToolkit({
|
|
697
|
-
select_date: {
|
|
698
|
-
description:
|
|
699
|
-
"Ask the user to select a date. Use this when you need to collect a date (e.g. for scheduling, booking, deadlines).",
|
|
700
|
-
parameters: z.object({
|
|
701
|
-
prompt: z.string().describe("Message to display to the user"),
|
|
702
|
-
minDate: z.string().optional().describe("Minimum date (ISO string)"),
|
|
703
|
-
maxDate: z.string().optional().describe("Maximum date (ISO string)"),
|
|
704
|
-
}),
|
|
705
|
-
execute: humanTool(),
|
|
706
|
-
render: DatePickerToolUI,
|
|
707
|
-
},
|
|
708
|
-
collect_contact: {
|
|
709
|
-
description:
|
|
710
|
-
"Collect contact information from the user. Use this when you need the user's name, email, or phone number.",
|
|
711
|
-
parameters: z.object({
|
|
712
|
-
prompt: z.string().describe("Message to display to the user"),
|
|
713
|
-
fields: z
|
|
714
|
-
.array(z.enum(["name", "email", "phone"]))
|
|
715
|
-
.describe("Which fields to collect"),
|
|
716
|
-
}),
|
|
717
|
-
execute: humanTool(),
|
|
718
|
-
render: ContactFormToolUI,
|
|
719
|
-
},
|
|
720
|
-
generate_chart: {
|
|
721
|
-
execute: externalTool(),
|
|
722
|
-
render: ChartToolUI,
|
|
723
|
-
},
|
|
724
|
-
show_location: {
|
|
725
|
-
execute: externalTool(),
|
|
726
|
-
render: LocationToolUI,
|
|
727
|
-
},
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
## components.json
|
|
733
|
-
|
|
734
|
-
```json
|
|
735
|
-
{
|
|
736
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
737
|
-
"style": "new-york",
|
|
738
|
-
"rsc": true,
|
|
739
|
-
"tsx": true,
|
|
740
|
-
"tailwind": {
|
|
741
|
-
"config": "",
|
|
742
|
-
"css": "app/globals.css",
|
|
743
|
-
"baseColor": "zinc",
|
|
744
|
-
"cssVariables": true,
|
|
745
|
-
"prefix": ""
|
|
746
|
-
},
|
|
747
|
-
"aliases": {
|
|
748
|
-
"components": "@/components",
|
|
749
|
-
"utils": "@/lib/utils",
|
|
750
|
-
"ui": "@/components/ui",
|
|
751
|
-
"lib": "@/lib",
|
|
752
|
-
"hooks": "@/hooks"
|
|
753
|
-
},
|
|
754
|
-
"iconLibrary": "lucide",
|
|
755
|
-
"registries": {
|
|
756
|
-
"@assistant-ui": "https://r.assistant-ui.com/{name}.json"
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
## components/assistant-message-gui.tsx
|
|
763
|
-
|
|
764
|
-
```tsx
|
|
765
|
-
"use client";
|
|
766
|
-
|
|
767
|
-
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
|
|
768
|
-
import {
|
|
769
|
-
Reasoning,
|
|
770
|
-
ReasoningContent,
|
|
771
|
-
ReasoningRoot,
|
|
772
|
-
ReasoningText,
|
|
773
|
-
ReasoningTrigger,
|
|
774
|
-
} from "@/components/assistant-ui/reasoning";
|
|
775
|
-
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
|
|
776
|
-
import {
|
|
777
|
-
ToolGroupContent,
|
|
778
|
-
ToolGroupRoot,
|
|
779
|
-
ToolGroupTrigger,
|
|
780
|
-
} from "@/components/assistant-ui/tool-group";
|
|
781
|
-
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
|
|
782
|
-
import {
|
|
783
|
-
UnknownComponentFallback,
|
|
784
|
-
componentsAllowlist,
|
|
785
|
-
} from "@/components/gui";
|
|
786
|
-
import {
|
|
787
|
-
RENDER_GUI_TOOL_NAME,
|
|
788
|
-
isLeakedRenderGuiText,
|
|
789
|
-
parseRenderGuiResult,
|
|
790
|
-
} from "@/lib/render-gui-tool";
|
|
791
|
-
import { cn } from "@/lib/utils";
|
|
792
|
-
import type { GenerativeUISpec } from "@assistant-ui/react";
|
|
793
|
-
import {
|
|
794
|
-
ActionBarPrimitive,
|
|
795
|
-
AuiIf,
|
|
796
|
-
BranchPickerPrimitive,
|
|
797
|
-
ErrorPrimitive,
|
|
798
|
-
getMcpAppFromToolPart,
|
|
799
|
-
MessagePrimitive,
|
|
800
|
-
useAuiState,
|
|
801
|
-
} from "@assistant-ui/react";
|
|
802
|
-
import {
|
|
803
|
-
CheckIcon,
|
|
804
|
-
ChevronLeftIcon,
|
|
805
|
-
ChevronRightIcon,
|
|
806
|
-
CopyIcon,
|
|
807
|
-
RefreshCwIcon,
|
|
808
|
-
} from "lucide-react";
|
|
809
|
-
import { type FC, useEffect, useRef } from "react";
|
|
810
|
-
|
|
811
|
-
type AssistantMessageGuiProps = {
|
|
812
|
-
/** Set false in dev to surface the dropped-bridge warning. */
|
|
813
|
-
bridgeEnabled?: boolean;
|
|
814
|
-
};
|
|
815
|
-
|
|
816
|
-
const AllowlistedGenerativeUI = ({ spec }: { spec?: GenerativeUISpec }) => (
|
|
817
|
-
<MessagePrimitive.GenerativeUI
|
|
818
|
-
spec={spec}
|
|
819
|
-
components={componentsAllowlist}
|
|
820
|
-
Fallback={UnknownComponentFallback}
|
|
821
|
-
/>
|
|
822
|
-
);
|
|
823
|
-
|
|
824
|
-
const useDroppedGenerativeUIWarning = (bridgeEnabled: boolean) => {
|
|
825
|
-
const content = useAuiState((s) => s.message.content);
|
|
826
|
-
const warned = useRef(false);
|
|
827
|
-
|
|
828
|
-
useEffect(() => {
|
|
829
|
-
if (
|
|
830
|
-
process.env.NODE_ENV === "production" ||
|
|
831
|
-
bridgeEnabled ||
|
|
832
|
-
warned.current
|
|
833
|
-
) {
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
const hasRenderGui = content.some(
|
|
838
|
-
(part) =>
|
|
839
|
-
part.type === "tool-call" &&
|
|
840
|
-
part.toolName === RENDER_GUI_TOOL_NAME &&
|
|
841
|
-
part.result != null &&
|
|
842
|
-
parseRenderGuiResult(part.result) != null,
|
|
843
|
-
);
|
|
844
|
-
|
|
845
|
-
const hasUnhandledGenerativeUI = content.some(
|
|
846
|
-
(part) => part.type === "generative-ui",
|
|
847
|
-
);
|
|
848
|
-
|
|
849
|
-
if (hasRenderGui || hasUnhandledGenerativeUI) {
|
|
850
|
-
warned.current = true;
|
|
851
|
-
console.warn(
|
|
852
|
-
"[generative-ui] Message contains render_gui or generative-ui parts but the bridge is disabled. " +
|
|
853
|
-
"Enable the bridge in assistant-message-gui.tsx or wire MessagePrimitive.GenerativeUI.",
|
|
854
|
-
);
|
|
855
|
-
}
|
|
856
|
-
}, [bridgeEnabled, content]);
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
export const AssistantMessageGui: FC<AssistantMessageGuiProps> = ({
|
|
860
|
-
bridgeEnabled = true,
|
|
861
|
-
}) => {
|
|
862
|
-
useDroppedGenerativeUIWarning(bridgeEnabled);
|
|
863
|
-
|
|
864
|
-
const hasBridgedRenderGui = useAuiState((s) =>
|
|
865
|
-
s.message.content.some(
|
|
866
|
-
(part) =>
|
|
867
|
-
part.type === "tool-call" &&
|
|
868
|
-
part.toolName === RENDER_GUI_TOOL_NAME &&
|
|
869
|
-
parseRenderGuiResult(part.result) != null,
|
|
870
|
-
),
|
|
871
|
-
);
|
|
872
|
-
|
|
873
|
-
const ACTION_BAR_PT = "pt-1.5";
|
|
874
|
-
const ACTION_BAR_HEIGHT = `-mb-7.5 min-h-7.5 ${ACTION_BAR_PT}`;
|
|
875
|
-
|
|
876
|
-
return (
|
|
877
|
-
<MessagePrimitive.Root
|
|
878
|
-
data-slot="aui_assistant-message-root"
|
|
879
|
-
data-role="assistant"
|
|
880
|
-
className="fade-in slide-in-from-bottom-1 animate-in relative duration-150"
|
|
881
|
-
>
|
|
882
|
-
<div
|
|
883
|
-
data-slot="aui_assistant-message-content"
|
|
884
|
-
// [contain-intrinsic-size:auto_24px] fixes issue #4104, don't change without checking for regressions
|
|
885
|
-
className="text-foreground px-2 leading-relaxed wrap-break-word [contain-intrinsic-size:auto_24px] [content-visibility:auto]"
|
|
886
|
-
>
|
|
887
|
-
<MessagePrimitive.GroupedParts
|
|
888
|
-
groupBy={(part) => {
|
|
889
|
-
if (part.type === "reasoning") {
|
|
890
|
-
return ["group-chainOfThought", "group-reasoning"];
|
|
891
|
-
}
|
|
892
|
-
if (part.type === "tool-call") {
|
|
893
|
-
if (getMcpAppFromToolPart(part)) return [];
|
|
894
|
-
if (part.toolName === RENDER_GUI_TOOL_NAME) return [];
|
|
895
|
-
return ["group-chainOfThought", "group-tool"];
|
|
896
|
-
}
|
|
897
|
-
return [];
|
|
898
|
-
}}
|
|
899
|
-
>
|
|
900
|
-
{({ part, children }) => {
|
|
901
|
-
switch (part.type) {
|
|
902
|
-
case "group-chainOfThought":
|
|
903
|
-
return <div data-slot="aui_chain-of-thought">{children}</div>;
|
|
904
|
-
case "group-reasoning": {
|
|
905
|
-
const running = part.status.type === "running";
|
|
906
|
-
return (
|
|
907
|
-
<ReasoningRoot streaming={running}>
|
|
908
|
-
<ReasoningTrigger active={running} />
|
|
909
|
-
<ReasoningContent aria-busy={running}>
|
|
910
|
-
<ReasoningText>{children}</ReasoningText>
|
|
911
|
-
</ReasoningContent>
|
|
912
|
-
</ReasoningRoot>
|
|
913
|
-
);
|
|
914
|
-
}
|
|
915
|
-
case "group-tool":
|
|
916
|
-
return (
|
|
917
|
-
<ToolGroupRoot>
|
|
918
|
-
<ToolGroupTrigger
|
|
919
|
-
count={part.indices.length}
|
|
920
|
-
active={part.status.type === "running"}
|
|
921
|
-
/>
|
|
922
|
-
<ToolGroupContent>{children}</ToolGroupContent>
|
|
923
|
-
</ToolGroupRoot>
|
|
924
|
-
);
|
|
925
|
-
case "text":
|
|
926
|
-
if (
|
|
927
|
-
bridgeEnabled &&
|
|
928
|
-
hasBridgedRenderGui &&
|
|
929
|
-
isLeakedRenderGuiText(part.text)
|
|
930
|
-
) {
|
|
931
|
-
return null;
|
|
932
|
-
}
|
|
933
|
-
return <MarkdownText />;
|
|
934
|
-
case "reasoning":
|
|
935
|
-
return <Reasoning {...part} />;
|
|
936
|
-
case "generative-ui":
|
|
937
|
-
return bridgeEnabled ? <AllowlistedGenerativeUI /> : null;
|
|
938
|
-
case "tool-call": {
|
|
939
|
-
if (bridgeEnabled && part.toolName === RENDER_GUI_TOOL_NAME) {
|
|
940
|
-
const spec = parseRenderGuiResult(part.result);
|
|
941
|
-
if (spec) return <AllowlistedGenerativeUI spec={spec} />;
|
|
942
|
-
}
|
|
943
|
-
return part.toolUI ?? <ToolFallback {...part} />;
|
|
944
|
-
}
|
|
945
|
-
default:
|
|
946
|
-
return null;
|
|
947
|
-
}
|
|
948
|
-
}}
|
|
949
|
-
</MessagePrimitive.GroupedParts>
|
|
950
|
-
<MessagePrimitive.Error>
|
|
951
|
-
<ErrorPrimitive.Root className="aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200">
|
|
952
|
-
<ErrorPrimitive.Message className="aui-message-error-message line-clamp-2" />
|
|
953
|
-
</ErrorPrimitive.Root>
|
|
954
|
-
</MessagePrimitive.Error>
|
|
955
|
-
</div>
|
|
956
|
-
|
|
957
|
-
<div
|
|
958
|
-
data-slot="aui_assistant-message-footer"
|
|
959
|
-
className={cn("ms-2 flex items-center", ACTION_BAR_HEIGHT)}
|
|
960
|
-
>
|
|
961
|
-
<BranchPickerPrimitive.Root
|
|
962
|
-
hideWhenSingleBranch
|
|
963
|
-
className="aui-branch-picker-root text-muted-foreground -ms-2 me-2 inline-flex items-center text-xs"
|
|
964
|
-
>
|
|
965
|
-
<BranchPickerPrimitive.Previous asChild>
|
|
966
|
-
<TooltipIconButton tooltip="Previous">
|
|
967
|
-
<ChevronLeftIcon />
|
|
968
|
-
</TooltipIconButton>
|
|
969
|
-
</BranchPickerPrimitive.Previous>
|
|
970
|
-
<span className="aui-branch-picker-state font-medium">
|
|
971
|
-
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
972
|
-
</span>
|
|
973
|
-
<BranchPickerPrimitive.Next asChild>
|
|
974
|
-
<TooltipIconButton tooltip="Next">
|
|
975
|
-
<ChevronRightIcon />
|
|
976
|
-
</TooltipIconButton>
|
|
977
|
-
</BranchPickerPrimitive.Next>
|
|
978
|
-
</BranchPickerPrimitive.Root>
|
|
979
|
-
<ActionBarPrimitive.Root
|
|
980
|
-
hideWhenRunning
|
|
981
|
-
autohide="not-last"
|
|
982
|
-
className="aui-assistant-action-bar-root text-muted-foreground -ms-1 flex gap-1"
|
|
983
|
-
>
|
|
984
|
-
<ActionBarPrimitive.Copy asChild>
|
|
985
|
-
<TooltipIconButton tooltip="Copy">
|
|
986
|
-
<AuiIf condition={(s) => s.message.isCopied}>
|
|
987
|
-
<CheckIcon />
|
|
988
|
-
</AuiIf>
|
|
989
|
-
<AuiIf condition={(s) => !s.message.isCopied}>
|
|
990
|
-
<CopyIcon />
|
|
991
|
-
</AuiIf>
|
|
992
|
-
</TooltipIconButton>
|
|
993
|
-
</ActionBarPrimitive.Copy>
|
|
994
|
-
<ActionBarPrimitive.Reload asChild>
|
|
995
|
-
<TooltipIconButton tooltip="Refresh">
|
|
996
|
-
<RefreshCwIcon />
|
|
997
|
-
</TooltipIconButton>
|
|
998
|
-
</ActionBarPrimitive.Reload>
|
|
999
|
-
</ActionBarPrimitive.Root>
|
|
1000
|
-
</div>
|
|
1001
|
-
</MessagePrimitive.Root>
|
|
1002
|
-
);
|
|
1003
|
-
};
|
|
1004
|
-
|
|
1005
|
-
```
|
|
1006
|
-
|
|
1007
|
-
## components/chart-tool-ui.tsx
|
|
1008
|
-
|
|
1009
|
-
```tsx
|
|
1010
|
-
"use client";
|
|
1011
|
-
|
|
1012
|
-
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1013
|
-
import {
|
|
1014
|
-
BarChart,
|
|
1015
|
-
Bar,
|
|
1016
|
-
LineChart,
|
|
1017
|
-
Line,
|
|
1018
|
-
PieChart,
|
|
1019
|
-
Pie,
|
|
1020
|
-
Cell,
|
|
1021
|
-
XAxis,
|
|
1022
|
-
YAxis,
|
|
1023
|
-
CartesianGrid,
|
|
1024
|
-
Tooltip,
|
|
1025
|
-
Legend,
|
|
1026
|
-
ResponsiveContainer,
|
|
1027
|
-
} from "recharts";
|
|
1028
|
-
import { Loader2Icon } from "lucide-react";
|
|
1029
|
-
|
|
1030
|
-
type ChartArgs = {
|
|
1031
|
-
title: string;
|
|
1032
|
-
type: "bar" | "line" | "pie";
|
|
1033
|
-
data: Array<Record<string, string | number>>;
|
|
1034
|
-
xKey: string;
|
|
1035
|
-
dataKeys: string[];
|
|
1036
|
-
};
|
|
1037
|
-
|
|
1038
|
-
type ChartResult = {
|
|
1039
|
-
success: boolean;
|
|
1040
|
-
};
|
|
1041
|
-
|
|
1042
|
-
const COLORS = [
|
|
1043
|
-
"oklch(0.646 0.222 41.116)",
|
|
1044
|
-
"oklch(0.6 0.118 184.704)",
|
|
1045
|
-
"oklch(0.398 0.07 227.392)",
|
|
1046
|
-
"oklch(0.828 0.189 84.429)",
|
|
1047
|
-
"oklch(0.769 0.188 70.08)",
|
|
1048
|
-
];
|
|
1049
|
-
|
|
1050
|
-
export const ChartToolUI: ToolCallMessagePartComponent<ChartArgs, ChartResult> =
|
|
1051
|
-
function ChartUI({ args, status }) {
|
|
1052
|
-
if (status.type === "running" && !args.data?.length) {
|
|
1053
|
-
return (
|
|
1054
|
-
<div className="flex items-center gap-2 rounded-lg border p-4">
|
|
1055
|
-
<Loader2Icon className="text-muted-foreground size-4 animate-spin" />
|
|
1056
|
-
<span className="text-muted-foreground text-sm">
|
|
1057
|
-
Generating chart...
|
|
1058
|
-
</span>
|
|
1059
|
-
</div>
|
|
1060
|
-
);
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
const { title, type, data, xKey, dataKeys } = args;
|
|
1064
|
-
if (!data?.length || !dataKeys?.length) return null;
|
|
1065
|
-
|
|
1066
|
-
return (
|
|
1067
|
-
<div className="my-2 rounded-lg border p-4">
|
|
1068
|
-
<h3 className="mb-3 text-center text-sm font-semibold">{title}</h3>
|
|
1069
|
-
<div className="h-[280px] w-full">
|
|
1070
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
1071
|
-
{type === "bar" ? (
|
|
1072
|
-
<BarChart data={data}>
|
|
1073
|
-
<CartesianGrid strokeDasharray="3 3" vertical={false} />
|
|
1074
|
-
<XAxis
|
|
1075
|
-
dataKey={xKey}
|
|
1076
|
-
tickLine={false}
|
|
1077
|
-
axisLine={false}
|
|
1078
|
-
fontSize={12}
|
|
1079
|
-
/>
|
|
1080
|
-
<YAxis tickLine={false} axisLine={false} fontSize={12} />
|
|
1081
|
-
<Tooltip />
|
|
1082
|
-
<Legend />
|
|
1083
|
-
{dataKeys.map((key, i) => (
|
|
1084
|
-
<Bar
|
|
1085
|
-
key={key}
|
|
1086
|
-
dataKey={key}
|
|
1087
|
-
fill={COLORS[i % COLORS.length]}
|
|
1088
|
-
radius={[4, 4, 0, 0]}
|
|
1089
|
-
/>
|
|
1090
|
-
))}
|
|
1091
|
-
</BarChart>
|
|
1092
|
-
) : type === "line" ? (
|
|
1093
|
-
<LineChart data={data}>
|
|
1094
|
-
<CartesianGrid strokeDasharray="3 3" vertical={false} />
|
|
1095
|
-
<XAxis
|
|
1096
|
-
dataKey={xKey}
|
|
1097
|
-
tickLine={false}
|
|
1098
|
-
axisLine={false}
|
|
1099
|
-
fontSize={12}
|
|
1100
|
-
/>
|
|
1101
|
-
<YAxis tickLine={false} axisLine={false} fontSize={12} />
|
|
1102
|
-
<Tooltip />
|
|
1103
|
-
<Legend />
|
|
1104
|
-
{dataKeys.map((key, i) => (
|
|
1105
|
-
<Line
|
|
1106
|
-
key={key}
|
|
1107
|
-
type="monotone"
|
|
1108
|
-
dataKey={key}
|
|
1109
|
-
stroke={COLORS[i % COLORS.length] ?? "#8884d8"}
|
|
1110
|
-
strokeWidth={2}
|
|
1111
|
-
dot={false}
|
|
1112
|
-
/>
|
|
1113
|
-
))}
|
|
1114
|
-
</LineChart>
|
|
1115
|
-
) : (
|
|
1116
|
-
<PieChart>
|
|
1117
|
-
<Tooltip />
|
|
1118
|
-
<Legend />
|
|
1119
|
-
<Pie
|
|
1120
|
-
data={data}
|
|
1121
|
-
dataKey={dataKeys[0]!}
|
|
1122
|
-
nameKey={xKey}
|
|
1123
|
-
cx="50%"
|
|
1124
|
-
cy="50%"
|
|
1125
|
-
outerRadius={80}
|
|
1126
|
-
label
|
|
1127
|
-
>
|
|
1128
|
-
{data.map((_, i) => (
|
|
1129
|
-
<Cell
|
|
1130
|
-
key={i}
|
|
1131
|
-
fill={COLORS[i % COLORS.length] ?? "#8884d8"}
|
|
1132
|
-
/>
|
|
1133
|
-
))}
|
|
1134
|
-
</Pie>
|
|
1135
|
-
</PieChart>
|
|
1136
|
-
)}
|
|
1137
|
-
</ResponsiveContainer>
|
|
1138
|
-
</div>
|
|
1139
|
-
</div>
|
|
1140
|
-
);
|
|
1141
|
-
};
|
|
1142
|
-
|
|
1143
|
-
```
|
|
1144
|
-
|
|
1145
|
-
## components/contact-form-tool-ui.tsx
|
|
1146
|
-
|
|
1147
|
-
```tsx
|
|
1148
|
-
"use client";
|
|
1149
|
-
|
|
1150
|
-
import { useState } from "react";
|
|
1151
|
-
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1152
|
-
import { UserIcon, CheckCircle2Icon } from "lucide-react";
|
|
1153
|
-
|
|
1154
|
-
type ContactFormArgs = {
|
|
1155
|
-
prompt: string;
|
|
1156
|
-
fields: Array<"name" | "email" | "phone">;
|
|
1157
|
-
};
|
|
1158
|
-
|
|
1159
|
-
type ContactFormResult = {
|
|
1160
|
-
name?: string;
|
|
1161
|
-
email?: string;
|
|
1162
|
-
phone?: string;
|
|
1163
|
-
};
|
|
1164
|
-
|
|
1165
|
-
export const ContactFormToolUI: ToolCallMessagePartComponent<
|
|
1166
|
-
ContactFormArgs,
|
|
1167
|
-
ContactFormResult
|
|
1168
|
-
> = function ContactFormUI({ args, result, addResult }) {
|
|
1169
|
-
const [form, setForm] = useState<ContactFormResult>({});
|
|
1170
|
-
|
|
1171
|
-
if (result) {
|
|
1172
|
-
return (
|
|
1173
|
-
<div className="my-2 rounded-lg border border-green-200 bg-green-50 p-3">
|
|
1174
|
-
<div className="mb-1 flex items-center gap-2">
|
|
1175
|
-
<CheckCircle2Icon className="size-4 text-green-600" />
|
|
1176
|
-
<span className="text-sm font-medium text-green-800">
|
|
1177
|
-
Contact info collected
|
|
1178
|
-
</span>
|
|
1179
|
-
</div>
|
|
1180
|
-
<div className="ml-6 space-y-0.5 text-xs text-green-700">
|
|
1181
|
-
{result.name && <p>Name: {result.name}</p>}
|
|
1182
|
-
{result.email && <p>Email: {result.email}</p>}
|
|
1183
|
-
{result.phone && <p>Phone: {result.phone}</p>}
|
|
1184
|
-
</div>
|
|
1185
|
-
</div>
|
|
1186
|
-
);
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
const fields = args.fields ?? ["name", "email", "phone"];
|
|
1190
|
-
const isValid = fields.every((f) => form[f]?.trim());
|
|
1191
|
-
|
|
1192
|
-
return (
|
|
1193
|
-
<div className="my-2 rounded-lg border p-4">
|
|
1194
|
-
<div className="mb-3 flex items-center gap-2">
|
|
1195
|
-
<UserIcon className="text-muted-foreground size-4" />
|
|
1196
|
-
<span className="text-sm font-medium">{args.prompt}</span>
|
|
1197
|
-
</div>
|
|
1198
|
-
<div className="space-y-2">
|
|
1199
|
-
{fields.includes("name") && (
|
|
1200
|
-
<input
|
|
1201
|
-
type="text"
|
|
1202
|
-
placeholder="Name"
|
|
1203
|
-
value={form.name ?? ""}
|
|
1204
|
-
onChange={(e) => setForm((p) => ({ ...p, name: e.target.value }))}
|
|
1205
|
-
className="bg-background w-full rounded-md border px-3 py-2 text-sm"
|
|
1206
|
-
/>
|
|
1207
|
-
)}
|
|
1208
|
-
{fields.includes("email") && (
|
|
1209
|
-
<input
|
|
1210
|
-
type="email"
|
|
1211
|
-
placeholder="Email"
|
|
1212
|
-
value={form.email ?? ""}
|
|
1213
|
-
onChange={(e) => setForm((p) => ({ ...p, email: e.target.value }))}
|
|
1214
|
-
className="bg-background w-full rounded-md border px-3 py-2 text-sm"
|
|
1215
|
-
/>
|
|
1216
|
-
)}
|
|
1217
|
-
{fields.includes("phone") && (
|
|
1218
|
-
<input
|
|
1219
|
-
type="tel"
|
|
1220
|
-
placeholder="Phone"
|
|
1221
|
-
value={form.phone ?? ""}
|
|
1222
|
-
onChange={(e) => setForm((p) => ({ ...p, phone: e.target.value }))}
|
|
1223
|
-
className="bg-background w-full rounded-md border px-3 py-2 text-sm"
|
|
1224
|
-
/>
|
|
1225
|
-
)}
|
|
1226
|
-
<button
|
|
1227
|
-
type="button"
|
|
1228
|
-
disabled={!isValid}
|
|
1229
|
-
onClick={() => addResult(form)}
|
|
1230
|
-
className="bg-primary text-primary-foreground w-full rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50"
|
|
1231
|
-
>
|
|
1232
|
-
Submit
|
|
1233
|
-
</button>
|
|
1234
|
-
</div>
|
|
1235
|
-
</div>
|
|
1236
|
-
);
|
|
1237
|
-
};
|
|
1238
|
-
|
|
1239
|
-
```
|
|
1240
|
-
|
|
1241
|
-
## components/dashboard-header.tsx
|
|
1242
|
-
|
|
1243
|
-
```tsx
|
|
1244
|
-
"use client";
|
|
1245
|
-
|
|
1246
|
-
type DashboardHeaderProps = {
|
|
1247
|
-
title: string;
|
|
1248
|
-
description?: string;
|
|
1249
|
-
period?: string;
|
|
1250
|
-
};
|
|
1251
|
-
|
|
1252
|
-
export function DashboardHeader({
|
|
1253
|
-
title,
|
|
1254
|
-
description,
|
|
1255
|
-
period,
|
|
1256
|
-
}: DashboardHeaderProps) {
|
|
1257
|
-
return (
|
|
1258
|
-
<header className="flex flex-wrap items-start justify-between gap-3">
|
|
1259
|
-
<div className="min-w-0">
|
|
1260
|
-
<h2 className="text-lg font-semibold tracking-tight">{title}</h2>
|
|
1261
|
-
{description ? (
|
|
1262
|
-
<p className="text-muted-foreground mt-1 text-sm">{description}</p>
|
|
1263
|
-
) : null}
|
|
1264
|
-
</div>
|
|
1265
|
-
{period ? (
|
|
1266
|
-
<span className="bg-muted text-muted-foreground rounded-full px-2.5 py-1 text-xs font-medium">
|
|
1267
|
-
{period}
|
|
1268
|
-
</span>
|
|
1269
|
-
) : null}
|
|
1270
|
-
</header>
|
|
1271
|
-
);
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
```
|
|
1275
|
-
|
|
1276
|
-
## components/date-picker-tool-ui.tsx
|
|
1277
|
-
|
|
1278
|
-
```tsx
|
|
1279
|
-
"use client";
|
|
1280
|
-
|
|
1281
|
-
import { useState } from "react";
|
|
1282
|
-
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1283
|
-
import { CalendarIcon, CheckCircle2Icon } from "lucide-react";
|
|
1284
|
-
|
|
1285
|
-
type DatePickerArgs = {
|
|
1286
|
-
prompt: string;
|
|
1287
|
-
minDate?: string;
|
|
1288
|
-
maxDate?: string;
|
|
1289
|
-
};
|
|
1290
|
-
|
|
1291
|
-
type DatePickerResult = {
|
|
1292
|
-
date: string;
|
|
1293
|
-
};
|
|
1294
|
-
|
|
1295
|
-
export const DatePickerToolUI: ToolCallMessagePartComponent<
|
|
1296
|
-
DatePickerArgs,
|
|
1297
|
-
DatePickerResult
|
|
1298
|
-
> = function DatePickerUI({ args, result, addResult }) {
|
|
1299
|
-
const [value, setValue] = useState("");
|
|
1300
|
-
|
|
1301
|
-
if (result) {
|
|
1302
|
-
return (
|
|
1303
|
-
<div className="my-2 flex items-center gap-2 rounded-lg border border-green-200 bg-green-50 p-3">
|
|
1304
|
-
<CheckCircle2Icon className="size-4 text-green-600" />
|
|
1305
|
-
<span className="text-sm text-green-800">
|
|
1306
|
-
Selected: {new Date(result.date).toLocaleDateString()}
|
|
1307
|
-
</span>
|
|
1308
|
-
</div>
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
return (
|
|
1313
|
-
<div className="my-2 rounded-lg border p-4">
|
|
1314
|
-
<div className="mb-3 flex items-center gap-2">
|
|
1315
|
-
<CalendarIcon className="text-muted-foreground size-4" />
|
|
1316
|
-
<span className="text-sm font-medium">{args.prompt}</span>
|
|
1317
|
-
</div>
|
|
1318
|
-
<div className="flex items-center gap-2">
|
|
1319
|
-
<input
|
|
1320
|
-
type="date"
|
|
1321
|
-
value={value}
|
|
1322
|
-
min={args.minDate}
|
|
1323
|
-
max={args.maxDate}
|
|
1324
|
-
onChange={(e) => setValue(e.target.value)}
|
|
1325
|
-
className="bg-background rounded-md border px-3 py-2 text-sm"
|
|
1326
|
-
/>
|
|
1327
|
-
<button
|
|
1328
|
-
type="button"
|
|
1329
|
-
disabled={!value}
|
|
1330
|
-
onClick={() => addResult({ date: new Date(value).toISOString() })}
|
|
1331
|
-
className="bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50"
|
|
1332
|
-
>
|
|
1333
|
-
Confirm
|
|
1334
|
-
</button>
|
|
1335
|
-
</div>
|
|
1336
|
-
</div>
|
|
1337
|
-
);
|
|
1338
|
-
};
|
|
1339
|
-
|
|
1340
|
-
```
|
|
1341
|
-
|
|
1342
|
-
## components/example-nav.tsx
|
|
1343
|
-
|
|
1344
|
-
```tsx
|
|
1345
|
-
import Link from "next/link";
|
|
1346
|
-
|
|
1347
|
-
const links = [
|
|
1348
|
-
{ href: "/", label: "Generative UI" },
|
|
1349
|
-
{ href: "/tool-ui", label: "Tool UI" },
|
|
1350
|
-
{ href: "/primitive", label: "Static primitive (legacy)" },
|
|
1351
|
-
{ href: "/gui-chat", label: "GUI chat (legacy)" },
|
|
1352
|
-
] as const;
|
|
1353
|
-
|
|
1354
|
-
export function ExampleNav() {
|
|
1355
|
-
return (
|
|
1356
|
-
<nav className="bg-background flex flex-wrap items-center gap-2 border-b px-4 py-2 text-sm">
|
|
1357
|
-
<span className="text-muted-foreground font-medium">Examples:</span>
|
|
1358
|
-
{links.map(({ href, label }) => (
|
|
1359
|
-
<Link
|
|
1360
|
-
key={href}
|
|
1361
|
-
href={href}
|
|
1362
|
-
className="text-foreground hover:bg-muted rounded-md px-2 py-1"
|
|
1363
|
-
>
|
|
1364
|
-
{label}
|
|
1365
|
-
</Link>
|
|
1366
|
-
))}
|
|
1367
|
-
</nav>
|
|
1368
|
-
);
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
```
|
|
1372
|
-
|
|
1373
|
-
## components/generative-ui-style.tsx
|
|
1374
|
-
|
|
1375
|
-
```tsx
|
|
1376
|
-
import {
|
|
1377
|
-
generativeUiCssText,
|
|
1378
|
-
generativeUiThemeVars,
|
|
1379
|
-
} from "@assistant-ui/ui/lib/generative-ui-vocabulary-css";
|
|
1380
|
-
|
|
1381
|
-
function themeVarsBlock(selector: string, vars: Record<string, string>) {
|
|
1382
|
-
const body = Object.entries(vars)
|
|
1383
|
-
.map(([name, value]) => ` ${name}: ${value};`)
|
|
1384
|
-
.join("\n");
|
|
1385
|
-
return `${selector} {\n${body}\n}`;
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
export function GenerativeUIStyle() {
|
|
1389
|
-
const css = [
|
|
1390
|
-
themeVarsBlock(":root", generativeUiThemeVars.light),
|
|
1391
|
-
themeVarsBlock(".dark", generativeUiThemeVars.dark),
|
|
1392
|
-
generativeUiCssText(),
|
|
1393
|
-
].join("\n\n");
|
|
1394
|
-
|
|
1395
|
-
return <style>{css}</style>;
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
```
|
|
1399
|
-
|
|
1400
|
-
## components/gui/index.tsx
|
|
1401
|
-
|
|
1402
|
-
```tsx
|
|
1403
|
-
"use client";
|
|
1404
|
-
|
|
1405
|
-
import type { ComponentType, PropsWithChildren } from "react";
|
|
1406
|
-
|
|
1407
|
-
/**
|
|
1408
|
-
* The component allowlist passed to `<MessagePrimitive.GenerativeUI />`.
|
|
1409
|
-
* The agent's JSON spec can reference any of these by name.
|
|
1410
|
-
*/
|
|
1411
|
-
|
|
1412
|
-
export const UnknownComponentFallback = ({
|
|
1413
|
-
component,
|
|
1414
|
-
}: {
|
|
1415
|
-
component: string;
|
|
1416
|
-
}) => (
|
|
1417
|
-
<span className="bg-muted rounded px-1.5 py-0.5 font-mono text-xs">
|
|
1418
|
-
unknown component: {component}
|
|
1419
|
-
</span>
|
|
1420
|
-
);
|
|
1421
|
-
|
|
1422
|
-
const Card: ComponentType<
|
|
1423
|
-
PropsWithChildren<{ title?: string; description?: string }>
|
|
1424
|
-
> = ({ title, description, children }) => (
|
|
1425
|
-
<div className="bg-card rounded-xl border p-4 shadow-sm">
|
|
1426
|
-
{title ? <div className="text-base font-semibold">{title}</div> : null}
|
|
1427
|
-
{description ? (
|
|
1428
|
-
<div className="text-muted-foreground mt-1 text-sm">{description}</div>
|
|
1429
|
-
) : null}
|
|
1430
|
-
{children ? <div className="mt-3">{children}</div> : null}
|
|
1431
|
-
</div>
|
|
1432
|
-
);
|
|
1433
|
-
|
|
1434
|
-
const Button: ComponentType<
|
|
1435
|
-
PropsWithChildren<{
|
|
1436
|
-
label?: string;
|
|
1437
|
-
variant?: "primary" | "secondary";
|
|
1438
|
-
onClickPrompt?: string;
|
|
1439
|
-
}>
|
|
1440
|
-
> = ({ label, variant = "primary", onClickPrompt, children }) => {
|
|
1441
|
-
const cls =
|
|
1442
|
-
variant === "primary"
|
|
1443
|
-
? "bg-primary text-primary-foreground hover:bg-primary/90"
|
|
1444
|
-
: "bg-secondary text-secondary-foreground hover:bg-secondary/80";
|
|
1445
|
-
return (
|
|
1446
|
-
<button
|
|
1447
|
-
type="button"
|
|
1448
|
-
className={`mt-2 inline-flex items-center rounded-md px-3 py-1.5 text-sm font-medium ${cls}`}
|
|
1449
|
-
onClick={() => {
|
|
1450
|
-
if (onClickPrompt) {
|
|
1451
|
-
// In a richer integration this would call composer.setText / send.
|
|
1452
|
-
alert(`button -> ${onClickPrompt}`);
|
|
1453
|
-
}
|
|
1454
|
-
}}
|
|
1455
|
-
>
|
|
1456
|
-
{children ?? label ?? "Click"}
|
|
1457
|
-
</button>
|
|
1458
|
-
);
|
|
1459
|
-
};
|
|
1460
|
-
|
|
1461
|
-
const Stack: ComponentType<
|
|
1462
|
-
PropsWithChildren<{ gap?: "sm" | "md" | "lg"; direction?: "row" | "column" }>
|
|
1463
|
-
> = ({ gap = "md", direction = "column", children }) => {
|
|
1464
|
-
const gapClass = gap === "sm" ? "gap-2" : gap === "lg" ? "gap-6" : "gap-4";
|
|
1465
|
-
const dirClass = direction === "row" ? "flex-row" : "flex-col";
|
|
1466
|
-
return <div className={`flex ${dirClass} ${gapClass}`}>{children}</div>;
|
|
1467
|
-
};
|
|
1468
|
-
|
|
1469
|
-
const Heading: ComponentType<
|
|
1470
|
-
PropsWithChildren<{ level?: 1 | 2 | 3; children?: React.ReactNode }>
|
|
1471
|
-
> = ({ level = 2, children }) => {
|
|
1472
|
-
const cls =
|
|
1473
|
-
level === 1
|
|
1474
|
-
? "text-2xl font-bold"
|
|
1475
|
-
: level === 2
|
|
1476
|
-
? "text-lg font-semibold"
|
|
1477
|
-
: "text-base font-semibold";
|
|
1478
|
-
const Tag = `h${level}` as keyof React.JSX.IntrinsicElements;
|
|
1479
|
-
return <Tag className={cls}>{children}</Tag>;
|
|
1480
|
-
};
|
|
1481
|
-
|
|
1482
|
-
const Text: ComponentType<PropsWithChildren> = ({ children }) => (
|
|
1483
|
-
<p className="text-foreground text-sm leading-6">{children}</p>
|
|
1484
|
-
);
|
|
1485
|
-
|
|
1486
|
-
const Stat: ComponentType<{ label: string; value: string | number }> = ({
|
|
1487
|
-
label,
|
|
1488
|
-
value,
|
|
1489
|
-
}) => (
|
|
1490
|
-
<div className="bg-muted/40 flex flex-col rounded-lg border p-3">
|
|
1491
|
-
<span className="text-muted-foreground text-xs">{label}</span>
|
|
1492
|
-
<span className="text-xl font-semibold">{value}</span>
|
|
1493
|
-
</div>
|
|
1494
|
-
);
|
|
1495
|
-
|
|
1496
|
-
export const componentsAllowlist = {
|
|
1497
|
-
Card,
|
|
1498
|
-
Button,
|
|
1499
|
-
Stack,
|
|
1500
|
-
Heading,
|
|
1501
|
-
Text,
|
|
1502
|
-
Stat,
|
|
1503
|
-
} as const;
|
|
1504
|
-
|
|
1505
|
-
```
|
|
1506
|
-
|
|
1507
|
-
## components/location-tool-ui.tsx
|
|
1508
|
-
|
|
1509
|
-
```tsx
|
|
1510
|
-
"use client";
|
|
1511
|
-
|
|
1512
|
-
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
|
|
1513
|
-
import { MapPinIcon, Loader2Icon } from "lucide-react";
|
|
1514
|
-
|
|
1515
|
-
type LocationArgs = {
|
|
1516
|
-
name: string;
|
|
1517
|
-
address?: string;
|
|
1518
|
-
lat: number;
|
|
1519
|
-
lng: number;
|
|
1520
|
-
};
|
|
1521
|
-
|
|
1522
|
-
type LocationResult = {
|
|
1523
|
-
success: boolean;
|
|
1524
|
-
};
|
|
1525
|
-
|
|
1526
|
-
export const LocationToolUI: ToolCallMessagePartComponent<
|
|
1527
|
-
LocationArgs,
|
|
1528
|
-
LocationResult
|
|
1529
|
-
> = function LocationUI({ args, status }) {
|
|
1530
|
-
if (status.type === "running" && (args.lat == null || args.lng == null)) {
|
|
1531
|
-
return (
|
|
1532
|
-
<div className="flex items-center gap-2 rounded-lg border p-4">
|
|
1533
|
-
<Loader2Icon className="text-muted-foreground size-4 animate-spin" />
|
|
1534
|
-
<span className="text-muted-foreground text-sm">
|
|
1535
|
-
Loading location...
|
|
1536
|
-
</span>
|
|
1537
|
-
</div>
|
|
1538
|
-
);
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
const { name, address, lat, lng } = args;
|
|
1542
|
-
if (lat == null || lng == null) return null;
|
|
1543
|
-
|
|
1544
|
-
const mapSrc = `https://www.openstreetmap.org/export/embed.html?bbox=${lng - 0.01},${lat - 0.01},${lng + 0.01},${lat + 0.01}&layer=mapnik&marker=${lat},${lng}`;
|
|
1545
|
-
|
|
1546
|
-
return (
|
|
1547
|
-
<div className="my-2 overflow-hidden rounded-lg border">
|
|
1548
|
-
<div className="flex items-center gap-2 border-b px-3 py-2">
|
|
1549
|
-
<MapPinIcon className="text-muted-foreground size-4" />
|
|
1550
|
-
<div>
|
|
1551
|
-
<p className="text-sm font-medium">{name}</p>
|
|
1552
|
-
{address && (
|
|
1553
|
-
<p className="text-muted-foreground text-xs">{address}</p>
|
|
1554
|
-
)}
|
|
1555
|
-
</div>
|
|
1556
|
-
</div>
|
|
1557
|
-
<iframe
|
|
1558
|
-
title={`Map of ${name}`}
|
|
1559
|
-
src={mapSrc}
|
|
1560
|
-
className="h-[200px] w-full border-0"
|
|
1561
|
-
/>
|
|
1562
|
-
</div>
|
|
1563
|
-
);
|
|
1564
|
-
};
|
|
1565
|
-
|
|
1566
|
-
```
|
|
1567
|
-
|
|
1568
|
-
## lib/render-gui-tool.test.ts
|
|
1569
|
-
|
|
1570
|
-
```typescript
|
|
1571
|
-
import { describe, expect, it } from "vitest";
|
|
1572
|
-
import {
|
|
1573
|
-
generativeUISpecSchema,
|
|
1574
|
-
isLeakedRenderGuiText,
|
|
1575
|
-
parseRenderGuiResult,
|
|
1576
|
-
renderGuiToolResultSchema,
|
|
1577
|
-
} from "./render-gui-tool";
|
|
1578
|
-
|
|
1579
|
-
describe("render-gui-tool", () => {
|
|
1580
|
-
it("accepts a valid Card + Button spec", () => {
|
|
1581
|
-
const spec = {
|
|
1582
|
-
root: {
|
|
1583
|
-
component: "Card",
|
|
1584
|
-
props: { title: "Welcome" },
|
|
1585
|
-
children: [
|
|
1586
|
-
{
|
|
1587
|
-
component: "Button",
|
|
1588
|
-
props: { label: "Get started", variant: "primary" },
|
|
1589
|
-
},
|
|
1590
|
-
],
|
|
1591
|
-
},
|
|
1592
|
-
};
|
|
1593
|
-
|
|
1594
|
-
expect(generativeUISpecSchema.parse(spec)).toEqual(spec);
|
|
1595
|
-
expect(
|
|
1596
|
-
parseRenderGuiResult(renderGuiToolResultSchema.parse({ spec })),
|
|
1597
|
-
).toEqual(spec);
|
|
1598
|
-
});
|
|
1599
|
-
|
|
1600
|
-
it("rejects a spec with empty component name", () => {
|
|
1601
|
-
expect(() =>
|
|
1602
|
-
generativeUISpecSchema.parse({
|
|
1603
|
-
root: { component: "", props: { title: "Bad" } },
|
|
1604
|
-
}),
|
|
1605
|
-
).toThrow();
|
|
1606
|
-
});
|
|
1607
|
-
|
|
1608
|
-
it("returns undefined for malformed tool results", () => {
|
|
1609
|
-
expect(parseRenderGuiResult({ notSpec: true })).toBeUndefined();
|
|
1610
|
-
expect(parseRenderGuiResult(null)).toBeUndefined();
|
|
1611
|
-
});
|
|
1612
|
-
|
|
1613
|
-
it("detects leaked render_gui tool result text", () => {
|
|
1614
|
-
const payload = renderGuiToolResultSchema.parse({
|
|
1615
|
-
spec: {
|
|
1616
|
-
root: {
|
|
1617
|
-
component: "Card",
|
|
1618
|
-
children: [{ component: "Text", children: ["Hello"] }],
|
|
1619
|
-
},
|
|
1620
|
-
},
|
|
1621
|
-
});
|
|
1622
|
-
|
|
1623
|
-
expect(isLeakedRenderGuiText(JSON.stringify(payload, null, 2))).toBe(true);
|
|
1624
|
-
expect(
|
|
1625
|
-
isLeakedRenderGuiText(
|
|
1626
|
-
"```json\n" + JSON.stringify(payload, null, 2) + "\n```",
|
|
1627
|
-
),
|
|
1628
|
-
).toBe(true);
|
|
1629
|
-
expect(isLeakedRenderGuiText("Here is your card.")).toBe(false);
|
|
1630
|
-
});
|
|
1631
|
-
});
|
|
1632
|
-
|
|
1633
|
-
```
|
|
1634
|
-
|
|
1635
|
-
## lib/render-gui-tool.ts
|
|
1636
|
-
|
|
1637
|
-
```typescript
|
|
1638
|
-
import { z } from "zod";
|
|
1639
|
-
import type { GenerativeUISpec } from "@assistant-ui/react";
|
|
1640
|
-
|
|
1641
|
-
export const RENDER_GUI_TOOL_NAME = "render_gui" as const;
|
|
1642
|
-
|
|
1643
|
-
const generativeUINodeSchema: z.ZodType<unknown> = z.lazy(() =>
|
|
1644
|
-
z.union([
|
|
1645
|
-
z.string(),
|
|
1646
|
-
z.object({
|
|
1647
|
-
component: z.string().min(1),
|
|
1648
|
-
props: z.record(z.string(), z.unknown()).optional(),
|
|
1649
|
-
children: z.array(generativeUINodeSchema).optional(),
|
|
1650
|
-
key: z.string().optional(),
|
|
1651
|
-
}),
|
|
1652
|
-
]),
|
|
1653
|
-
);
|
|
1654
|
-
|
|
1655
|
-
export const generativeUISpecSchema = z.object({
|
|
1656
|
-
root: z.union([
|
|
1657
|
-
generativeUINodeSchema,
|
|
1658
|
-
z.array(generativeUINodeSchema).min(1),
|
|
1659
|
-
]),
|
|
1660
|
-
});
|
|
1661
|
-
|
|
1662
|
-
export const renderGuiToolInputSchema = z.object({
|
|
1663
|
-
spec: generativeUISpecSchema,
|
|
1664
|
-
});
|
|
1665
|
-
|
|
1666
|
-
export const renderGuiToolResultSchema = renderGuiToolInputSchema;
|
|
1667
|
-
|
|
1668
|
-
export const parseRenderGuiResult = (
|
|
1669
|
-
result: unknown,
|
|
1670
|
-
): GenerativeUISpec | undefined => {
|
|
1671
|
-
const parsed = renderGuiToolResultSchema.safeParse(result);
|
|
1672
|
-
return parsed.success ? (parsed.data.spec as GenerativeUISpec) : undefined;
|
|
1673
|
-
};
|
|
1674
|
-
|
|
1675
|
-
export const renderGuiToolDescription =
|
|
1676
|
-
"Compose inline UI from the allowlisted component library (Card, Text, Button, Stack, Stat, Heading). " +
|
|
1677
|
-
"Pass a JSON spec with a root node tree. Use for dashboards, status panels, and structured layouts — not for user input forms (use interactive tool UI instead).";
|
|
1678
|
-
|
|
1679
|
-
export const renderGuiChatInstructions =
|
|
1680
|
-
"When the user asks for UI, call render_gui with the spec. " +
|
|
1681
|
-
"Do not paste JSON, code blocks, or the tool result in your text reply — the client renders the UI from the tool output automatically. " +
|
|
1682
|
-
"Keep any text reply brief or omit it when the UI alone answers the request.";
|
|
1683
|
-
|
|
1684
|
-
const stripMarkdownJsonFence = (text: string): string => {
|
|
1685
|
-
const trimmed = text.trim();
|
|
1686
|
-
const match = trimmed.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?```\s*$/i);
|
|
1687
|
-
return match ? match[1]!.trim() : trimmed;
|
|
1688
|
-
};
|
|
1689
|
-
|
|
1690
|
-
/** Text echo of a render_gui tool result/spec — hide when the bridge already rendered it. */
|
|
1691
|
-
export const isLeakedRenderGuiText = (text: string): boolean => {
|
|
1692
|
-
const candidate = stripMarkdownJsonFence(text);
|
|
1693
|
-
if (!candidate.startsWith("{")) return false;
|
|
1694
|
-
|
|
1695
|
-
try {
|
|
1696
|
-
const parsed = JSON.parse(candidate);
|
|
1697
|
-
if (renderGuiToolResultSchema.safeParse(parsed).success) return true;
|
|
1698
|
-
if (generativeUISpecSchema.safeParse(parsed).success) return true;
|
|
1699
|
-
} catch {
|
|
1700
|
-
return false;
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
return false;
|
|
1704
|
-
};
|
|
1705
|
-
|
|
1706
|
-
```
|
|
1707
|
-
|
|
1708
|
-
## next.config.ts
|
|
1709
|
-
|
|
1710
|
-
```typescript
|
|
1711
|
-
import { withAui } from "@assistant-ui/next";
|
|
1712
|
-
import type { NextConfig } from "next";
|
|
1713
|
-
|
|
1714
|
-
const nextConfig: NextConfig = {/* config options here */};
|
|
1715
|
-
|
|
1716
|
-
export default withAui(nextConfig);
|
|
1717
|
-
|
|
1718
|
-
```
|
|
1719
|
-
|
|
1720
|
-
## package.json
|
|
1721
|
-
|
|
1722
|
-
```json
|
|
1723
|
-
{
|
|
1724
|
-
"name": "with-generative-ui",
|
|
1725
|
-
"version": "0.0.0",
|
|
1726
|
-
"private": true,
|
|
1727
|
-
"type": "module",
|
|
1728
|
-
"scripts": {
|
|
1729
|
-
"dev": "next dev",
|
|
1730
|
-
"build": "next build",
|
|
1731
|
-
"start": "next start",
|
|
1732
|
-
"test": "vitest run"
|
|
1733
|
-
},
|
|
1734
|
-
"dependencies": {
|
|
1735
|
-
"@ai-sdk/openai": "^4.0.46",
|
|
1736
|
-
"@assistant-ui/ai-sdk": "workspace:*",
|
|
1737
|
-
"@assistant-ui/react": "workspace:*",
|
|
1738
|
-
"@assistant-ui/react-generative-ui": "workspace:*",
|
|
1739
|
-
"@assistant-ui/ui": "workspace:*",
|
|
1740
|
-
"ai": "^7.0.77",
|
|
1741
|
-
"class-variance-authority": "^0.7.1",
|
|
1742
|
-
"clsx": "^2.1.1",
|
|
1743
|
-
"lucide-react": "^1.33.0",
|
|
1744
|
-
"next": "^16.3.2",
|
|
1745
|
-
"react": "^19.2.8",
|
|
1746
|
-
"react-dom": "^19.2.8",
|
|
1747
|
-
"recharts": "^3.10.1",
|
|
1748
|
-
"tailwind-merge": "^3.6.0",
|
|
1749
|
-
"zod": "^4.4.3"
|
|
1750
|
-
},
|
|
1751
|
-
"devDependencies": {
|
|
1752
|
-
"@assistant-ui/next": "workspace:*",
|
|
1753
|
-
"@assistant-ui/x-buildutils": "workspace:*",
|
|
1754
|
-
"@tailwindcss/postcss": "^4.3.3",
|
|
1755
|
-
"@types/node": "^26.2.0",
|
|
1756
|
-
"@types/react": "^19.2.18",
|
|
1757
|
-
"@types/react-dom": "^19.2.5",
|
|
1758
|
-
"postcss": "^8.5.26",
|
|
1759
|
-
"tailwindcss": "^4.3.3",
|
|
1760
|
-
"tw-animate-css": "^1.4.0",
|
|
1761
|
-
"typescript": "^7.0.2",
|
|
1762
|
-
"vitest": "^4.1.11"
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
```
|
|
1767
|
-
|
|
1768
|
-
## tsconfig.json
|
|
1769
|
-
|
|
1770
|
-
```json
|
|
1771
|
-
{
|
|
1772
|
-
"extends": "@assistant-ui/x-buildutils/ts/next",
|
|
1773
|
-
"compilerOptions": {
|
|
1774
|
-
"paths": {
|
|
1775
|
-
"@/*": ["./*"],
|
|
1776
|
-
"@/components/assistant-ui/*": [
|
|
1777
|
-
"../../packages/ui/src/components/assistant-ui/*"
|
|
1778
|
-
],
|
|
1779
|
-
"@/hooks/*": ["../../packages/ui/src/hooks/*"],
|
|
1780
|
-
"@/components/ui/*": [
|
|
1781
|
-
"../../packages/ui/src/components/ui/base/*",
|
|
1782
|
-
"../../packages/ui/src/components/ui/radix/*"
|
|
1783
|
-
],
|
|
1784
|
-
"@/components/ui/radix/*": [
|
|
1785
|
-
"../../packages/ui/src/components/ui/radix/*"
|
|
1786
|
-
],
|
|
1787
|
-
"@/lib/utils": ["../../packages/ui/src/lib/utils"],
|
|
1788
|
-
"@assistant-ui/ui/*": ["../../packages/ui/src/*"]
|
|
1789
|
-
}
|
|
1790
|
-
},
|
|
1791
|
-
"include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
1792
|
-
"exclude": ["node_modules"]
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
```
|
|
1796
|
-
|
|
1797
|
-
## vitest.config.ts
|
|
1798
|
-
|
|
1799
|
-
```typescript
|
|
1800
|
-
import { defineConfig } from "vitest/config";
|
|
1801
|
-
|
|
1802
|
-
export default defineConfig({
|
|
1803
|
-
test: {
|
|
1804
|
-
environment: "node",
|
|
1805
|
-
include: ["lib/**/*.test.ts"],
|
|
1806
|
-
},
|
|
1807
|
-
});
|
|
1808
|
-
|
|
1809
|
-
```
|
|
1810
|
-
|