@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
|
@@ -382,6 +382,35 @@ export function ShaderCanvas(props: ShaderCanvasProps): JSX.Element {
|
|
|
382
382
|
let drawFrame: ((now: number) => void) | null = null;
|
|
383
383
|
/** The pending animation frame id, or 0 when the loop is stopped. */
|
|
384
384
|
let raf = 0;
|
|
385
|
+
/**
|
|
386
|
+
* `cancelAnimationFrame`, captured at SETUP.
|
|
387
|
+
*
|
|
388
|
+
* `stopLoop()` below runs at dispose (via `release()`), and dispose is not
|
|
389
|
+
* guaranteed to happen while the page that mounted this canvas is still
|
|
390
|
+
* standing -- `component-register`'s `disconnectedCallback` defers a
|
|
391
|
+
* microtask, and a test environment tears its DOM globals down in between.
|
|
392
|
+
* A bare `cancelAnimationFrame` there throws from a promise nobody holds, so
|
|
393
|
+
* it surfaces as an unhandled rejection that fails a run in which every test
|
|
394
|
+
* passed. See tests/components/teardown-without-dom-globals.test.tsx.
|
|
395
|
+
*
|
|
396
|
+
* The FUNCTION, not the view. The `const win = window` capture that fixes a
|
|
397
|
+
* bare `document` does nothing here: `window === globalThis` -- measured, in
|
|
398
|
+
* jsdom and in real Chromium/WebKit alike -- and the teardown deletes these
|
|
399
|
+
* keys off that very object, so `win.cancelAnimationFrame` is undefined by
|
|
400
|
+
* the time cleanup runs. It only trades the ReferenceError for a TypeError.
|
|
401
|
+
* `.bind` pins the receiver the WebIDL operation is specified on; Chromium
|
|
402
|
+
* and WebKit both accept a detached call (measured), so the bind is belt and
|
|
403
|
+
* braces against an engine that does not, at zero cost.
|
|
404
|
+
*
|
|
405
|
+
* GUARDED because "setup" for this component is its body, and a server render
|
|
406
|
+
* executes component bodies. Node has no `cancelAnimationFrame` at all, so an
|
|
407
|
+
* unguarded capture here would trade the disposal crash for an SSR crash --
|
|
408
|
+
* measured, not hypothesised. Nothing can be scheduled without
|
|
409
|
+
* `requestAnimationFrame` either, so the no-op fallback is exactly right.
|
|
410
|
+
*/
|
|
411
|
+
const cancelFrame = typeof cancelAnimationFrame === 'function'
|
|
412
|
+
? cancelAnimationFrame.bind(globalThis)
|
|
413
|
+
: () => {};
|
|
385
414
|
|
|
386
415
|
/** The assembled source and the uniform snapshot it was assembled from. */
|
|
387
416
|
let build: { source: string; uniforms: Record<string, UniformSpec> } | null = null;
|
|
@@ -460,7 +489,8 @@ export function ShaderCanvas(props: ShaderCanvasProps): JSX.Element {
|
|
|
460
489
|
|
|
461
490
|
const stopLoop = () => {
|
|
462
491
|
if (raf === 0) return;
|
|
463
|
-
|
|
492
|
+
// Captured at setup -- see `cancelFrame`. This line runs at dispose.
|
|
493
|
+
cancelFrame(raf);
|
|
464
494
|
raf = 0;
|
|
465
495
|
// Bank what was drawn so `iTime` resumes from here, not from zero.
|
|
466
496
|
elapsedMs += Math.max(0, performance.now() - runStartedAt);
|
|
@@ -1,28 +1,60 @@
|
|
|
1
1
|
// src/components/card-fallback.tsx
|
|
2
|
-
// Rendered by the dispatcher when an envelope
|
|
2
|
+
// Rendered by the dispatcher when an envelope cannot be rendered: its `type` has no
|
|
3
|
+
// registered card, or its `data` failed HARD validation against the built-in schema
|
|
4
|
+
// for that type (see primitives/card-validate-cards.ts for what "hard" means).
|
|
3
5
|
// Visual: reuses the Card chrome so it sits naturally in a card stream.
|
|
4
|
-
import type
|
|
6
|
+
import { Show, type JSX } from 'solid-js';
|
|
5
7
|
import { Card } from './card';
|
|
6
8
|
import { AlertTriangle } from 'lucide-solid';
|
|
7
9
|
|
|
8
10
|
export interface CardFallbackProps {
|
|
9
|
-
/** The
|
|
11
|
+
/** The envelope type, shown to aid debugging. */
|
|
10
12
|
type: string;
|
|
11
13
|
/** The envelope id (for parity with cards; not displayed). */
|
|
12
14
|
cardId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Why this card could not render, when the type WAS known but the data was not
|
|
17
|
+
* usable. Carries the failing field paths verbatim, e.g.
|
|
18
|
+
* `(root).actions: fewer than minItems 1`.
|
|
19
|
+
*
|
|
20
|
+
* Absent means the older case: an unrecognized type. The two are told apart by
|
|
21
|
+
* this prop rather than by a mode flag so a caller cannot ask for the diagnostic
|
|
22
|
+
* and forget to supply the diagnosis.
|
|
23
|
+
*/
|
|
24
|
+
reason?: string;
|
|
13
25
|
}
|
|
14
26
|
|
|
15
|
-
/** Inert, themed fallback for
|
|
27
|
+
/** Inert, themed fallback for a card that cannot render. Emits nothing itself:
|
|
16
28
|
* the dispatcher emits the contract `error` event alongside rendering this. */
|
|
17
29
|
export function CardFallback(props: CardFallbackProps): JSX.Element {
|
|
18
30
|
return (
|
|
19
31
|
<Card>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
<Show
|
|
33
|
+
when={props.reason}
|
|
34
|
+
fallback={
|
|
35
|
+
<div data-card-fallback role="alert" class="flex items-center gap-2 p-4 text-sm text-muted-foreground">
|
|
36
|
+
<AlertTriangle class="size-4 shrink-0 text-destructive dark:text-red-400" aria-hidden="true" />
|
|
37
|
+
<span>
|
|
38
|
+
Unsupported card type: <code class="font-mono">{props.type}</code>
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
>
|
|
43
|
+
{(reason) => (
|
|
44
|
+
<div
|
|
45
|
+
data-card-fallback
|
|
46
|
+
data-card-invalid
|
|
47
|
+
role="alert"
|
|
48
|
+
class="flex items-start gap-2 p-4 text-sm text-muted-foreground"
|
|
49
|
+
>
|
|
50
|
+
<AlertTriangle class="size-4 shrink-0 translate-y-0.5 text-destructive dark:text-red-400" aria-hidden="true" />
|
|
51
|
+
<span class="min-w-0">
|
|
52
|
+
Invalid <code class="font-mono">{props.type}</code> card:{' '}
|
|
53
|
+
<code data-card-invalid-reason class="font-mono break-words">{reason()}</code>
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</Show>
|
|
26
58
|
</Card>
|
|
27
59
|
);
|
|
28
60
|
}
|
|
@@ -2,17 +2,85 @@
|
|
|
2
2
|
// The Solid single-envelope dispatcher: pick the card for envelope.type and render it
|
|
3
3
|
// with the envelope spread onto its props. Routing uses the ambient CardProvider
|
|
4
4
|
// (useCardHost). Unknown type → CardFallback + a one-shot contract `error` emit.
|
|
5
|
-
|
|
5
|
+
// Invalid data → two-tier validation, mirroring the remote transport; see below.
|
|
6
|
+
import { createEffect, createMemo, untrack, Show, type JSX } from 'solid-js';
|
|
6
7
|
import { Dynamic } from 'solid-js/web';
|
|
7
8
|
import type { CardEnvelope } from '../primitives/card-contract';
|
|
8
9
|
import { useCardHost } from '../primitives/card-host';
|
|
9
|
-
import { mergeCardComponents, type CardComponentMap } from '../primitives/card-registry';
|
|
10
|
+
import { BUILTIN_CARD_COMPONENTS, mergeCardComponents, type CardComponentMap } from '../primitives/card-registry';
|
|
11
|
+
import type { JsonSchema } from '../primitives/card-validate';
|
|
12
|
+
import { cardValidationMessage, validateCardData, type CardValidationReport } from '../primitives/card-validate-cards';
|
|
10
13
|
import { CardFallback } from './card-fallback';
|
|
11
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Consumer card schemas by envelope type: `{ 'pricing-table': pricingSchema }`.
|
|
17
|
+
*
|
|
18
|
+
* `object`, NOT `JsonSchema`, and that is measured rather than lazy. A real schema
|
|
19
|
+
* is either imported from a `.json` file — where TypeScript widens `"type": "object"`
|
|
20
|
+
* to `string`, which `JsonSchema`'s literal union rejects — or written out with the
|
|
21
|
+
* `$schema` / `title` / `description` / `additionalProperties` keywords that
|
|
22
|
+
* `JsonSchema` does not describe at all, which excess-property checking rejects.
|
|
23
|
+
* Both are the ordinary case, so the tighter type would make the normal way of
|
|
24
|
+
* supplying a schema a compile error. `src/schemas/index.ts` widens `CardSchema`
|
|
25
|
+
* for exactly this reason and says so at length (lines 92-110 there).
|
|
26
|
+
*
|
|
27
|
+
* The value is handed straight to `validateCardData`, which reads only the keywords
|
|
28
|
+
* `validateAgainstSchema` implements and ignores the rest.
|
|
29
|
+
*/
|
|
30
|
+
export type CardSchemaMap = Record<string, object>;
|
|
31
|
+
|
|
12
32
|
export interface CardRendererProps {
|
|
13
33
|
envelope: CardEnvelope;
|
|
14
34
|
/** Add/override type→component entries (merged over the built-ins). */
|
|
15
35
|
types?: CardComponentMap;
|
|
36
|
+
/**
|
|
37
|
+
* JSON Schemas for the card types this app renders, keyed by `envelope.type`.
|
|
38
|
+
* `createCardRegistry(...).validationSchemas` is exactly this shape.
|
|
39
|
+
*
|
|
40
|
+
* The companion of `types`, and the half that was missing: `types` says WHAT
|
|
41
|
+
* draws a `pricing-table`, `schemas` says what a VALID one looks like. Without it
|
|
42
|
+
* the kit checks its own seven built-ins and leaves the developer's own card —
|
|
43
|
+
* the one the app actually cares about — as the only unvalidated thing on screen.
|
|
44
|
+
*
|
|
45
|
+
* A schema given here WINS over a built-in of the same name, matching
|
|
46
|
+
* `mergeCardComponents`, where the consumer's entry is spread over ours.
|
|
47
|
+
*/
|
|
48
|
+
schemas?: CardSchemaMap;
|
|
49
|
+
/**
|
|
50
|
+
* Validate `envelope.data` against the built-in schema for `envelope.type` before
|
|
51
|
+
* rendering. Default `true`.
|
|
52
|
+
*
|
|
53
|
+
* ON IN PRODUCTION TOO, DELIBERATELY. The obvious alternative, stripping the check
|
|
54
|
+
* from production builds, inverts the point: a model emitting a bad shape is a
|
|
55
|
+
* production failure mode, so stripping it means the developer's USERS get the
|
|
56
|
+
* broken card while the developer's laptop looks fine. The cost is the projected
|
|
57
|
+
* schema data for all seven card types, measured by building this package twice
|
|
58
|
+
* (once with the projection stubbed to `{}`) rather than estimated: +834 B gzip on
|
|
59
|
+
* `dist/index.js` and +775 B gzip on the elements register bundle. That is below
|
|
60
|
+
* the noise floor of a package that already ships a Solid runtime and `marked`.
|
|
61
|
+
*
|
|
62
|
+
* Set `false` to opt out. A type with no schema at all — no built-in, and none
|
|
63
|
+
* supplied through `schemas` — is never validated either way.
|
|
64
|
+
*/
|
|
65
|
+
validateCards?: boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* True when the consumer registered a schema for this type.
|
|
70
|
+
*
|
|
71
|
+
* Spelled out rather than left to `validateCardData` because it is a GATE, not a
|
|
72
|
+
* lookup: a consumer schema is the one thing that authorises validating a renderer
|
|
73
|
+
* that is not ours. `hasOwnProperty` (not `in`) so a type named `toString` cannot
|
|
74
|
+
* pick up `Object.prototype`, and the `typeof` check so a `{ 'x': null }` entry
|
|
75
|
+
* reads as "not registered" instead of matching and then validating against
|
|
76
|
+
* nothing. The same predicate lives in elements/cards.tsx for `<kai-cards>`; the
|
|
77
|
+
* two dispatchers already duplicate this rule (they compare component identity vs
|
|
78
|
+
* tag identity), so keep them in step.
|
|
79
|
+
*/
|
|
80
|
+
export function hasConsumerSchema(schemas: CardSchemaMap | undefined, type: string): boolean {
|
|
81
|
+
if (!schemas || !Object.prototype.hasOwnProperty.call(schemas, type)) return false;
|
|
82
|
+
const s = schemas[type];
|
|
83
|
+
return typeof s === 'object' && s !== null;
|
|
16
84
|
}
|
|
17
85
|
|
|
18
86
|
export function CardRenderer(props: CardRendererProps): JSX.Element {
|
|
@@ -20,12 +88,74 @@ export function CardRenderer(props: CardRendererProps): JSX.Element {
|
|
|
20
88
|
const map = createMemo(() => mergeCardComponents(props.types));
|
|
21
89
|
const entry = createMemo(() => map()[props.envelope.type]);
|
|
22
90
|
|
|
91
|
+
// MIRRORS src/remote/provider-runtime.ts:139-147. That transport runs
|
|
92
|
+
// `validateAgainstSchema(renderer.schema, envelope.data)` and, on failure, renders
|
|
93
|
+
// a placeholder and emits `{ kind: 'error', cardId, message }`. This is the same
|
|
94
|
+
// behaviour on the native path, split into two tiers so a card that renders
|
|
95
|
+
// acceptably today is reported without being replaced. Keep the two in step.
|
|
96
|
+
//
|
|
97
|
+
// WHAT AUTHORISES A CHECK IS A SCHEMA THAT DESCRIBES WHAT IS ON SCREEN.
|
|
98
|
+
//
|
|
99
|
+
// `types` lets a consumer replace a built-in type's renderer with their own
|
|
100
|
+
// (`types={{ confirm: MyConfirm }}`), and `confirm.schema.json` describes OUR
|
|
101
|
+
// ConfirmCard's data, not theirs. Validating a replaced renderer's payload against
|
|
102
|
+
// our schema would reject shapes that are correct for the component actually on
|
|
103
|
+
// screen. So OUR schema applies only to OUR component: the identity check is
|
|
104
|
+
// against BUILTIN_CARD_COMPONENTS, the same object `mergeCardComponents` puts in
|
|
105
|
+
// the map when nothing overrode the type, and the same one elements/message.tsx
|
|
106
|
+
// reuses for a non-overridden built-in.
|
|
107
|
+
//
|
|
108
|
+
// A schema the CONSUMER registered is the other way round: they wrote it about
|
|
109
|
+
// their own card, and it is the shape their model was told to emit, so it applies
|
|
110
|
+
// whichever component draws the type. That covers the case the identity check can
|
|
111
|
+
// never reach — a `pricing-table` that is nobody's built-in — and it re-enables
|
|
112
|
+
// the check on an overridden built-in, where the objection was our schema and not
|
|
113
|
+
// the checking.
|
|
114
|
+
const report = createMemo<CardValidationReport | null>(() => {
|
|
115
|
+
if (props.validateCards === false) return null;
|
|
116
|
+
if (
|
|
117
|
+
!hasConsumerSchema(props.schemas, props.envelope.type) &&
|
|
118
|
+
entry() !== BUILTIN_CARD_COMPONENTS[props.envelope.type]
|
|
119
|
+
) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
// `schemas` is passed even when the gate opened on renderer identity, so a
|
|
123
|
+
// consumer schema for a built-in type wins over ours — `schemaFor`'s rule.
|
|
124
|
+
return validateCardData(props.envelope.type, props.envelope.data, props.schemas as Record<string, JsonSchema> | undefined);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// One `error` per distinct problem, both tiers. Keyed on the message rather than
|
|
128
|
+
// on mount because streaming hands this component a NEW envelope object per chunk
|
|
129
|
+
// (that is the documented way to re-render), so an identity-triggered emit would
|
|
130
|
+
// fire once per chunk for one bad card.
|
|
131
|
+
let lastEmitted: string | null = null;
|
|
132
|
+
createEffect(() => {
|
|
133
|
+
const r = report();
|
|
134
|
+
if (!entry()) return; // an unknown TYPE reports itself, once, in UnknownCard
|
|
135
|
+
if (!r || r.ok) {
|
|
136
|
+
lastEmitted = null;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const message = cardValidationMessage(r);
|
|
140
|
+
if (message === lastEmitted) return;
|
|
141
|
+
lastEmitted = message;
|
|
142
|
+
host?.emit({ kind: 'error', cardId: props.envelope.id, message });
|
|
143
|
+
});
|
|
144
|
+
|
|
23
145
|
return (
|
|
24
|
-
<Show
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
146
|
+
<Show when={entry()} fallback={<UnknownCard envelope={props.envelope} />}>
|
|
147
|
+
{(comp) => (
|
|
148
|
+
<Show
|
|
149
|
+
when={report()?.tier === 'hard'}
|
|
150
|
+
// SOFT and valid both take this branch: the card renders exactly as it
|
|
151
|
+
// does today. The soft failure is reported through the effect above and
|
|
152
|
+
// changes nothing on screen, which is the whole point of the tiering.
|
|
153
|
+
fallback={<Dynamic component={comp()} envelope={props.envelope} host={host} />}
|
|
154
|
+
>
|
|
155
|
+
{/* HARD: there is nothing to draw, so name the field instead. */}
|
|
156
|
+
<CardFallback type={props.envelope.type} cardId={props.envelope.id} reason={report()!.summary} />
|
|
157
|
+
</Show>
|
|
158
|
+
)}
|
|
29
159
|
</Show>
|
|
30
160
|
);
|
|
31
161
|
}
|
|
@@ -46,7 +176,14 @@ function UnknownCard(props: { envelope: CardEnvelope }): JSX.Element {
|
|
|
46
176
|
/** Function sugar: renderCard(env) ≡ <CardRenderer envelope={env} />. */
|
|
47
177
|
export function renderCard(
|
|
48
178
|
envelope: CardEnvelope,
|
|
49
|
-
opts?: { types?: CardComponentMap },
|
|
179
|
+
opts?: { types?: CardComponentMap; schemas?: CardSchemaMap; validateCards?: boolean },
|
|
50
180
|
): JSX.Element {
|
|
51
|
-
return
|
|
181
|
+
return (
|
|
182
|
+
<CardRenderer
|
|
183
|
+
envelope={envelope}
|
|
184
|
+
types={opts?.types}
|
|
185
|
+
schemas={opts?.schemas}
|
|
186
|
+
validateCards={opts?.validateCards}
|
|
187
|
+
/>
|
|
188
|
+
);
|
|
52
189
|
}
|
|
@@ -74,6 +74,10 @@ function ChatContainerScrollAnchor(props: ChatContainerScrollAnchorProps) {
|
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/** `ChatContainer` is the exported alias of `ChatContainerRoot`; its props type
|
|
78
|
+
* is aliased too, so the name a consumer imports always has a matching Props. */
|
|
79
|
+
export type ChatContainerProps = ChatContainerRootProps;
|
|
80
|
+
|
|
77
81
|
export {
|
|
78
82
|
ChatContainerRoot as ChatContainer,
|
|
79
83
|
ChatContainerRoot,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSignal, createEffect, For, Show, onMount } from 'solid-js';
|
|
1
|
+
import { createSignal, createEffect, createMemo, For, Show, onMount } from 'solid-js';
|
|
2
2
|
import { ChatConfig, useChatConfig } from '../primitives/chat-config';
|
|
3
3
|
import { type ComposerDoc, normalizeValue, serializeToText } from '../primitives/composer-model';
|
|
4
4
|
import { ChatContainer, ChatContainerContent, ChatContainerScrollAnchor } from './chat-container';
|
|
@@ -11,11 +11,14 @@ import {
|
|
|
11
11
|
Context, ContextTrigger, ContextContent, ContextContentHeader,
|
|
12
12
|
ContextContentBody, ContextContentFooter, ContextInputUsage, ContextOutputUsage,
|
|
13
13
|
} from './context';
|
|
14
|
-
import { DefaultPromptInput } from '../elements/default-input';
|
|
14
|
+
import { DefaultPromptInput, type RejectedAttachment } from '../elements/default-input';
|
|
15
|
+
import type { MediaTypeFilter } from '../wire/media-types';
|
|
15
16
|
import type { TriggerDef } from './composer';
|
|
16
17
|
import type { ChatMessage } from '../elements/chat-types';
|
|
17
18
|
import type { ProseSize } from '../primitives/chat-config';
|
|
18
19
|
import type { ModelOption } from '../types';
|
|
20
|
+
import type { CardComponentMap } from '../primitives/card-registry';
|
|
21
|
+
import type { CardSchemaMap } from './card-renderer';
|
|
19
22
|
|
|
20
23
|
export interface ChatThreadContextUsage {
|
|
21
24
|
usedTokens: number;
|
|
@@ -29,9 +32,19 @@ export interface ChatThreadProps {
|
|
|
29
32
|
/** Extra classes for the thread root (e.g. `h-full`). */
|
|
30
33
|
class?: string;
|
|
31
34
|
/** The full message thread to render, newest last. Each entry carries its role,
|
|
32
|
-
*
|
|
33
|
-
*
|
|
35
|
+
* ordered `parts`, and optional actions/avatar/feedback. Set as a JS property
|
|
36
|
+
* (`el.messages = [...]`). */
|
|
34
37
|
messages: ChatMessage[];
|
|
38
|
+
/** Add/override card type -> component entries, forwarded to `CardRenderer`
|
|
39
|
+
* for `card` parts. */
|
|
40
|
+
cardTypes?: CardComponentMap;
|
|
41
|
+
/** JSON Schemas for the card types this app renders, keyed by envelope type,
|
|
42
|
+
* forwarded to `CardRenderer` for `card` parts. The companion of `cardTypes`:
|
|
43
|
+
* that says what DRAWS a card, this says what a VALID one looks like.
|
|
44
|
+
* `createCardRegistry(...).validationSchemas` is exactly this shape. Without it
|
|
45
|
+
* the kit checks its own seven built-ins and leaves your own card type
|
|
46
|
+
* unvalidated. A schema here WINS over a built-in of the same name. */
|
|
47
|
+
cardSchemas?: CardSchemaMap;
|
|
35
48
|
/** Value of the input. A **string** is controlled (the host owns the text and
|
|
36
49
|
* updates it on `kai-value-change`). A **ComposerDoc** is a one-time seed that
|
|
37
50
|
* pre-populates pills; the user then edits freely. Leave unset for uncontrolled. */
|
|
@@ -72,8 +85,8 @@ export interface ChatThreadProps {
|
|
|
72
85
|
context?: ChatThreadContextUsage;
|
|
73
86
|
/** Show the scroll-to-bottom button inside the scroll area. Default true. */
|
|
74
87
|
scrollButton?: boolean;
|
|
75
|
-
/** Whether the host has `slot="header-start"` content (left of the title)
|
|
76
|
-
*
|
|
88
|
+
/** Whether the host has `slot="header-start"` content (left of the title). Set
|
|
89
|
+
* by the `<kai-chat>` facade so a custom control forces the header open. */
|
|
77
90
|
headerStart?: boolean;
|
|
78
91
|
/** Whether the host has `slot="header-end"` content (right of the controls). */
|
|
79
92
|
headerEnd?: boolean;
|
|
@@ -87,24 +100,31 @@ export interface ChatThreadProps {
|
|
|
87
100
|
// content owns its own data/events — a slotted (light-DOM) node
|
|
88
101
|
// can't read this component's reactive state. That boundary is
|
|
89
102
|
// the whole reason `messages` stays a data prop, not a slot.
|
|
90
|
-
/** REPLACE
|
|
103
|
+
/** REPLACE: full custom header in place of the built-in title/model/context bar. */
|
|
91
104
|
headerFull?: boolean;
|
|
92
|
-
/** INJECT
|
|
105
|
+
/** INJECT: left sidebar column (e.g. a conversation list / your own nav). */
|
|
93
106
|
sidebar?: boolean;
|
|
94
|
-
/** REPLACE
|
|
107
|
+
/** REPLACE: custom zero-state rendered in the message area while the thread is empty (replaces the empty message list only; the composer and its suggestions still render). */
|
|
95
108
|
empty?: boolean;
|
|
96
|
-
/** REPLACE
|
|
109
|
+
/** REPLACE: full custom composer in place of the built-in prompt input. The
|
|
97
110
|
* projected content wires its own submit (the data-flow boundary). */
|
|
98
111
|
composer?: boolean;
|
|
99
|
-
/** INJECT
|
|
112
|
+
/** INJECT: accessory row just above the composer (e.g. extra actions). */
|
|
100
113
|
composerActions?: boolean;
|
|
101
|
-
/** INJECT
|
|
114
|
+
/** INJECT: footer row below the composer (disclaimers, token meter, …). */
|
|
102
115
|
footer?: boolean;
|
|
116
|
+
/** Which attachment media types the user may stage, in HTML `accept` syntax
|
|
117
|
+
* (`'image/*,application/pdf'`). Omitted means no filter. Narrowed by what the
|
|
118
|
+
* encoders can actually send — the same string, and the same resolver, as
|
|
119
|
+
* `toOpenAIMessages(msgs, { accept })`. */
|
|
120
|
+
accept?: MediaTypeFilter;
|
|
121
|
+
/** Files the composer refused because `accept` excluded them. */
|
|
122
|
+
onAttachmentsRejected?: (rejected: RejectedAttachment[]) => void;
|
|
103
123
|
/** Show a Search (Globe) button in the input toolbar; fires a `search` event. */
|
|
104
124
|
search?: boolean;
|
|
105
125
|
/** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
|
|
106
126
|
voice?: boolean;
|
|
107
|
-
/** Rich entity triggers
|
|
127
|
+
/** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored
|
|
108
128
|
* menu that inserts an atomic pill (`/` skills, `@` agents/plugins). Set as a
|
|
109
129
|
* JS property; forwarded to the input. */
|
|
110
130
|
triggers?: TriggerDef[];
|
|
@@ -136,9 +156,48 @@ export interface ChatThreadController {
|
|
|
136
156
|
scrollToBottom(behavior?: ScrollBehavior): void;
|
|
137
157
|
}
|
|
138
158
|
|
|
159
|
+
/**
|
|
160
|
+
* THE MESSAGE LIST'S KEY, and the reason it is not the message object. This is
|
|
161
|
+
* the canonical note; `thread.tsx` keys its identical list the same way and
|
|
162
|
+
* points here.
|
|
163
|
+
*
|
|
164
|
+
* `<For>` is REFERENCE-keyed, and a streaming assistant message gets a brand
|
|
165
|
+
* new object identity on every delta — `createAssistantStream` rebuilds it as
|
|
166
|
+
* `{ ...prev[i], parts: next }` because a new reference IS the re-render
|
|
167
|
+
* signal. Keyed on the objects, every chunk therefore looks like an entirely
|
|
168
|
+
* new list: the whole message row is torn down and rebuilt, and everything the
|
|
169
|
+
* user did inside it dies with it. Expanding a tool or reasoning panel
|
|
170
|
+
* mid-stream did nothing at all — the disclosure opened and was discarded
|
|
171
|
+
* microseconds later by the next token. (`MessageBody` keys its PARTS by
|
|
172
|
+
* position for exactly this reason; that fix was dead while its parent kept
|
|
173
|
+
* destroying the subtree above it.)
|
|
174
|
+
*
|
|
175
|
+
* So key on `message.id`, which is stable across the object churn: `<For>` over
|
|
176
|
+
* the id array diffs by string value, a delta produces an identical id list,
|
|
177
|
+
* and no row moves. The row then reads its message through `messages[i()]` —
|
|
178
|
+
* `<For>`'s index accessor, which it keeps current across inserts, removals and
|
|
179
|
+
* moves — so the CONTENT keeps updating through accessors while the DOM stays
|
|
180
|
+
* put.
|
|
181
|
+
*
|
|
182
|
+
* WHY NOT `<Index>`, the other way to survive the churn: `<Index>` keys by
|
|
183
|
+
* POSITION, so a row's local state (an open panel, a half-filled form card)
|
|
184
|
+
* belongs to the slot rather than to the message. Appends and tail truncations
|
|
185
|
+
* (regenerate/edit) are fine, but prepending older turns — load-earlier-history,
|
|
186
|
+
* which every real chat grows — shifts every row, and each open disclosure
|
|
187
|
+
* stays behind with the wrong message. Position IS a valid key inside a
|
|
188
|
+
* message, where the folds only ever append or patch a part in place; it is not
|
|
189
|
+
* one for the message list, where the host owns the array and splices it.
|
|
190
|
+
* Both approaches require the row to read through accessors — that is inherent
|
|
191
|
+
* in keeping a row mounted while its object is replaced, not a cost unique to
|
|
192
|
+
* either.
|
|
193
|
+
*
|
|
194
|
+
* Contract: `id` must be unique per message. It already had to be — the
|
|
195
|
+
* feedback/copy state above this list is keyed by it.
|
|
196
|
+
*/
|
|
139
197
|
export function ChatThread(props: ChatThreadProps) {
|
|
140
198
|
const outer = useChatConfig();
|
|
141
199
|
const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
|
|
200
|
+
const messageKeys = createMemo(() => props.messages.map((m) => m.id));
|
|
142
201
|
// Feedback (copy + vote) state lives ABOVE the per-message <For>, so streaming
|
|
143
202
|
// re-renders (a fresh `messages` array ref per chunk) don't wipe it.
|
|
144
203
|
// The copy/feedback toasts scope to the chat (this thread's root) so they appear
|
|
@@ -261,44 +320,60 @@ export function ChatThread(props: ChatThreadProps) {
|
|
|
261
320
|
<Show when={props.empty && props.messages.length === 0}>
|
|
262
321
|
<slot name="empty" />
|
|
263
322
|
</Show>
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
323
|
+
{/* Keyed by message id (see the note above this component), so a
|
|
324
|
+
streaming delta updates the row instead of replacing it. */}
|
|
325
|
+
<For each={messageKeys()}>
|
|
326
|
+
{(_id, i) => (
|
|
327
|
+
// The row reads its message through <For>'s index accessor,
|
|
328
|
+
// never through a captured value: the row outlives the delta
|
|
329
|
+
// that replaced its object, so every read below has to go
|
|
330
|
+
// through `m()` for the new content to land. <Show> supplies
|
|
331
|
+
// the non-null accessor and covers the frame where a removal
|
|
332
|
+
// has shortened the array.
|
|
333
|
+
<Show when={props.messages[i()]}>
|
|
334
|
+
{(m) => {
|
|
335
|
+
const body = (
|
|
336
|
+
<MessageBody
|
|
337
|
+
parts={m().parts}
|
|
338
|
+
cardTypes={props.cardTypes}
|
|
339
|
+
cardSchemas={props.cardSchemas}
|
|
340
|
+
isUser={m().role === 'user'}
|
|
341
|
+
markdown={m().role === 'assistant'}
|
|
342
|
+
actions={m().actions}
|
|
343
|
+
actionsReveal={reveal()}
|
|
344
|
+
activeFeedback={feedback.resolveFeedback(m())}
|
|
345
|
+
copied={feedback.isCopied(m().id)}
|
|
346
|
+
onAction={(action) => feedback.handleAction(m(), action)}
|
|
347
|
+
/>
|
|
348
|
+
);
|
|
349
|
+
const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
|
|
350
|
+
return (
|
|
351
|
+
// `role` is the SPEAKER, forwarded on BOTH branches —
|
|
352
|
+
// see the same note in thread.tsx. `Message` turns it
|
|
353
|
+
// into `role="article"` + an `aria-label`; without it the
|
|
354
|
+
// row is a bare div chromium prunes from the
|
|
355
|
+
// accessibility tree as "uninteresting".
|
|
356
|
+
<Show
|
|
357
|
+
when={m().avatar}
|
|
358
|
+
fallback={
|
|
359
|
+
<Message role={m().role} class={`${rowGroup()}${m().role === 'user' ? 'flex-col items-end' : 'flex-col items-start'}`}>
|
|
360
|
+
{body}
|
|
361
|
+
</Message>
|
|
362
|
+
}
|
|
363
|
+
>
|
|
364
|
+
{(av) => (
|
|
365
|
+
<Message role={m().role} class={rowGroup()}>
|
|
366
|
+
<MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />
|
|
367
|
+
<div class={`flex min-w-0 flex-1 flex-col ${m().role === 'user' ? 'items-end' : 'items-start'}`}>
|
|
368
|
+
{body}
|
|
369
|
+
</div>
|
|
370
|
+
</Message>
|
|
371
|
+
)}
|
|
372
|
+
</Show>
|
|
373
|
+
);
|
|
374
|
+
}}
|
|
375
|
+
</Show>
|
|
376
|
+
)}
|
|
302
377
|
</For>
|
|
303
378
|
<ChatContainerScrollAnchor />
|
|
304
379
|
</ChatContainerContent>
|
|
@@ -325,6 +400,7 @@ export function ChatThread(props: ChatThreadProps) {
|
|
|
325
400
|
<DefaultPromptInput
|
|
326
401
|
value={current()} placeholder={props.placeholder} loading={props.loading === true}
|
|
327
402
|
suggestions={visibleSuggestions()} attachments={attachments()}
|
|
403
|
+
accept={props.accept} onAttachmentsRejected={props.onAttachmentsRejected}
|
|
328
404
|
search={props.search === true} voice={props.voice === true}
|
|
329
405
|
triggers={props.triggers} kindIcons={props.kindIcons}
|
|
330
406
|
onValueChange={handleChange} onSubmit={handleSubmit} onSuggestionClick={handleSuggestionClick}
|
|
@@ -337,7 +413,7 @@ export function ChatThread(props: ChatThreadProps) {
|
|
|
337
413
|
</Show>
|
|
338
414
|
</div>
|
|
339
415
|
</div>
|
|
340
|
-
{/* INJECT
|
|
416
|
+
{/* INJECT: footer row below the composer. */}
|
|
341
417
|
<Show when={props.footer}>
|
|
342
418
|
<div part="footer" class="shrink-0 px-4 pb-3">
|
|
343
419
|
<div class="mx-auto max-w-3xl text-center text-xs text-muted-foreground"><slot name="footer" /></div>
|
|
@@ -24,37 +24,25 @@ import { useCardHost } from '../primitives/card-host';
|
|
|
24
24
|
import { Check, X } from 'lucide-solid';
|
|
25
25
|
|
|
26
26
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
-
// Types (choice.schema.json) —
|
|
27
|
+
// Types (choice.schema.json) — AUTHORED IN ../primitives/card-data-types.ts.
|
|
28
|
+
// See the note in confirm-card.tsx, or that file's header, for why they left a
|
|
29
|
+
// `.tsx` and why they are `type` aliases. Re-exported here unchanged.
|
|
28
30
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
payload?: unknown; // echoed back in the emitted action
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type ChoiceAllowOther = boolean | { label?: string; placeholder?: string };
|
|
48
|
-
|
|
49
|
-
export interface ChoiceCardData {
|
|
50
|
-
prompt?: string; // optional question/body above the options
|
|
51
|
-
options: ChoiceOption[]; // 1..N
|
|
52
|
-
allowOther?: ChoiceAllowOther; // free-text escape
|
|
53
|
-
submitLabel?: string; // label for the Submit button (default 'Submit')
|
|
54
|
-
dismissible?: boolean; // show a close affordance that emits `dismiss`
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type ChoiceCardEnvelope = CardEnvelope<'choice', ChoiceCardData>;
|
|
32
|
+
import type {
|
|
33
|
+
ChoiceAllowOther,
|
|
34
|
+
ChoiceCardData,
|
|
35
|
+
ChoiceOption,
|
|
36
|
+
ChoiceOptionMedia,
|
|
37
|
+
} from '../primitives/card-data-types';
|
|
38
|
+
|
|
39
|
+
export type {
|
|
40
|
+
ChoiceAllowOther,
|
|
41
|
+
ChoiceCardData,
|
|
42
|
+
ChoiceCardEnvelope,
|
|
43
|
+
ChoiceOption,
|
|
44
|
+
ChoiceOptionMedia,
|
|
45
|
+
} from '../primitives/card-data-types';
|
|
58
46
|
|
|
59
47
|
export const CHOICE_CARD_TYPE = 'choice' as const;
|
|
60
48
|
|