@kitn.ai/ui 0.20.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -45
- package/dist/components/artifact-card.d.ts +51 -0
- package/dist/components/artifact.d.ts +1 -1
- package/dist/components/attachments.d.ts +2 -2
- package/dist/components/audio-visualizer/index.d.ts +3 -3
- package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
- package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
- package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
- package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
- package/dist/components/card-fallback.d.ts +12 -2
- package/dist/components/card-renderer.d.ts +63 -2
- package/dist/components/chat-container.d.ts +3 -0
- package/dist/components/chat-scope-picker.d.ts +2 -2
- package/dist/components/chat-thread.d.ts +77 -18
- package/dist/components/choice-card.d.ts +3 -28
- package/dist/components/composer-dom.d.ts +1 -1
- package/dist/components/composer-highlight.d.ts +1 -1
- package/dist/components/composer-history.d.ts +1 -1
- package/dist/components/composer.d.ts +1 -1
- package/dist/components/confirm-card.d.ts +3 -18
- package/dist/components/context.d.ts +8 -4
- package/dist/components/conversation-item.d.ts +1 -1
- package/dist/components/conversation-list.d.ts +4 -3
- package/dist/components/embed.d.ts +3 -3
- package/dist/components/file-tree.d.ts +11 -22
- package/dist/components/form-widgets.d.ts +1 -1
- package/dist/components/form.d.ts +3 -44
- package/dist/components/link-preview.d.ts +3 -3
- package/dist/components/loader.d.ts +30 -48
- package/dist/components/message-skills.d.ts +4 -0
- package/dist/components/message.d.ts +84 -21
- package/dist/components/model-switcher.d.ts +2 -2
- package/dist/components/prompt-input.d.ts +2 -2
- package/dist/components/response-compare-types.d.ts +11 -2
- package/dist/components/response-compare.d.ts +3 -3
- package/dist/components/source.d.ts +12 -3
- package/dist/components/tasks-card.d.ts +3 -31
- package/dist/components/thread.d.ts +17 -5
- package/dist/components/toast.d.ts +2 -2
- package/dist/components/tool-classify.d.ts +8 -0
- package/dist/components/tool-types.d.ts +29 -1
- package/dist/components/tool.d.ts +3 -3
- package/dist/components/use-card-resolution.d.ts +1 -1
- package/dist/create-tween-COnPwAQN.js +338 -0
- package/dist/create-tween-DmTUaXWE.js +341 -0
- package/dist/create-tween-qs-jjvNA.js +7 -0
- package/dist/custom-elements.json +1726 -463
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- package/dist/elements/card.js +1 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-types.d.ts +70 -10
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- package/dist/elements/chunks/{Icon-Tj58ES_d.js → Icon-CHG5z5L7.js} +1 -1
- package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-BAtCEEgg.js} +1 -1
- package/dist/elements/chunks/arrow-left-CFPTeL1Y.js +1 -0
- package/dist/elements/chunks/artifact-fBZOE4SO.js +1 -0
- package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-DpYMe5VQ.js} +1 -1
- package/dist/elements/chunks/audio-visualizer-DFwzAcuL.js +1 -0
- package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-D6zodm6E.js} +1 -1
- package/dist/elements/chunks/{button-ZWNif3--.js → button-C42vrGvO.js} +1 -1
- package/dist/elements/chunks/card-renderer-DMZsSuvU.js +1 -0
- package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
- package/dist/elements/chunks/chat-thread-CNNEhol-.js +1 -0
- package/dist/elements/chunks/check-7Q3K-iXE.js +1 -0
- package/dist/elements/chunks/chevron-down-CpNYLn7E.js +1 -0
- package/dist/elements/chunks/chevron-right-DrH85Fha.js +1 -0
- package/dist/elements/chunks/choice-card-YoWjpsFV.js +1 -0
- package/dist/elements/chunks/circle-C9KRjKYv.js +1 -0
- package/dist/elements/chunks/circle-check-Dmi7Y4zw.js +1 -0
- package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-QIxXda6k.js} +1 -1
- package/dist/elements/chunks/code-block-CqeugReY.js +1 -0
- package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-sTv-_5lF.js} +1 -1
- package/dist/elements/chunks/{composer-BguS0QL_.js → composer-ldQyeVEB.js} +2 -2
- package/dist/elements/chunks/confirm-card-C0RNOwfn.js +1 -0
- package/dist/elements/chunks/context-5qgypNHC.js +1 -0
- package/dist/elements/chunks/conversation-list-DLzOacXz.js +1 -0
- package/dist/elements/chunks/create-tween-V4TXZ93X.js +7 -0
- package/dist/elements/chunks/default-input-DeeRSDHc.js +1 -0
- package/dist/elements/chunks/define-lE-QvQFn.js +1 -0
- package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DZSa9jog.js} +1 -1
- package/dist/elements/chunks/{download-Dsbg3ste.js → download-B2ZmnGqW.js} +1 -1
- package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-R3B7cSRE.js} +1 -1
- package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BmxceY4l.js} +1 -1
- package/dist/elements/chunks/embed-BVrtTZPo.js +1 -0
- package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-BbdR7YO7.js} +1 -1
- package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-D7dijo1A.js} +1 -1
- package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-0upJ5jeb.js} +1 -1
- package/dist/elements/chunks/{folder-glP5rha4.js → folder-D8z58t7B.js} +1 -1
- package/dist/elements/chunks/form-p5BKJNw5.js +1 -0
- package/dist/elements/chunks/hover-card-CN9s2md5.js +1 -0
- package/dist/elements/chunks/{icon-BLb8beoi.js → icon-CNiKP37E.js} +1 -1
- package/dist/elements/chunks/{info-CIsv92JK.js → info-BSnuJiHI.js} +1 -1
- package/dist/elements/chunks/{input-Dds1kFyt.js → input-BauDmzxX.js} +1 -1
- package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-BlHJaP9b.js} +1 -1
- package/dist/elements/chunks/{link-i4r_k7z4.js → link-DEi5iUWC.js} +1 -1
- package/dist/elements/chunks/link-preview-BaHyM6W4.js +1 -0
- package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-CmJG_Fkq.js} +1 -1
- package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-D2jaMpCN.js} +1 -1
- package/dist/elements/chunks/message-C5UfXZ2Z.js +1 -0
- package/dist/elements/chunks/message-CXWLmmLn.js +1 -0
- package/dist/elements/chunks/message-square-hXylwsy0.js +1 -0
- package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-C9ytZFMU.js} +1 -1
- package/dist/elements/chunks/model-switcher-CivGfD7-.js +1 -0
- package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-DJL_sbOm.js} +1 -1
- package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CFaB8naM.js} +1 -1
- package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-Br5SksfR.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-CMIvtAhU.js} +1 -1
- package/dist/elements/chunks/reasoning-DpZcNzLq.js +1 -0
- package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-Q8i3T9a_.js} +1 -1
- package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-B5IHCBFV.js} +1 -1
- package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-eLeydBje.js} +1 -1
- package/dist/elements/chunks/scroll-button-DWbz0yA1.js +1 -0
- package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-Xic78AD_.js} +1 -1
- package/dist/elements/chunks/{settings-B8lmec4D.js → settings-B8H51pAx.js} +1 -1
- package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-CsG9eYLe.js} +1 -1
- package/dist/elements/chunks/{share-C3lTiYGt.js → share-CNTx0z__.js} +1 -1
- package/dist/elements/chunks/skeleton-CLlHTcMI.js +1 -0
- package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
- package/dist/elements/chunks/source-BoVcU5ok.js +1 -0
- package/dist/elements/chunks/{star-CSJtGxgv.js → star-CxQVTVhI.js} +1 -1
- package/dist/elements/chunks/{store-CHyW95TP.js → store-CLtS5CUG.js} +1 -1
- package/dist/elements/chunks/tasks-card-CzlkLmUt.js +1 -0
- package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D5NhpIQ1.js} +1 -1
- package/dist/elements/chunks/textarea-x5Uxsmtm.js +1 -0
- package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-UobcJnx9.js} +1 -1
- package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-BOfs9eXq.js} +1 -1
- package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-Be6Dh_dt.js} +1 -1
- package/dist/elements/chunks/tooltip-RxMxyCLF.js +1 -0
- package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C4yxH2XN.js} +1 -1
- package/dist/elements/chunks/use-card-resolution-jva9ehH6.js +1 -0
- package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Dx4VRcjS.js} +2 -2
- package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-Y1ZTWgEa.js} +1 -1
- package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-B9gml9Cg.js} +2 -2
- package/dist/elements/chunks/{video-B7vmenoC.js → video-CrPHsytT.js} +1 -1
- package/dist/elements/chunks/x-_-OPHept.js +1 -0
- package/dist/elements/coachmark.js +1 -1
- package/dist/elements/code-block.js +1 -1
- package/dist/elements/command.js +1 -1
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.js +1 -1
- package/dist/elements/confirm-card.js +1 -1
- package/dist/elements/context-meter.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/default-input.d.ts +34 -7
- package/dist/elements/define.d.ts +1 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/disclosure.d.ts +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +107 -0
- package/dist/elements/embed.js +1 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- package/dist/elements/hover-card.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- package/dist/elements/link-preview.js +1 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.js +1 -1
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- package/dist/elements/nav.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-group.js +1 -1
- package/dist/elements/pane.js +1 -1
- package/dist/elements/popover.js +1 -1
- package/dist/elements/progress-bar.js +1 -1
- package/dist/elements/prompt-dock.js +1 -1
- package/dist/elements/prompt-input.js +1 -1
- package/dist/elements/prompt-suggestions.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/register.d.ts +8 -6
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +1 -1
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/separator.js +1 -1
- package/dist/elements/setting-item.js +1 -1
- package/dist/elements/settings-group.js +1 -1
- package/dist/elements/skeleton.js +1 -1
- package/dist/elements/slot-text.d.ts +51 -0
- package/dist/elements/slots.d.ts +21 -0
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/validate-messages.d.ts +25 -0
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +2734 -217
- package/dist/index.d.ts +163 -125
- package/dist/index.js +6572 -5990
- package/dist/index.server.d.ts +5 -0
- package/dist/index.server.js +5403 -4860
- package/dist/kai-provider.es.d.ts +5 -0
- package/dist/kai-provider.es.js +79 -77
- package/dist/kai.es.d.ts +5 -0
- package/dist/kai.es.js +1 -1
- package/dist/llms/llms-full.txt +774 -151
- package/dist/llms/llms.txt +57 -5
- package/dist/mcp.es.js +4756 -782
- package/dist/primitives/card-component-types.d.ts +11 -0
- package/dist/primitives/card-data-types.d.ts +196 -0
- package/dist/primitives/card-host.d.ts +1 -1
- package/dist/primitives/card-recovery.d.ts +3 -3
- package/dist/primitives/card-registry.d.ts +4 -14
- package/dist/primitives/card-resolution.d.ts +1 -1
- package/dist/primitives/card-routing.d.ts +1 -1
- package/dist/primitives/card-tags.d.ts +11 -0
- package/dist/primitives/card-validate-cards.d.ts +57 -0
- package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
- package/dist/primitives/card-validate-schemas.d.ts +17 -0
- package/dist/primitives/card-validate.d.ts +24 -0
- package/dist/primitives/create-kai-chat.d.ts +3 -3
- package/dist/primitives/embed-providers.d.ts +1 -1
- package/dist/primitives/link-preview.d.ts +1 -1
- package/dist/primitives/message-feedback.d.ts +2 -2
- package/dist/primitives/toast-store.d.ts +1 -1
- package/dist/react/index.d.ts +730 -302
- package/dist/react/use-kai-chat.d.ts +8 -4
- package/dist/react.d.ts +5 -0
- package/dist/react.js +418 -317
- package/dist/register-impl-AxIlqjo7.js +145 -0
- package/dist/remote/host-embed.d.ts +1 -1
- package/dist/remote/index.d.ts +2 -2
- package/dist/remote/provider-runtime.d.ts +2 -2
- package/dist/remote/provider.d.ts +2 -2
- package/dist/remote/validate.d.ts +1 -1
- package/dist/remote/wire.d.ts +1 -1
- package/dist/schemas/artifact.schema.json +92 -0
- package/dist/schemas/embed.schema.json +0 -2
- package/dist/schemas/from-tool-call.d.ts +48 -0
- package/dist/schemas/index.d.ts +48 -0
- package/dist/schemas/link.schema.json +0 -2
- package/dist/schemas/provider-subsets.d.ts +136 -0
- package/dist/schemas/registry.d.ts +140 -0
- package/dist/schemas/tool-defs.d.ts +121 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.js +717 -0
- package/dist/solid-BGYSJyHG.js +22960 -0
- package/dist/solid-Dt2nEwfl.js +20194 -0
- package/dist/solid.d.ts +66 -0
- package/dist/solid.js +261 -0
- package/dist/solid.server.d.ts +5 -0
- package/dist/solid.server.js +261 -0
- package/dist/state/index.d.ts +14 -4
- package/dist/state/messages.d.ts +8 -3
- package/dist/state/mock.d.ts +46 -0
- package/dist/state/parts.d.ts +85 -0
- package/dist/state/stream.d.ts +15 -9
- package/dist/state.d.ts +5 -0
- package/dist/state.js +253 -84
- package/dist/ui/action-icons.d.ts +1 -1
- package/dist/ui/collapsible.d.ts +11 -6
- package/dist/ui/dropdown.d.ts +47 -42
- package/dist/ui/pane-group.d.ts +1 -1
- package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-B44X69AG.js} +1 -1
- package/dist/variant-aurora-BRhV8Flk.js +391 -0
- package/dist/variant-aurora-Ds5ou9BH.js +381 -0
- package/dist/variant-custom-B20FhtYj.js +170 -0
- package/dist/{variant-custom-Dif-IV4u.js → variant-custom-BvA1Schl.js} +1 -1
- package/dist/variant-custom-D6Rtvneb.js +200 -0
- package/dist/{variant-wave-DbfNdvSi.js → variant-wave-BUQtkryq.js} +1 -1
- package/dist/variant-wave-BVYnqy9L.js +218 -0
- package/dist/variant-wave-DXC6_LcH.js +208 -0
- package/dist/wire/chunk.d.ts +171 -0
- package/dist/wire/consume.d.ts +26 -0
- package/dist/wire/encode.d.ts +221 -0
- package/dist/wire/files.d.ts +116 -0
- package/dist/wire/formats/anthropic.d.ts +2 -0
- package/dist/wire/formats/openai.d.ts +5 -0
- package/dist/wire/index.d.ts +16 -0
- package/dist/wire/media-types.d.ts +106 -0
- package/dist/wire/read.d.ts +26 -0
- package/dist/wire/sink-helpers.d.ts +21 -0
- package/dist/wire/sse.d.ts +33 -0
- package/dist/wire.d.ts +5 -53
- package/dist/wire.js +1126 -0
- package/frameworks/react/index.tsx +191 -158
- package/frameworks/react/runtime.tsx +21 -1
- package/frameworks/react/use-kai-chat.tsx +11 -1
- package/llms-full.txt +774 -151
- package/llms.txt +57 -5
- package/package.json +62 -8
- package/src/agent-tooling/archetypes.ts +127 -0
- package/src/agent-tooling/integrations/anthropic.ts +436 -0
- package/src/agent-tooling/integrations/cloudflare.ts +141 -52
- package/src/agent-tooling/integrations/langgraph.ts +80 -13
- package/src/agent-tooling/integrations/mastra.ts +161 -12
- package/src/agent-tooling/integrations/mock.ts +47 -8
- package/src/agent-tooling/integrations/ollama.ts +68 -24
- package/src/agent-tooling/integrations/openai.ts +89 -0
- package/src/agent-tooling/integrations/openrouter.ts +58 -8
- package/src/agent-tooling/integrations/pi.ts +104 -23
- package/src/agent-tooling/integrations/pydantic-ai.ts +61 -5
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +120 -13
- package/src/agent-tooling/mcp/manifest.ts +206 -25
- package/src/agent-tooling/mcp/tools/debug.ts +13 -7
- package/src/agent-tooling/mcp/tools/reference.ts +285 -6
- package/src/agent-tooling/mcp/tools/scaffold.ts +4152 -661
- package/src/agent-tooling/registry.ts +74 -0
- package/src/agent-tooling/types.ts +361 -1
- package/src/components/artifact-card.tsx +120 -0
- package/src/components/audio-visualizer/index.tsx +9 -0
- package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
- package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
- package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
- package/src/components/card-fallback.tsx +42 -10
- package/src/components/card-renderer.tsx +146 -9
- package/src/components/chat-container.tsx +4 -0
- package/src/components/chat-thread.tsx +128 -52
- package/src/components/choice-card.tsx +17 -29
- package/src/components/composer.tsx +12 -2
- package/src/components/confirm-card.tsx +24 -20
- package/src/components/context.tsx +30 -16
- package/src/components/conversation-item.tsx +6 -0
- package/src/components/conversation-list.tsx +18 -2
- package/src/components/file-tree.tsx +11 -22
- package/src/components/file-upload.tsx +14 -8
- package/src/components/form.tsx +14 -47
- package/src/components/loader.tsx +39 -12
- package/src/components/message-skills.tsx +4 -0
- package/src/components/message.tsx +294 -46
- package/src/components/model-switcher.tsx +38 -8
- package/src/components/reasoning.tsx +92 -5
- package/src/components/response-compare-types.ts +25 -0
- package/src/components/response-compare.tsx +4 -9
- package/src/components/source.tsx +50 -24
- package/src/components/tasks-card.tsx +10 -33
- package/src/components/thread.tsx +84 -42
- package/src/components/toast.tsx +17 -6
- package/src/components/tool-classify.ts +26 -0
- package/src/components/tool-types.ts +31 -1
- package/src/elements/agent-card.tsx +11 -11
- package/src/elements/artifact.tsx +15 -7
- package/src/elements/attachments.tsx +6 -4
- package/src/elements/avatar.tsx +1 -1
- package/src/elements/button.tsx +29 -6
- package/src/elements/card.tsx +2 -2
- package/src/elements/cards.tsx +109 -14
- package/src/elements/chain-of-thought.tsx +14 -10
- package/src/elements/chat-scope-picker.tsx +9 -7
- package/src/elements/chat-types.ts +59 -6
- package/src/elements/chat-workspace.tsx +50 -9
- package/src/elements/chat.tsx +90 -3
- package/src/elements/choice.tsx +8 -8
- package/src/elements/coachmark.tsx +1 -1
- package/src/elements/command.tsx +8 -23
- package/src/elements/compare.tsx +7 -6
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +8 -8
- package/src/elements/confirm-card.tsx +9 -9
- package/src/elements/context-meter.tsx +4 -18
- package/src/elements/conversation-list.tsx +14 -9
- package/src/elements/default-input.tsx +131 -8
- package/src/elements/define.tsx +178 -43
- package/src/elements/editable-label.tsx +17 -2
- package/src/elements/element-data-types.ts +112 -0
- package/src/elements/element-meta.json +1624 -306
- package/src/elements/element-types.d.ts +2645 -214
- package/src/elements/feedback-bar.tsx +1 -1
- package/src/elements/file-tree.tsx +1 -1
- package/src/elements/file-upload.tsx +1 -1
- package/src/elements/form.tsx +14 -6
- package/src/elements/input.tsx +1 -1
- package/src/elements/kbd.tsx +1 -1
- package/src/elements/menu.tsx +40 -32
- package/src/elements/message-skills.tsx +7 -9
- package/src/elements/message.tsx +200 -32
- package/src/elements/model-switcher.tsx +5 -3
- package/src/elements/pane.tsx +1 -1
- package/src/elements/prompt-dock.tsx +8 -8
- package/src/elements/prompt-input.tsx +10 -10
- package/src/elements/prompt-suggestions.tsx +7 -4
- package/src/elements/reasoning.tsx +1 -1
- package/src/elements/register.ts +9 -0
- package/src/elements/resizable.globals.d.ts +36 -0
- package/src/elements/resizable.tsx +24 -13
- package/src/elements/response-stream.tsx +1 -1
- package/src/elements/scroll-button.tsx +1 -1
- package/src/elements/search.tsx +6 -1
- package/src/elements/segmented.tsx +5 -11
- package/src/elements/separator.tsx +1 -1
- package/src/elements/slot-text.ts +73 -0
- package/src/elements/slots.ts +67 -24
- package/src/elements/source.tsx +21 -22
- package/src/elements/switch.tsx +3 -3
- package/src/elements/tasks.tsx +5 -4
- package/src/elements/thread.tsx +36 -4
- package/src/elements/toast.tsx +3 -2
- package/src/elements/tool.tsx +1 -1
- package/src/elements/validate-messages.ts +76 -0
- package/src/elements/voice-input.tsx +7 -7
- package/src/elements/voice-output.tsx +4 -4
- package/src/index.ts +145 -6
- package/src/primitives/card-component-types.ts +63 -0
- package/src/primitives/card-data-types.ts +312 -0
- package/src/primitives/card-recovery.ts +13 -2
- package/src/primitives/card-registry.tsx +34 -23
- package/src/primitives/card-schemas/artifact.schema.json +92 -0
- package/src/primitives/card-schemas/embed.schema.json +0 -2
- package/src/primitives/card-schemas/link.schema.json +0 -2
- package/src/primitives/card-tags.ts +61 -0
- package/src/primitives/card-validate-cards.ts +255 -0
- package/src/primitives/card-validate-generator.testlib.ts +38 -0
- package/src/primitives/card-validate-schemas.ts +58 -0
- package/src/primitives/card-validate.ts +48 -20
- package/src/primitives/create-tween.ts +54 -2
- package/src/primitives/message-feedback.ts +3 -2
- package/src/primitives/use-audio-analysis.ts +20 -1
- package/src/primitives/use-sequencer.ts +20 -1
- package/src/schemas/from-tool-call.ts +151 -0
- package/src/schemas/index.ts +340 -0
- package/src/schemas/provider-subsets.ts +538 -0
- package/src/schemas/registry.ts +355 -0
- package/src/schemas/tool-defs.ts +492 -0
- package/src/solid.ts +150 -0
- package/src/state/index.ts +27 -1
- package/src/state/messages.ts +21 -4
- package/src/state/mock.ts +211 -0
- package/src/state/parts.ts +295 -0
- package/src/state/stream.ts +56 -58
- package/src/ui/collapsible.tsx +17 -5
- package/src/ui/dropdown.tsx +46 -12
- package/src/ui/overlay.tsx +10 -4
- package/src/wire/chunk.ts +201 -0
- package/src/wire/consume.ts +440 -0
- package/src/wire/encode.ts +689 -0
- package/src/wire/files.ts +342 -0
- package/src/wire/formats/anthropic.ts +267 -0
- package/src/wire/formats/openai.ts +187 -0
- package/src/wire/index.ts +73 -0
- package/src/wire/media-types.ts +344 -0
- package/src/wire/read.ts +152 -0
- package/src/wire/sink-helpers.ts +50 -0
- package/src/wire/sse.ts +140 -0
- package/dist/create-tween-hvpmSuwW.js +0 -7
- package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
- package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
- package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
- package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
- package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
- package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
- package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
- package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
- package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
- package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
- package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
- package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
- package/dist/elements/chunks/default-input-Cqqilg9t.js +0 -1
- package/dist/elements/chunks/define-D1din7Ld.js +0 -1
- package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
- package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
- package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
- package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
- package/dist/elements/chunks/model-switcher-B94YAKsM.js +0 -1
- package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
- package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
- package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
- package/dist/elements/chunks/slots--V19HwUb.js +0 -1
- package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
- package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
- package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
- package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
- package/dist/host-embed.d.ts +0 -33
- package/dist/kai-provider.d.ts +0 -2
- package/dist/origin.d.ts +0 -5
- package/dist/provider-runtime.d.ts +0 -27
- package/dist/register-impl-DQyejdfb.js +0 -145
- package/dist/validate.d.ts +0 -4
- package/dist/version.d.ts +0 -4
- package/src/components/component-meta.json +0 -4550
- package/src/elements/card-media.jpg +0 -0
- package/src/elements/resizable.d.ts +0 -27
- package/src/elements/video-poster.jpg +0 -0
|
@@ -2,16 +2,48 @@
|
|
|
2
2
|
* manifest.ts — reads dist/custom-elements.json (a Custom Elements Manifest)
|
|
3
3
|
* and exposes helpers for the component_reference tool.
|
|
4
4
|
*
|
|
5
|
-
* Resolution strategy (dual-context)
|
|
5
|
+
* Resolution strategy (dual-context) — each context is an EXACT location, never a
|
|
6
|
+
* search. See `resolveManifestPath` for why that distinction is the whole point:
|
|
6
7
|
* 1. Bundled bin: dist/mcp.es.js lives in dist/, so custom-elements.json is
|
|
7
|
-
* a sibling →
|
|
8
|
-
* 2. Vitest (source): manifest.ts lives
|
|
9
|
-
*
|
|
8
|
+
* a sibling → ./custom-elements.json relative to import.meta.url.
|
|
9
|
+
* 2. Vitest (source): manifest.ts lives at <package>/src/agent-tooling/mcp/, so
|
|
10
|
+
* the manifest is <package>/dist/custom-elements.json and nowhere else.
|
|
11
|
+
*
|
|
12
|
+
* It also answers "which of these 80 elements has anything to do with cards", for
|
|
13
|
+
* the card contract component_reference serves. That question lives HERE rather than
|
|
14
|
+
* in reference.ts because half of it is a question about the element manifest — the
|
|
15
|
+
* kit's own `type -> tag` map, crossed against the tag list this module already owns
|
|
16
|
+
* — and because both halves of the answer must come off one place. See
|
|
17
|
+
* `cardTagForType` for the rule and for what happens when an eighth card type lands.
|
|
10
18
|
*/
|
|
11
19
|
|
|
12
20
|
import { readFileSync, existsSync } from 'node:fs';
|
|
13
21
|
import { fileURLToPath } from 'node:url';
|
|
14
|
-
import { join, dirname } from 'node:path';
|
|
22
|
+
import { join, dirname, resolve } from 'node:path';
|
|
23
|
+
// The package's own public entry, by the same specifier the scaffolder tells a
|
|
24
|
+
// consumer's route to use. That is now a CHOICE, and this comment used to say the
|
|
25
|
+
// opposite: the barrel re-exports src/schemas/registry.ts, which type-IMPORTED
|
|
26
|
+
// `CardComponentMap` from src/primitives/card-registry.TSX, and pulling a .tsx into
|
|
27
|
+
// this pass would mean giving tsconfig.mcp.json `jsx` + `jsxImportSource` + the DOM
|
|
28
|
+
// lib, dragging the whole Solid component tree into a Node-only project — measured
|
|
29
|
+
// as 0 errors -> 1364. Those two types moved to the DOM-free
|
|
30
|
+
// src/primitives/card-component-types.ts, so a relative import of the barrel would
|
|
31
|
+
// typecheck here today. It stays on the public specifier anyway, because emitting
|
|
32
|
+
// and consuming the same string is the point of this module. The built entry
|
|
33
|
+
// resolves to dist/schemas/index.d.ts, whose own reference to card-registry is a
|
|
34
|
+
// .d.ts that skipLibCheck skips, so the Node/no-DOM guarantee survives intact.
|
|
35
|
+
//
|
|
36
|
+
// `BUILTIN_CARD_TAGS` is the authoritative `CardEnvelope.type -> kai-* tag` map and
|
|
37
|
+
// arrives here as DATA, not a type. It is authored in src/primitives/card-tags.ts,
|
|
38
|
+
// which holds that map ALONE — no Solid below it — so it is readable from source by a
|
|
39
|
+
// Node/no-DOM project rather than only through this built entry. Before that split it
|
|
40
|
+
// shared a module with `BUILTIN_CARD_COMPONENTS` and this module re-derived it by
|
|
41
|
+
// convention instead; see `cardTagForType`.
|
|
42
|
+
//
|
|
43
|
+
// This costs a build before typecheck and before the unit suite. That is not a new
|
|
44
|
+
// dependency: resolveManifestPath() below already requires dist/custom-elements.json,
|
|
45
|
+
// and CI already runs `nx build ui` ahead of both.
|
|
46
|
+
import { BUILTIN_CARD_TAGS, cardSchemaNames } from '@kitn.ai/ui/schemas';
|
|
15
47
|
|
|
16
48
|
// ── CEM types ────────────────────────────────────────────────────────────────
|
|
17
49
|
|
|
@@ -81,32 +113,95 @@ interface CustomElementsManifest {
|
|
|
81
113
|
}
|
|
82
114
|
|
|
83
115
|
// ── Manifest resolution ───────────────────────────────────────────────────────
|
|
116
|
+
//
|
|
117
|
+
// THE MANIFEST IS THIS PACKAGE'S OWN BUILD ARTIFACT, SO IT IS ADDRESSED, NOT SEARCHED
|
|
118
|
+
// FOR. This used to walk up ten parent directories taking the first
|
|
119
|
+
// `<dir>/dist/custom-elements.json` it found, and that is a categorically weaker
|
|
120
|
+
// thing than it looks: "a custom-elements.json exists somewhere above me" and "THIS
|
|
121
|
+
// package's custom-elements.json exists" are different facts, and a walk-up cannot
|
|
122
|
+
// tell them apart. It reports success for both.
|
|
123
|
+
//
|
|
124
|
+
// It was not hypothetical. Measured from an agent git worktree at
|
|
125
|
+
// `<repo>/.claude/worktrees/<agent>/packages/ui/src/agent-tooling/mcp`, the loop
|
|
126
|
+
// climbed past the worktree's own (unbuilt) `packages/ui/dist`, out of the worktree
|
|
127
|
+
// entirely, and bound on iteration 8 to `<repo>/dist/custom-elements.json` — a
|
|
128
|
+
// leftover from the pre-monorepo layout, six weeks stale, 78 tags, and zero elements
|
|
129
|
+
// declaring `cardSchemas`. The consequence is this repo's dominant failure mode in
|
|
130
|
+
// its purest form: on an unbuilt tree the MCP manifest tests did not error, they
|
|
131
|
+
// PASSED, 16 of 17, against an artifact from a tree nobody was working in. Two
|
|
132
|
+
// checkouts could disagree about what they had tested and nothing said so.
|
|
133
|
+
//
|
|
134
|
+
// So the rule here is now: a missing manifest is a HARD FAILURE that names the path
|
|
135
|
+
// it expected. Never a fallback, never a wider search. If this throws, the answer is
|
|
136
|
+
// to build — not to let it find someone else's build.
|
|
137
|
+
|
|
138
|
+
const PACKAGE_NAME = '@kitn.ai/ui';
|
|
139
|
+
const MANIFEST_FILE = 'custom-elements.json';
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* `<package>/src/agent-tooling/mcp` -> `<package>`. A fixed, exact hop, and it is
|
|
143
|
+
* CHECKED below rather than trusted: if this module is ever moved to a different
|
|
144
|
+
* depth the derived root stops being this package and resolution throws, instead of
|
|
145
|
+
* silently addressing whatever directory happens to sit three levels up.
|
|
146
|
+
*/
|
|
147
|
+
const SOURCE_TO_PACKAGE_ROOT = ['..', '..', '..'] as const;
|
|
148
|
+
|
|
149
|
+
/** Is `root` the root of THIS package — not merely *a* directory holding a dist/? */
|
|
150
|
+
function isThisPackage(root: string): boolean {
|
|
151
|
+
const manifest = join(root, 'package.json');
|
|
152
|
+
if (!existsSync(manifest)) return false;
|
|
153
|
+
try {
|
|
154
|
+
return (JSON.parse(readFileSync(manifest, 'utf-8')) as { name?: string }).name === PACKAGE_NAME;
|
|
155
|
+
} catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
84
159
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Absolute path to this package's Custom Elements Manifest, or a throw naming what
|
|
162
|
+
* it looked for.
|
|
163
|
+
*
|
|
164
|
+
* `fromDir` exists for the tests and defaults to this module's own directory. It is
|
|
165
|
+
* the only way to write the check that matters: the guarantee is not "a manifest was
|
|
166
|
+
* found", it is "THIS package's manifest was found", and the two only come apart
|
|
167
|
+
* when there is a decoy above the origin. manifest.test.ts builds exactly that tree.
|
|
168
|
+
*/
|
|
169
|
+
export function resolveManifestPath(
|
|
170
|
+
fromDir: string = dirname(fileURLToPath(import.meta.url)),
|
|
171
|
+
): string {
|
|
172
|
+
// 1. Bundled bin: dist/mcp.es.js and dist/custom-elements.json are siblings.
|
|
173
|
+
// Unambiguous by construction — a sibling cannot be another checkout's artifact.
|
|
174
|
+
const sibling = join(fromDir, MANIFEST_FILE);
|
|
175
|
+
if (existsSync(sibling)) return sibling;
|
|
176
|
+
|
|
177
|
+
// 2. Source (vitest, tsx): one exact location, derived and then verified.
|
|
178
|
+
const packageRoot = resolve(fromDir, ...SOURCE_TO_PACKAGE_ROOT);
|
|
179
|
+
const expected = join(packageRoot, 'dist', MANIFEST_FILE);
|
|
88
180
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
181
|
+
if (!isThisPackage(packageRoot)) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`[${PACKAGE_NAME}] Cannot locate the Custom Elements Manifest: ${packageRoot} is not ` +
|
|
184
|
+
`the ${PACKAGE_NAME} package root, so ${expected} would not be this package's ` +
|
|
185
|
+
`manifest even if it existed.\n` +
|
|
186
|
+
`Resolved from: ${fromDir}\n` +
|
|
187
|
+
`This module must live at <package>/src/agent-tooling/mcp/ (or be bundled beside ` +
|
|
188
|
+
`${MANIFEST_FILE} in dist/). Resolution deliberately does NOT search parent ` +
|
|
189
|
+
`directories — finding some other checkout's manifest is worse than failing.`,
|
|
190
|
+
);
|
|
93
191
|
}
|
|
94
192
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
dir = parent;
|
|
193
|
+
if (!existsSync(expected)) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`[${PACKAGE_NAME}] Missing build artifact: ${expected}\n` +
|
|
196
|
+
`Resolved from: ${fromDir}\n` +
|
|
197
|
+
`The Custom Elements Manifest is generated by the build. Run \`nx build ui\` ` +
|
|
198
|
+
`(or \`npm run build:api\` in packages/ui) and try again.\n` +
|
|
199
|
+
`Resolution deliberately does NOT search parent directories: binding to a ` +
|
|
200
|
+
`neighbouring checkout's manifest would make this succeed against stale data.`,
|
|
201
|
+
);
|
|
105
202
|
}
|
|
106
203
|
|
|
107
|
-
|
|
108
|
-
`Could not find custom-elements.json. Searched from: ${thisDir}`,
|
|
109
|
-
);
|
|
204
|
+
return expected;
|
|
110
205
|
}
|
|
111
206
|
|
|
112
207
|
// ── Parsed manifest (module-level cache) ─────────────────────────────────────
|
|
@@ -140,3 +235,89 @@ export function listElements(): string[] {
|
|
|
140
235
|
.map((d) => d.tagName!)
|
|
141
236
|
.sort();
|
|
142
237
|
}
|
|
238
|
+
|
|
239
|
+
// ── Which elements have anything to do with cards ────────────────────────────
|
|
240
|
+
//
|
|
241
|
+
// Two different populations, and conflating them would be the "attaches card
|
|
242
|
+
// material to everything" failure:
|
|
243
|
+
//
|
|
244
|
+
// CARD-BACKED kai-confirm, kai-choice, … — one element per CardEnvelope.type.
|
|
245
|
+
// These get a schema and a generated tool definition.
|
|
246
|
+
// CARD HOST kai-chat, kai-message, … — the elements that RENDER a thread of
|
|
247
|
+
// cards and therefore carry the `cardTypes` / `cardSchemas` props.
|
|
248
|
+
// These get the wiring note, not a schema.
|
|
249
|
+
//
|
|
250
|
+
// Neither list is written down here. The host list is derived from the manifest; the
|
|
251
|
+
// card-backed one is the kit's own map, read rather than guessed at. Either way an
|
|
252
|
+
// eighth card type is covered the day it lands rather than the day someone remembers
|
|
253
|
+
// this file.
|
|
254
|
+
|
|
255
|
+
/** Cached derivations. Same lifetime as the parsed manifest above. */
|
|
256
|
+
let _cardTags: Map<string, string> | undefined;
|
|
257
|
+
let _cardHosts: string[] | undefined;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* `CardEnvelope.type` -> the `kai-*` element that renders it.
|
|
261
|
+
*
|
|
262
|
+
* THE MAP IS IMPORTED, NOT INFERRED. `BUILTIN_CARD_TAGS` is the same object
|
|
263
|
+
* `<kai-cards>` dispatches on in the browser, reached here through
|
|
264
|
+
* `@kitn.ai/ui/schemas`. This function used to RE-DERIVE it by convention — the tag
|
|
265
|
+
* is `kai-<t>` when that element exists, else the single element whose tag starts
|
|
266
|
+
* `kai-<t>-` — which was correct against all 80 tags on this tree, `link` ->
|
|
267
|
+
* `kai-link-preview` included, and was still a second copy of a fact the repo already
|
|
268
|
+
* held. The eighth card type is the one that would have broken it: any type whose tag
|
|
269
|
+
* is neither `kai-<t>` nor the sole `kai-<t>-*` had to be noticed by a human, and a
|
|
270
|
+
* future `kai-form-field` would have made `form` ambiguous on its own. A lookup has
|
|
271
|
+
* neither failure mode.
|
|
272
|
+
*
|
|
273
|
+
* WHY IT IS STILL CROSSED AGAINST THE MANIFEST. The map is authoritative for the
|
|
274
|
+
* ASSOCIATION; only the manifest knows what actually got registered. A tag in the map
|
|
275
|
+
* with no element behind it (a rename that missed this file) would otherwise have
|
|
276
|
+
* `component_reference` send a harness to an element that does not exist. Entries with
|
|
277
|
+
* no registered element are dropped, so the answer is a real tag or nothing.
|
|
278
|
+
*
|
|
279
|
+
* WHEN IT BREAKS, IT BREAKS LOUDLY. reference.test.ts asserts every member of
|
|
280
|
+
* `cardSchemaNames` resolves AND that what it resolves to is in `listElements()`, so a
|
|
281
|
+
* card type missing from the map, or pointed at a tag nobody registered, fails a test
|
|
282
|
+
* instead of silently losing its schema in the reference.
|
|
283
|
+
*/
|
|
284
|
+
export function cardTagForType(type: string): string | undefined {
|
|
285
|
+
if (!_cardTags) {
|
|
286
|
+
const present = new Set(listElements());
|
|
287
|
+
_cardTags = new Map(Object.entries(BUILTIN_CARD_TAGS).filter(([, tag]) => present.has(tag)));
|
|
288
|
+
}
|
|
289
|
+
return _cardTags.get(type);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** The inverse: which card type does this element render, if any. */
|
|
293
|
+
export function cardTypeForTag(tag: string): string | undefined {
|
|
294
|
+
for (const name of cardSchemaNames) {
|
|
295
|
+
if (cardTagForType(name) === tag) return name;
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* The elements that host a thread of cards, derived from the manifest: an element is
|
|
302
|
+
* a card host exactly when it declares the `cardSchemas` prop.
|
|
303
|
+
*
|
|
304
|
+
* That prop is the one that carries a developer's own card schemas into the browser
|
|
305
|
+
* validator, so "declares it" and "hosts cards" are the same fact rather than two
|
|
306
|
+
* facts that can disagree. Today it selects kai-chat / kai-message / kai-thread /
|
|
307
|
+
* kai-workspace; an element that grows the prop tomorrow joins without an edit here.
|
|
308
|
+
*/
|
|
309
|
+
export function cardHostTags(): string[] {
|
|
310
|
+
if (!_cardHosts) {
|
|
311
|
+
_cardHosts = getDeclarations()
|
|
312
|
+
.filter(
|
|
313
|
+
(d) =>
|
|
314
|
+
d.tagName !== undefined &&
|
|
315
|
+
(d.members ?? []).some(
|
|
316
|
+
(m) => m.kind === 'field' && m.privacy === 'public' && m.name === 'cardSchemas',
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
.map((d) => d.tagName!)
|
|
320
|
+
.sort();
|
|
321
|
+
}
|
|
322
|
+
return _cardHosts;
|
|
323
|
+
}
|
|
@@ -39,7 +39,7 @@ const RULES: Rule[] = [
|
|
|
39
39
|
'```js\n' +
|
|
40
40
|
"// ✅ Works — set messages in JavaScript as a property\n" +
|
|
41
41
|
"const chat = document.querySelector('kai-chat');\n" +
|
|
42
|
-
"chat.messages = [{ id: '1', role: 'assistant',
|
|
42
|
+
"chat.messages = [{ id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hello!' }] }];\n" +
|
|
43
43
|
'```\n\n' +
|
|
44
44
|
'```html\n' +
|
|
45
45
|
'<!-- ❌ Fails — messages cannot be an HTML attribute -->\n' +
|
|
@@ -55,7 +55,7 @@ const RULES: Rule[] = [
|
|
|
55
55
|
title: 'In-place mutation does not trigger a re-render',
|
|
56
56
|
cause:
|
|
57
57
|
'Mutating an existing message object or array in place (e.g. `chat.messages.push(…)` ' +
|
|
58
|
-
'or `chat.messages[i].
|
|
58
|
+
'or `chat.messages[i].parts = […]`) does not trigger a re-render. ' +
|
|
59
59
|
'The element only reacts when it detects a new array/object reference.',
|
|
60
60
|
fix:
|
|
61
61
|
'Assign a NEW array (and a new object) on every change — never mutate in place.\n\n' +
|
|
@@ -63,17 +63,23 @@ const RULES: Rule[] = [
|
|
|
63
63
|
'// ✅ Triggers re-render — new array + new object reference\n' +
|
|
64
64
|
'chat.messages = [\n' +
|
|
65
65
|
' ...chat.messages,\n' +
|
|
66
|
-
" { id: crypto.randomUUID(), role: 'user',
|
|
66
|
+
" { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text: userText }] },\n" +
|
|
67
67
|
'];\n\n' +
|
|
68
|
-
'// ✅ During streaming
|
|
68
|
+
'// ✅ During streaming: new array + new object per chunk, and FOLD the delta\n' +
|
|
69
|
+
"// onto the trailing text part so reasoning/tool/card parts survive.\n" +
|
|
70
|
+
"import { appendTextPart } from '@kitn.ai/ui/state';\n" +
|
|
69
71
|
'chat.messages = chat.messages.map((m) =>\n' +
|
|
70
|
-
' m.id === assistantId ? { ...m,
|
|
72
|
+
' m.id === assistantId ? { ...m, parts: appendTextPart(m.parts, delta) } : m\n' +
|
|
71
73
|
');\n\n' +
|
|
72
74
|
'// ❌ Does NOT trigger re-render\n' +
|
|
73
75
|
'chat.messages.push(newMsg);\n' +
|
|
74
|
-
'chat.messages[i].
|
|
76
|
+
'chat.messages[i].parts = appendTextPart(chat.messages[i].parts, delta);\n\n' +
|
|
77
|
+
'// ❌ Re-renders, but DROPS the reasoning/tool/card parts already on the message\n' +
|
|
78
|
+
'chat.messages = chat.messages.map((m) =>\n' +
|
|
79
|
+
" m.id === assistantId ? { ...m, parts: [{ type: 'text', text: accumulated }] } : m\n" +
|
|
80
|
+
');\n' +
|
|
75
81
|
'```\n\n' +
|
|
76
|
-
'The ergonomic path: helpers in `@kitn.ai/ui/state` (`appendMessage`, `updateMessage`, `
|
|
82
|
+
'The ergonomic path: helpers in `@kitn.ai/ui/state` (`appendMessage`, `updateMessage`, `appendText`) ' +
|
|
77
83
|
'and `createAssistantStream` handle the new-reference contract for you. ' +
|
|
78
84
|
'`useKaiChat` (React) and `createKaiChat` (Solid) own state entirely so mutation is never an option.\n\n' +
|
|
79
85
|
'// setMessages((m) => appendMessage(m, msg)) // new array, no footgun',
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
KAI_TOOL_PREFIX,
|
|
4
|
+
cardSchemaNames,
|
|
5
|
+
cardSchemas,
|
|
6
|
+
cardTools,
|
|
7
|
+
isCardSchemaName,
|
|
8
|
+
toolNameForCardType,
|
|
9
|
+
} from '@kitn.ai/ui/schemas';
|
|
10
|
+
import type { CardSchemaName, ToolProvider } from '@kitn.ai/ui/schemas';
|
|
2
11
|
import type { Tool } from './types';
|
|
3
|
-
import { getElement, listElements } from '../manifest';
|
|
12
|
+
import { cardHostTags, cardTagForType, cardTypeForTag, getElement, listElements } from '../manifest';
|
|
13
|
+
import type { CemMember } from '../manifest';
|
|
4
14
|
|
|
5
15
|
/**
|
|
6
16
|
* component_reference — look up AI/UI (kai-*) web components, their props,
|
|
@@ -10,6 +20,10 @@ import { getElement, listElements } from '../manifest';
|
|
|
10
20
|
* Backed by manifest.ts which resolves the CEM in both the bundled bin
|
|
11
21
|
* (dist/mcp.es.js sibling) and the Vitest source context (walks up to find
|
|
12
22
|
* dist/custom-elements.json in the repo root).
|
|
23
|
+
*
|
|
24
|
+
* For a card-backed element it also serves the card's JSON Schema and a tool
|
|
25
|
+
* definition GENERATED by `cardTools()`. See `renderCardContract` for why not one
|
|
26
|
+
* byte of that is written here as a literal.
|
|
13
27
|
*/
|
|
14
28
|
|
|
15
29
|
/** Types that warrant the JS-property contract note. */
|
|
@@ -19,7 +33,199 @@ function isJsOnlyType(typeText: string | undefined): boolean {
|
|
|
19
33
|
return typeText ? JS_ONLY_TYPE_PATTERNS.test(typeText) : false;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
|
-
|
|
36
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
// The imperative half of the interaction surface
|
|
38
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A CEM member of `kind: 'method'`.
|
|
42
|
+
*
|
|
43
|
+
* `CemMember` in manifest.ts types what EVERY member carries. `parameters` and
|
|
44
|
+
* `return` exist only on methods, and gen-element-api.mjs writes the AUTHORED
|
|
45
|
+
* parameter list into a single `parameters[0].name` rather than splitting it, so
|
|
46
|
+
* the signature is rebuilt from those two fields rather than read off one.
|
|
47
|
+
*/
|
|
48
|
+
interface CemMethodMember extends CemMember {
|
|
49
|
+
kind: 'method';
|
|
50
|
+
parameters?: { name: string }[];
|
|
51
|
+
return?: { type?: { text?: string } };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isPublicMethod(member: CemMember): member is CemMethodMember {
|
|
55
|
+
return member.kind === 'method' && member.privacy === 'public';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** `maximize(index: number): void` — the call as a consumer types it. */
|
|
59
|
+
function methodSignature(method: CemMethodMember): string {
|
|
60
|
+
return `${method.name}(${method.parameters?.[0]?.name ?? ''}): ${method.return?.type?.text ?? 'void'}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
// The card contract
|
|
65
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
const PROVIDERS = ['openai', 'anthropic', 'jsonschema'] as const;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* What a caller gets when they do not name a provider.
|
|
71
|
+
*
|
|
72
|
+
* NOT a coin-flip between the two wire formats, and deliberately not "serve all
|
|
73
|
+
* three". The three envelopes are not interchangeable in a way a reader can patch
|
|
74
|
+
* up: OpenAI nests the schema at `function.parameters`, Anthropic puts it flat at
|
|
75
|
+
* `input_schema`. Handing over one of those unasked means a harness on the other
|
|
76
|
+
* provider pastes it in and gets a 400 it will blame on the kit.
|
|
77
|
+
*
|
|
78
|
+
* `jsonschema` is the only one of the three that is not a wire envelope at all —
|
|
79
|
+
* `{ name, description, schema }` cannot be mistaken for either provider's shape, so
|
|
80
|
+
* a caller who reads it as one is corrected by the field names before they ship it.
|
|
81
|
+
* It is also directly usable, not a booby prize: `tool({ inputSchema: jsonSchema(
|
|
82
|
+
* def.schema) })` is exactly what the Vercel AI SDK wants, and of the nine
|
|
83
|
+
* integrations this MCP scaffolds, exactly one (openrouter) posts a raw OpenAI-wire
|
|
84
|
+
* tools array; the rest go through an SDK or an agent framework that takes the bare
|
|
85
|
+
* schema.
|
|
86
|
+
*
|
|
87
|
+
* Serving all three was the other candidate and it loses on cost for no gain in
|
|
88
|
+
* safety: measured on this tree, one card's pretty-printed definition runs
|
|
89
|
+
* 1.7-5.3 KB, so three of them plus the schema turns a single `kai-artifact` lookup
|
|
90
|
+
* into roughly 20 KB of context. The response names all three modes and the exact
|
|
91
|
+
* call that produces each, so a caller who does know their provider is one re-ask
|
|
92
|
+
* away and still never invents an envelope.
|
|
93
|
+
*/
|
|
94
|
+
const DEFAULT_PROVIDER: ToolProvider = 'jsonschema';
|
|
95
|
+
|
|
96
|
+
function isProvider(value: string): value is ToolProvider {
|
|
97
|
+
return (PROVIDERS as readonly string[]).includes(value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Stable fence info strings, so a reader (and reference.test.ts) can lift the blocks back out exactly. */
|
|
101
|
+
const TOOL_FENCE = 'kai-tool-definition';
|
|
102
|
+
const SCHEMA_FENCE = 'kai-card-schema';
|
|
103
|
+
|
|
104
|
+
function fence(info: string, value: unknown): string[] {
|
|
105
|
+
return ['```json ' + info, JSON.stringify(value, null, 2), '```'];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Render a card type as it would be written in JS source.
|
|
110
|
+
*
|
|
111
|
+
* The seven built-ins are all bare identifiers, but a card type is whatever string a
|
|
112
|
+
* developer put in `CardEnvelope.type` — `pricing-table` is legal and reaches this
|
|
113
|
+
* code the day an eighth built-in is hyphenated. Emitting `{ pricing-table: … }` as a
|
|
114
|
+
* copy-paste sample would be a syntax error, so the quoting is decided, not assumed.
|
|
115
|
+
*/
|
|
116
|
+
const BARE_IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
|
|
117
|
+
|
|
118
|
+
function asKey(cardType: string): string {
|
|
119
|
+
return BARE_IDENTIFIER.test(cardType) ? cardType : JSON.stringify(cardType);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function asMember(cardType: string): string {
|
|
123
|
+
return BARE_IDENTIFIER.test(cardType) ? `.${cardType}` : `[${JSON.stringify(cardType)}]`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The loop, in the four facts a harness cannot infer from a prop table.
|
|
128
|
+
*
|
|
129
|
+
* Shared by the card-backed and the card-host sections because they are the same
|
|
130
|
+
* contract seen from the two ends, and a second copy would be the drift this whole
|
|
131
|
+
* task exists to remove, one level up from the tool definition.
|
|
132
|
+
*
|
|
133
|
+
* `example` is the card the caller actually asked about, so the illustration is about
|
|
134
|
+
* their card rather than a fixed one they then have to translate.
|
|
135
|
+
*/
|
|
136
|
+
function loopWiring(example: string): string[] {
|
|
137
|
+
return [
|
|
138
|
+
'',
|
|
139
|
+
'#### Wiring the loop',
|
|
140
|
+
`- **Tool names are \`${KAI_TOOL_PREFIX}<card type>\`.** \`${toolNameForCardType(example)}\` produces \`{ type: "${example}" }\`. ` +
|
|
141
|
+
'Use `isCardTool(name)` to split card calls from your own tools; never match the prefix by hand.',
|
|
142
|
+
'- **`tool_call_id` becomes `CardEnvelope.id`, unchanged.** That is what makes a revision UPSERT: ' +
|
|
143
|
+
'a model that re-sends the same tool call id replaces the card in place instead of rendering a second copy of it. ' +
|
|
144
|
+
'Generating your own id breaks that silently.',
|
|
145
|
+
'- **`cardFromToolCall(name, input, { id: call.id })`** turns the call into a renderable envelope, ' +
|
|
146
|
+
'or returns `null` when it is one of your own tools so the loop falls through to it. It never throws.',
|
|
147
|
+
'- **Everything above is one import:** `import { cardTools, cardFromToolCall, isCardTool } from \'@kitn.ai/ui/schemas\'`. ' +
|
|
148
|
+
`The raw documents also ship as JSON (\`@kitn.ai/ui/schemas/${example}.schema.json\`) for a Python or Go backend.`,
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** The card-backed section: schema + a GENERATED tool definition. */
|
|
153
|
+
function renderCardContract(tag: string, cardType: CardSchemaName, provider: ToolProvider): string[] {
|
|
154
|
+
const schema = cardSchemas[cardType];
|
|
155
|
+
|
|
156
|
+
// GENERATED, NEVER RESTATED.
|
|
157
|
+
//
|
|
158
|
+
// This calls the same `cardTools` a consumer's route calls, on the same schema, so
|
|
159
|
+
// the definition served here cannot diverge from the one they ship — not when a
|
|
160
|
+
// schema gains a field, not when the projection changes what it strips. A literal
|
|
161
|
+
// typed into this file would read identically today and rot on the first schema
|
|
162
|
+
// change, which is exactly the hand-copy drift this tool exists to remove.
|
|
163
|
+
// reference.test.ts asserts byte-equality against BOTH `cardTools({ [type]: schema },
|
|
164
|
+
// …)` and the matching entry of the whole-registry `cardTools({ provider })`, so a
|
|
165
|
+
// hand-edit here fails a test rather than shipping.
|
|
166
|
+
const [def] = cardTools({ [cardType]: schema }, { provider });
|
|
167
|
+
|
|
168
|
+
const lines: string[] = [
|
|
169
|
+
'',
|
|
170
|
+
'### Card contract',
|
|
171
|
+
`\`<${tag}>\` renders \`CardEnvelope.type: "${cardType}"\`. A model does not emit an envelope; ` +
|
|
172
|
+
`it calls the tool \`${toolNameForCardType(cardType)}\`, and the kit turns that call back into one.`,
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
lines.push(
|
|
176
|
+
'',
|
|
177
|
+
`#### Tool definition — provider \`${provider}\``,
|
|
178
|
+
`Generated by \`cardTools({ ${asKey(cardType)}: cardSchemas${asMember(cardType)} }, { provider: '${provider}' })\`. ` +
|
|
179
|
+
'Copy it; do not retype it, and do not hand-maintain a second copy — regenerate instead.',
|
|
180
|
+
`Ask again with \`provider\` set to \`openai\`, \`anthropic\` or \`jsonschema\` for the other envelopes. ` +
|
|
181
|
+
'They are NOT interchangeable: OpenAI nests the schema at `function.parameters`, Anthropic puts it flat at `input_schema`.',
|
|
182
|
+
...fence(TOOL_FENCE, def),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
lines.push(
|
|
186
|
+
'',
|
|
187
|
+
'#### Card data JSON Schema',
|
|
188
|
+
`\`import { cardSchemas } from '@kitn.ai/ui/schemas'\` → \`cardSchemas${asMember(cardType)}\`. ` +
|
|
189
|
+
`Raw document: \`@kitn.ai/ui/schemas/${cardType}.schema.json\`.`,
|
|
190
|
+
'This is the authored contract, and it is what `registry.validate()` checks arriving data against. ' +
|
|
191
|
+
'The tool definition above carries the same document with `$schema`, `$id` and `x-kai-*` stripped — ' +
|
|
192
|
+
'that projection is `cardTools`\' job, so do not put a raw schema on the wire yourself.',
|
|
193
|
+
...fence(SCHEMA_FENCE, schema),
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
lines.push(...loopWiring(cardType));
|
|
197
|
+
return lines;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** The card-host section: no schema of its own, but this is where the props live. */
|
|
201
|
+
function renderCardHost(tag: string): string[] {
|
|
202
|
+
const rows = cardSchemaNames.map((type) => {
|
|
203
|
+
const cardTag = cardTagForType(type);
|
|
204
|
+
return `- \`${type}\` → \`<${cardTag ?? '(no element)'}>\`, tool \`${toolNameForCardType(type)}\``;
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
return [
|
|
208
|
+
'',
|
|
209
|
+
'### Card contract',
|
|
210
|
+
`\`<${tag}>\` renders generative-UI cards inside the thread. It is a HOST: it draws whatever ` +
|
|
211
|
+
'envelopes arrive, and carries the two props that say what a card may be.',
|
|
212
|
+
'',
|
|
213
|
+
'- **`cardTypes`** — `Record<envelope type, custom element tag>`. What DRAWS a card. ' +
|
|
214
|
+
`Merged over the built-ins, so your entry overrides ours and the other ${cardSchemaNames.length - 1} still render.`,
|
|
215
|
+
'- **`cardSchemas`** — `Record<envelope type, JSON Schema>`. What a VALID card looks like. ' +
|
|
216
|
+
`This is the prop that carries YOUR OWN card schemas into the browser validator; the ${cardSchemaNames.length} built-ins are already known. ` +
|
|
217
|
+
'Both are objects, so both are JS properties (`el.cardSchemas = …`), never HTML attributes.',
|
|
218
|
+
'',
|
|
219
|
+
'Write both once with `createCardRegistry({ use, custom })` from `@kitn.ai/ui/schemas` and thread it to both ends: ' +
|
|
220
|
+
'`el.cardTypes = cards.tags` / `el.cardSchemas = cards.validationSchemas` on the client, `cardTools(cards, { provider })` on the route.',
|
|
221
|
+
'',
|
|
222
|
+
'Built-in card types (ask `component_reference` for one of these tags to get its schema and tool definition):',
|
|
223
|
+
...rows,
|
|
224
|
+
...loopWiring(cardSchemaNames[0]),
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function formatReference(tag: string, provider: ToolProvider): string {
|
|
23
229
|
const el = getElement(tag);
|
|
24
230
|
|
|
25
231
|
if (!el) {
|
|
@@ -50,6 +256,17 @@ function formatReference(tag: string): string {
|
|
|
50
256
|
'and read `event.detail` for the payload.',
|
|
51
257
|
);
|
|
52
258
|
|
|
259
|
+
// ── Card contract ─────────────────────────────────────────────────────────
|
|
260
|
+
// Attached to the two populations manifest.ts derives, and to nothing else. A
|
|
261
|
+
// reference that hangs card material off all 80 elements is worse than one that
|
|
262
|
+
// hangs it off none: it teaches a harness that every element takes a tool call.
|
|
263
|
+
const cardType = cardTypeForTag(tag);
|
|
264
|
+
if (cardType !== undefined && isCardSchemaName(cardType)) {
|
|
265
|
+
lines.push(...renderCardContract(tag, cardType, provider));
|
|
266
|
+
} else if (cardHostTags().includes(tag)) {
|
|
267
|
+
lines.push(...renderCardHost(tag));
|
|
268
|
+
}
|
|
269
|
+
|
|
53
270
|
// ── Public JS properties ───────────────────────────────────────────────────
|
|
54
271
|
const publicFields = (el.members ?? []).filter(
|
|
55
272
|
(m) => m.kind === 'field' && m.privacy === 'public',
|
|
@@ -93,6 +310,25 @@ function formatReference(tag: string): string {
|
|
|
93
310
|
}
|
|
94
311
|
}
|
|
95
312
|
|
|
313
|
+
// ── Methods ───────────────────────────────────────────────────────────────
|
|
314
|
+
// The input half of the interaction surface. These were in the manifest and in
|
|
315
|
+
// the shipped types and rendered in NO reference, so the only way to find one
|
|
316
|
+
// was to read the kit's source.
|
|
317
|
+
const methods = (el.members ?? []).filter(isPublicMethod);
|
|
318
|
+
if (methods.length > 0) {
|
|
319
|
+
lines.push(
|
|
320
|
+
'',
|
|
321
|
+
'### Methods (call these on the element instance)',
|
|
322
|
+
`Get the element (\`const el = document.querySelector('${tag}')\`), then call it. ` +
|
|
323
|
+
'Methods drive the element from your code; the events above report back what the ' +
|
|
324
|
+
'user did. Both are public API.',
|
|
325
|
+
);
|
|
326
|
+
for (const method of methods) {
|
|
327
|
+
const desc = method.description?.trim() ?? '';
|
|
328
|
+
lines.push(`- **${methodSignature(method)}**${desc ? ` — ${desc}` : ''}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
96
332
|
// ── CSS custom properties ─────────────────────────────────────────────────
|
|
97
333
|
const cssProps = el.cssProperties ?? [];
|
|
98
334
|
if (cssProps.length > 0) {
|
|
@@ -142,21 +378,64 @@ function formatReference(tag: string): string {
|
|
|
142
378
|
export const reference: Tool = {
|
|
143
379
|
name: 'component_reference',
|
|
144
380
|
description:
|
|
145
|
-
'Look up AI/UI (kai-*) web components: their tags, props, events, and usage examples.'
|
|
146
|
-
|
|
381
|
+
'Look up AI/UI (kai-*) web components: their tags, props, events, imperative methods, and usage examples. ' +
|
|
382
|
+
'For a card-backed element it also returns the card\'s JSON Schema and a ready-to-send ' +
|
|
383
|
+
'tool definition generated from it — pass `provider` to get that provider\'s envelope.',
|
|
384
|
+
inputSchema: z.object({
|
|
385
|
+
name: z.string().optional(),
|
|
386
|
+
provider: z
|
|
387
|
+
.enum(PROVIDERS)
|
|
388
|
+
.optional()
|
|
389
|
+
.describe(
|
|
390
|
+
'Which tool-definition envelope to project for a card-backed element. ' +
|
|
391
|
+
`Defaults to "${DEFAULT_PROVIDER}", the provider-neutral { name, description, schema } form.`,
|
|
392
|
+
),
|
|
393
|
+
}),
|
|
147
394
|
handler: async (args: Record<string, unknown>) => {
|
|
148
395
|
const name = typeof args.name === 'string' ? args.name.trim() : undefined;
|
|
149
396
|
|
|
397
|
+
// Validated HERE, not left to the zod schema above. server.ts advertises
|
|
398
|
+
// `inputSchema` over the protocol but hands `request.params.arguments` straight
|
|
399
|
+
// to this handler without parsing it, so an unrecognised provider would reach
|
|
400
|
+
// `cardTools`, which treats anything that is not "openai"/"anthropic" as the
|
|
401
|
+
// jsonschema branch. A caller asking for "gemini" would then get a definition in
|
|
402
|
+
// a shape they did not ask for, with nothing saying so. Refusing is the only
|
|
403
|
+
// answer that cannot be mistaken for an answer.
|
|
404
|
+
const rawProvider = args.provider;
|
|
405
|
+
if (rawProvider !== undefined && (typeof rawProvider !== 'string' || !isProvider(rawProvider))) {
|
|
406
|
+
return {
|
|
407
|
+
content: [
|
|
408
|
+
{
|
|
409
|
+
type: 'text' as const,
|
|
410
|
+
text:
|
|
411
|
+
`Unknown provider: ${JSON.stringify(rawProvider)}\n\n` +
|
|
412
|
+
`Valid providers are ${PROVIDERS.map((p) => `"${p}"`).join(', ')}. ` +
|
|
413
|
+
`Omit it to get "${DEFAULT_PROVIDER}", the provider-neutral { name, description, schema } form ` +
|
|
414
|
+
'that the Vercel AI SDK and most agent frameworks take directly.\n' +
|
|
415
|
+
'No tool definition was returned, because guessing which envelope you meant would hand you ' +
|
|
416
|
+
'a shape your provider rejects with nothing saying why.',
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const provider: ToolProvider = rawProvider ?? DEFAULT_PROVIDER;
|
|
422
|
+
|
|
150
423
|
let text: string;
|
|
151
424
|
|
|
152
425
|
if (!name || name === 'list') {
|
|
153
426
|
const tags = listElements();
|
|
427
|
+
const cardRows = cardSchemaNames
|
|
428
|
+
.map((t) => cardTagForType(t))
|
|
429
|
+
.filter((t): t is string => t !== undefined);
|
|
154
430
|
text =
|
|
155
431
|
`AI/UI elements (${tags.length} total):\n\n` +
|
|
156
432
|
tags.map((t) => ` ${t}`).join('\n') +
|
|
157
|
-
'\n\nCall component_reference with a specific name (e.g. { name: "kai-chat" }) for full API details.'
|
|
433
|
+
'\n\nCall component_reference with a specific name (e.g. { name: "kai-chat" }) for full API details.' +
|
|
434
|
+
`\n\nCard-backed elements — ask for one of these to get its JSON Schema and a generated ` +
|
|
435
|
+
`\`${KAI_TOOL_PREFIX}*\` tool definition:\n ${cardRows.join(', ')}` +
|
|
436
|
+
`\nThe elements that HOST them (and carry the \`cardTypes\` / \`cardSchemas\` props): ${cardHostTags().join(', ')}`;
|
|
158
437
|
} else {
|
|
159
|
-
text = formatReference(name);
|
|
438
|
+
text = formatReference(name, provider);
|
|
160
439
|
}
|
|
161
440
|
|
|
162
441
|
return { content: [{ type: 'text' as const, text }] };
|