@kitn.ai/ui 0.20.0 → 0.21.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 +68 -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-D3Y5qiij.js +338 -0
- package/dist/create-tween-DGKY1FDY.js +341 -0
- package/dist/create-tween-paho5Rh-.js +7 -0
- package/dist/custom-elements.json +1681 -454
- 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-C-2LvGDG.js} +1 -1
- package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-CaYoImEk.js} +1 -1
- package/dist/elements/chunks/arrow-left-Bb46H7w9.js +1 -0
- package/dist/elements/chunks/artifact-BBIscOxJ.js +1 -0
- package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-BB56zoji.js} +1 -1
- package/dist/elements/chunks/audio-visualizer-BxOx4THz.js +1 -0
- package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-SxLSZ19R.js} +1 -1
- package/dist/elements/chunks/{button-ZWNif3--.js → button-CmkUkz6c.js} +1 -1
- package/dist/elements/chunks/card-renderer-Db4ffkWv.js +1 -0
- package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
- package/dist/elements/chunks/chat-thread-B3Ks-cKr.js +1 -0
- package/dist/elements/chunks/check-C8desc_h.js +1 -0
- package/dist/elements/chunks/chevron-down-DKtc2HNB.js +1 -0
- package/dist/elements/chunks/chevron-right-Dw4GPhwL.js +1 -0
- package/dist/elements/chunks/choice-card-Q9cYYDyM.js +1 -0
- package/dist/elements/chunks/circle-BeokBsvB.js +1 -0
- package/dist/elements/chunks/circle-check-wJSqt859.js +1 -0
- package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-D0MEfxOM.js} +1 -1
- package/dist/elements/chunks/code-block-C8VzAraE.js +1 -0
- package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-Cvj61obE.js} +1 -1
- package/dist/elements/chunks/{composer-BguS0QL_.js → composer-D86ztyL0.js} +2 -2
- package/dist/elements/chunks/confirm-card-BdyDAGLw.js +1 -0
- package/dist/elements/chunks/context-WHDl-xSx.js +1 -0
- package/dist/elements/chunks/conversation-list-CdR14_Y4.js +1 -0
- package/dist/elements/chunks/create-tween-C_A_B638.js +7 -0
- package/dist/elements/chunks/{default-input-Cqqilg9t.js → default-input-CSZqUM81.js} +1 -1
- package/dist/elements/chunks/define-BzPnNsXg.js +1 -0
- package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DVKsoc1F.js} +1 -1
- package/dist/elements/chunks/{download-Dsbg3ste.js → download-BjA54IMJ.js} +1 -1
- package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-BjVVHWXH.js} +1 -1
- package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BNedmqfi.js} +1 -1
- package/dist/elements/chunks/embed-DQsl4XEq.js +1 -0
- package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-Di-dw2CU.js} +1 -1
- package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-B3sAODCV.js} +1 -1
- package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-Dgto-bMn.js} +1 -1
- package/dist/elements/chunks/{folder-glP5rha4.js → folder-D6rMadFV.js} +1 -1
- package/dist/elements/chunks/form-CILxvhQ7.js +1 -0
- package/dist/elements/chunks/hover-card-BtiF4XiU.js +1 -0
- package/dist/elements/chunks/{icon-BLb8beoi.js → icon-DKkmze3y.js} +1 -1
- package/dist/elements/chunks/{info-CIsv92JK.js → info-CWRjZkuy.js} +1 -1
- package/dist/elements/chunks/{input-Dds1kFyt.js → input--QJBK6BA.js} +1 -1
- package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-C3zuKh8R.js} +1 -1
- package/dist/elements/chunks/{link-i4r_k7z4.js → link-BL5JA7Q0.js} +1 -1
- package/dist/elements/chunks/link-preview-CU37bbXh.js +1 -0
- package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-XmpyxyRH.js} +1 -1
- package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-3Gv5UZ_o.js} +1 -1
- package/dist/elements/chunks/message-CnBA2OUt.js +1 -0
- package/dist/elements/chunks/message-X5NZbq-W.js +1 -0
- package/dist/elements/chunks/message-square-CnpAm_P0.js +1 -0
- package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-DwyrUTcM.js} +1 -1
- package/dist/elements/chunks/{model-switcher-B94YAKsM.js → model-switcher-CclaJEHt.js} +1 -1
- package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-Cepd-KcS.js} +1 -1
- package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CdwKjrlu.js} +1 -1
- package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-DMVXBD3b.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-Di_WZE_5.js} +1 -1
- package/dist/elements/chunks/reasoning-D0jMch5u.js +1 -0
- package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-1znbL1Gv.js} +1 -1
- package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-DVhhgx8n.js} +1 -1
- package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-Bs4bFS1P.js} +1 -1
- package/dist/elements/chunks/scroll-button-Bet5NLc4.js +1 -0
- package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-C5Gh8qGC.js} +1 -1
- package/dist/elements/chunks/{settings-B8lmec4D.js → settings-5vmEFg0K.js} +1 -1
- package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-BWLB38kz.js} +1 -1
- package/dist/elements/chunks/{share-C3lTiYGt.js → share-BZ3G_DaB.js} +1 -1
- package/dist/elements/chunks/skeleton-DafPJQTp.js +1 -0
- package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
- package/dist/elements/chunks/source-D_qj_6uJ.js +1 -0
- package/dist/elements/chunks/{star-CSJtGxgv.js → star-Cuv7j2IE.js} +1 -1
- package/dist/elements/chunks/{store-CHyW95TP.js → store-C1StPHfW.js} +1 -1
- package/dist/elements/chunks/tasks-card-EyoBZfpA.js +1 -0
- package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D9gRSh34.js} +1 -1
- package/dist/elements/chunks/textarea-DuhtHfcm.js +1 -0
- package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-B9hwv43w.js} +1 -1
- package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-Bm3DUEDe.js} +1 -1
- package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-CDtW7L0z.js} +1 -1
- package/dist/elements/chunks/tooltip-eB226mGK.js +1 -0
- package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C1SNzTqK.js} +1 -1
- package/dist/elements/chunks/use-card-resolution-YZh2MvI5.js +1 -0
- package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Cj1F7D0l.js} +2 -2
- package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-T9gpt7QE.js} +1 -1
- package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-CxU9z-TE.js} +2 -2
- package/dist/elements/chunks/{video-B7vmenoC.js → video-CK4R7Rus.js} +1 -1
- package/dist/elements/chunks/x-D1qx0aLd.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 +7 -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 +2 -2
- 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/slots.d.ts +16 -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 +2725 -214
- package/dist/index.d.ts +163 -125
- package/dist/index.js +6336 -5802
- package/dist/index.server.d.ts +5 -0
- package/dist/index.server.js +16913 -0
- 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 +762 -148
- package/dist/llms/llms.txt +57 -5
- package/dist/mcp.es.js +4010 -770
- 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 +717 -299
- package/dist/react/use-kai-chat.d.ts +8 -4
- package/dist/react.d.ts +5 -0
- package/dist/react.js +417 -316
- package/dist/register-impl-bzrZ44ft.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-BCJUQqwS.js +22750 -0
- package/dist/solid-BdENBcEq.js +20108 -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-1wMcXRUS.js +381 -0
- package/dist/variant-aurora-BKHHiOgL.js +391 -0
- package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-DOb_o4pC.js} +1 -1
- package/dist/{variant-custom-Dif-IV4u.js → variant-custom-CJGB0Kbw.js} +1 -1
- package/dist/variant-custom-Co0CkXJF.js +200 -0
- package/dist/variant-custom-DWSSgmd2.js +170 -0
- package/dist/variant-wave-C3-45cL6.js +218 -0
- package/dist/{variant-wave-DbfNdvSi.js → variant-wave-CEODq-9q.js} +1 -1
- package/dist/variant-wave-jdXBnCUZ.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 +148 -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 +14 -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 +898 -0
- package/frameworks/react/index.tsx +183 -154
- package/frameworks/react/runtime.tsx +21 -1
- package/frameworks/react/use-kai-chat.tsx +11 -1
- package/llms-full.txt +762 -148
- package/llms.txt +57 -5
- package/package.json +65 -7
- package/src/agent-tooling/archetypes.ts +96 -0
- package/src/agent-tooling/integrations/anthropic.ts +412 -0
- package/src/agent-tooling/integrations/cloudflare.ts +136 -52
- package/src/agent-tooling/integrations/langgraph.ts +67 -13
- package/src/agent-tooling/integrations/mastra.ts +120 -12
- package/src/agent-tooling/integrations/mock.ts +43 -8
- package/src/agent-tooling/integrations/ollama.ts +61 -24
- package/src/agent-tooling/integrations/openai.ts +87 -0
- package/src/agent-tooling/integrations/openrouter.ts +56 -8
- package/src/agent-tooling/integrations/pi.ts +79 -23
- package/src/agent-tooling/integrations/pydantic-ai.ts +24 -2
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +84 -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 +3345 -675
- package/src/agent-tooling/registry.ts +17 -0
- package/src/agent-tooling/types.ts +229 -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 +118 -51
- 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 +12 -4
- 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/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 +11 -5
- 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 +3 -3
- 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 +64 -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 +3 -3
- 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 +1596 -304
- package/src/elements/element-types.d.ts +2636 -211
- 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 +10 -29
- 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/slots.ts +57 -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 +141 -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 +474 -0
- package/src/wire/formats/anthropic.ts +267 -0
- package/src/wire/formats/openai.ts +187 -0
- package/src/wire/index.ts +52 -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/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/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,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';
|
|
@@ -16,6 +16,8 @@ import type { TriggerDef } from './composer';
|
|
|
16
16
|
import type { ChatMessage } from '../elements/chat-types';
|
|
17
17
|
import type { ProseSize } from '../primitives/chat-config';
|
|
18
18
|
import type { ModelOption } from '../types';
|
|
19
|
+
import type { CardComponentMap } from '../primitives/card-registry';
|
|
20
|
+
import type { CardSchemaMap } from './card-renderer';
|
|
19
21
|
|
|
20
22
|
export interface ChatThreadContextUsage {
|
|
21
23
|
usedTokens: number;
|
|
@@ -29,9 +31,19 @@ export interface ChatThreadProps {
|
|
|
29
31
|
/** Extra classes for the thread root (e.g. `h-full`). */
|
|
30
32
|
class?: string;
|
|
31
33
|
/** The full message thread to render, newest last. Each entry carries its role,
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* ordered `parts`, and optional actions/avatar/feedback. Set as a JS property
|
|
35
|
+
* (`el.messages = [...]`). */
|
|
34
36
|
messages: ChatMessage[];
|
|
37
|
+
/** Add/override card type -> component entries, forwarded to `CardRenderer`
|
|
38
|
+
* for `card` parts. */
|
|
39
|
+
cardTypes?: CardComponentMap;
|
|
40
|
+
/** JSON Schemas for the card types this app renders, keyed by envelope type,
|
|
41
|
+
* forwarded to `CardRenderer` for `card` parts. The companion of `cardTypes`:
|
|
42
|
+
* that says what DRAWS a card, this says what a VALID one looks like.
|
|
43
|
+
* `createCardRegistry(...).validationSchemas` is exactly this shape. Without it
|
|
44
|
+
* the kit checks its own seven built-ins and leaves your own card type
|
|
45
|
+
* unvalidated. A schema here WINS over a built-in of the same name. */
|
|
46
|
+
cardSchemas?: CardSchemaMap;
|
|
35
47
|
/** Value of the input. A **string** is controlled (the host owns the text and
|
|
36
48
|
* updates it on `kai-value-change`). A **ComposerDoc** is a one-time seed that
|
|
37
49
|
* pre-populates pills; the user then edits freely. Leave unset for uncontrolled. */
|
|
@@ -72,8 +84,8 @@ export interface ChatThreadProps {
|
|
|
72
84
|
context?: ChatThreadContextUsage;
|
|
73
85
|
/** Show the scroll-to-bottom button inside the scroll area. Default true. */
|
|
74
86
|
scrollButton?: boolean;
|
|
75
|
-
/** Whether the host has `slot="header-start"` content (left of the title)
|
|
76
|
-
*
|
|
87
|
+
/** Whether the host has `slot="header-start"` content (left of the title). Set
|
|
88
|
+
* by the `<kai-chat>` facade so a custom control forces the header open. */
|
|
77
89
|
headerStart?: boolean;
|
|
78
90
|
/** Whether the host has `slot="header-end"` content (right of the controls). */
|
|
79
91
|
headerEnd?: boolean;
|
|
@@ -87,24 +99,24 @@ export interface ChatThreadProps {
|
|
|
87
99
|
// content owns its own data/events — a slotted (light-DOM) node
|
|
88
100
|
// can't read this component's reactive state. That boundary is
|
|
89
101
|
// the whole reason `messages` stays a data prop, not a slot.
|
|
90
|
-
/** REPLACE
|
|
102
|
+
/** REPLACE: full custom header in place of the built-in title/model/context bar. */
|
|
91
103
|
headerFull?: boolean;
|
|
92
|
-
/** INJECT
|
|
104
|
+
/** INJECT: left sidebar column (e.g. a conversation list / your own nav). */
|
|
93
105
|
sidebar?: boolean;
|
|
94
|
-
/** REPLACE
|
|
106
|
+
/** 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
107
|
empty?: boolean;
|
|
96
|
-
/** REPLACE
|
|
108
|
+
/** REPLACE: full custom composer in place of the built-in prompt input. The
|
|
97
109
|
* projected content wires its own submit (the data-flow boundary). */
|
|
98
110
|
composer?: boolean;
|
|
99
|
-
/** INJECT
|
|
111
|
+
/** INJECT: accessory row just above the composer (e.g. extra actions). */
|
|
100
112
|
composerActions?: boolean;
|
|
101
|
-
/** INJECT
|
|
113
|
+
/** INJECT: footer row below the composer (disclaimers, token meter, …). */
|
|
102
114
|
footer?: boolean;
|
|
103
115
|
/** Show a Search (Globe) button in the input toolbar; fires a `search` event. */
|
|
104
116
|
search?: boolean;
|
|
105
117
|
/** Show a Voice (Mic) button in the input toolbar; fires a `voice` event. */
|
|
106
118
|
voice?: boolean;
|
|
107
|
-
/** Rich entity triggers
|
|
119
|
+
/** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored
|
|
108
120
|
* menu that inserts an atomic pill (`/` skills, `@` agents/plugins). Set as a
|
|
109
121
|
* JS property; forwarded to the input. */
|
|
110
122
|
triggers?: TriggerDef[];
|
|
@@ -136,9 +148,48 @@ export interface ChatThreadController {
|
|
|
136
148
|
scrollToBottom(behavior?: ScrollBehavior): void;
|
|
137
149
|
}
|
|
138
150
|
|
|
151
|
+
/**
|
|
152
|
+
* THE MESSAGE LIST'S KEY, and the reason it is not the message object. This is
|
|
153
|
+
* the canonical note; `thread.tsx` keys its identical list the same way and
|
|
154
|
+
* points here.
|
|
155
|
+
*
|
|
156
|
+
* `<For>` is REFERENCE-keyed, and a streaming assistant message gets a brand
|
|
157
|
+
* new object identity on every delta — `createAssistantStream` rebuilds it as
|
|
158
|
+
* `{ ...prev[i], parts: next }` because a new reference IS the re-render
|
|
159
|
+
* signal. Keyed on the objects, every chunk therefore looks like an entirely
|
|
160
|
+
* new list: the whole message row is torn down and rebuilt, and everything the
|
|
161
|
+
* user did inside it dies with it. Expanding a tool or reasoning panel
|
|
162
|
+
* mid-stream did nothing at all — the disclosure opened and was discarded
|
|
163
|
+
* microseconds later by the next token. (`MessageBody` keys its PARTS by
|
|
164
|
+
* position for exactly this reason; that fix was dead while its parent kept
|
|
165
|
+
* destroying the subtree above it.)
|
|
166
|
+
*
|
|
167
|
+
* So key on `message.id`, which is stable across the object churn: `<For>` over
|
|
168
|
+
* the id array diffs by string value, a delta produces an identical id list,
|
|
169
|
+
* and no row moves. The row then reads its message through `messages[i()]` —
|
|
170
|
+
* `<For>`'s index accessor, which it keeps current across inserts, removals and
|
|
171
|
+
* moves — so the CONTENT keeps updating through accessors while the DOM stays
|
|
172
|
+
* put.
|
|
173
|
+
*
|
|
174
|
+
* WHY NOT `<Index>`, the other way to survive the churn: `<Index>` keys by
|
|
175
|
+
* POSITION, so a row's local state (an open panel, a half-filled form card)
|
|
176
|
+
* belongs to the slot rather than to the message. Appends and tail truncations
|
|
177
|
+
* (regenerate/edit) are fine, but prepending older turns — load-earlier-history,
|
|
178
|
+
* which every real chat grows — shifts every row, and each open disclosure
|
|
179
|
+
* stays behind with the wrong message. Position IS a valid key inside a
|
|
180
|
+
* message, where the folds only ever append or patch a part in place; it is not
|
|
181
|
+
* one for the message list, where the host owns the array and splices it.
|
|
182
|
+
* Both approaches require the row to read through accessors — that is inherent
|
|
183
|
+
* in keeping a row mounted while its object is replaced, not a cost unique to
|
|
184
|
+
* either.
|
|
185
|
+
*
|
|
186
|
+
* Contract: `id` must be unique per message. It already had to be — the
|
|
187
|
+
* feedback/copy state above this list is keyed by it.
|
|
188
|
+
*/
|
|
139
189
|
export function ChatThread(props: ChatThreadProps) {
|
|
140
190
|
const outer = useChatConfig();
|
|
141
191
|
const reveal = () => (props.actionsReveal === 'hover' ? 'hover' : 'always');
|
|
192
|
+
const messageKeys = createMemo(() => props.messages.map((m) => m.id));
|
|
142
193
|
// Feedback (copy + vote) state lives ABOVE the per-message <For>, so streaming
|
|
143
194
|
// re-renders (a fresh `messages` array ref per chunk) don't wipe it.
|
|
144
195
|
// The copy/feedback toasts scope to the chat (this thread's root) so they appear
|
|
@@ -261,44 +312,60 @@ export function ChatThread(props: ChatThreadProps) {
|
|
|
261
312
|
<Show when={props.empty && props.messages.length === 0}>
|
|
262
313
|
<slot name="empty" />
|
|
263
314
|
</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
|
-
|
|
315
|
+
{/* Keyed by message id (see the note above this component), so a
|
|
316
|
+
streaming delta updates the row instead of replacing it. */}
|
|
317
|
+
<For each={messageKeys()}>
|
|
318
|
+
{(_id, i) => (
|
|
319
|
+
// The row reads its message through <For>'s index accessor,
|
|
320
|
+
// never through a captured value: the row outlives the delta
|
|
321
|
+
// that replaced its object, so every read below has to go
|
|
322
|
+
// through `m()` for the new content to land. <Show> supplies
|
|
323
|
+
// the non-null accessor and covers the frame where a removal
|
|
324
|
+
// has shortened the array.
|
|
325
|
+
<Show when={props.messages[i()]}>
|
|
326
|
+
{(m) => {
|
|
327
|
+
const body = (
|
|
328
|
+
<MessageBody
|
|
329
|
+
parts={m().parts}
|
|
330
|
+
cardTypes={props.cardTypes}
|
|
331
|
+
cardSchemas={props.cardSchemas}
|
|
332
|
+
isUser={m().role === 'user'}
|
|
333
|
+
markdown={m().role === 'assistant'}
|
|
334
|
+
actions={m().actions}
|
|
335
|
+
actionsReveal={reveal()}
|
|
336
|
+
activeFeedback={feedback.resolveFeedback(m())}
|
|
337
|
+
copied={feedback.isCopied(m().id)}
|
|
338
|
+
onAction={(action) => feedback.handleAction(m(), action)}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
const rowGroup = () => (reveal() === 'hover' ? 'group ' : '');
|
|
342
|
+
return (
|
|
343
|
+
// `role` is the SPEAKER, forwarded on BOTH branches —
|
|
344
|
+
// see the same note in thread.tsx. `Message` turns it
|
|
345
|
+
// into `role="article"` + an `aria-label`; without it the
|
|
346
|
+
// row is a bare div chromium prunes from the
|
|
347
|
+
// accessibility tree as "uninteresting".
|
|
348
|
+
<Show
|
|
349
|
+
when={m().avatar}
|
|
350
|
+
fallback={
|
|
351
|
+
<Message role={m().role} class={`${rowGroup()}${m().role === 'user' ? 'flex-col items-end' : 'flex-col items-start'}`}>
|
|
352
|
+
{body}
|
|
353
|
+
</Message>
|
|
354
|
+
}
|
|
355
|
+
>
|
|
356
|
+
{(av) => (
|
|
357
|
+
<Message role={m().role} class={rowGroup()}>
|
|
358
|
+
<MessageAvatar src={av().src ?? ''} alt={av().alt ?? ''} fallback={av().fallback} />
|
|
359
|
+
<div class={`flex min-w-0 flex-1 flex-col ${m().role === 'user' ? 'items-end' : 'items-start'}`}>
|
|
360
|
+
{body}
|
|
361
|
+
</div>
|
|
362
|
+
</Message>
|
|
363
|
+
)}
|
|
364
|
+
</Show>
|
|
365
|
+
);
|
|
366
|
+
}}
|
|
367
|
+
</Show>
|
|
368
|
+
)}
|
|
302
369
|
</For>
|
|
303
370
|
<ChatContainerScrollAnchor />
|
|
304
371
|
</ChatContainerContent>
|
|
@@ -337,7 +404,7 @@ export function ChatThread(props: ChatThreadProps) {
|
|
|
337
404
|
</Show>
|
|
338
405
|
</div>
|
|
339
406
|
</div>
|
|
340
|
-
{/* INJECT
|
|
407
|
+
{/* INJECT: footer row below the composer. */}
|
|
341
408
|
<Show when={props.footer}>
|
|
342
409
|
<div part="footer" class="shrink-0 px-4 pb-3">
|
|
343
410
|
<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
|
|
|
@@ -469,11 +469,21 @@ export function Composer(props: ComposerProps): JSX.Element {
|
|
|
469
469
|
const handleBlur = (e: FocusEvent) => { focused = false; clearPillSelection(); props.onBlur?.(e); };
|
|
470
470
|
|
|
471
471
|
onMount(() => {
|
|
472
|
+
// Captured at SETUP and closed over, never re-resolved as a global inside
|
|
473
|
+
// `onCleanup`: cleanup can run after the host removed the DOM globals (a
|
|
474
|
+
// `kai-*` release is deferred one microtask past detachment, so an
|
|
475
|
+
// environment teardown gets in between), and a bare `document` there throws
|
|
476
|
+
// -- from a promise nobody holds, so it lands as an unhandled rejection that
|
|
477
|
+
// fails the run while every test passes. That is how this was found.
|
|
478
|
+
// See tests/components/teardown-without-dom-globals.test.tsx.
|
|
479
|
+
// `ownerDocument` rather than a captured `document`, matching the rest of
|
|
480
|
+
// this file and staying correct for a composer inside an iframe.
|
|
481
|
+
const doc = editable.ownerDocument;
|
|
472
482
|
const onSelectionChange = () => {
|
|
473
483
|
if (focused) updateTriggerState();
|
|
474
484
|
};
|
|
475
|
-
|
|
476
|
-
onCleanup(() =>
|
|
485
|
+
doc.addEventListener('selectionchange', onSelectionChange);
|
|
486
|
+
onCleanup(() => doc.removeEventListener('selectionchange', onSelectionChange));
|
|
477
487
|
});
|
|
478
488
|
|
|
479
489
|
// --- Imperative controller (Pattern C): hand the facade a handle over the
|
|
@@ -21,29 +21,33 @@ import { useCardHost } from '../primitives/card-host';
|
|
|
21
21
|
import { AlertTriangle, Check, X } from 'lucide-solid';
|
|
22
22
|
|
|
23
23
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
-
// Types (confirm.schema.json) —
|
|
24
|
+
// Types (confirm.schema.json) — AUTHORED IN ../primitives/card-data-types.ts.
|
|
25
|
+
//
|
|
26
|
+
// They used to be declared here, and moving them is the fourth instance of the
|
|
27
|
+
// split card-tags.ts and card-component-types.ts already made twice: a type
|
|
28
|
+
// import still has to RESOLVE, so while these lived in a `.tsx` no Node/no-DOM
|
|
29
|
+
// project could name them (TS6142), which meant `@kitn.ai/ui/schemas` could not
|
|
30
|
+
// re-export them and a TypeScript backend building a card envelope got
|
|
31
|
+
// `data: unknown` while Python and Go read the full shape out of the published
|
|
32
|
+
// JSON Schemas. They are also `type` aliases rather than `interface`s now, which
|
|
33
|
+
// is what makes `el.data = myConfirmCardData` compile — see that file's header
|
|
34
|
+
// for both measurements. Re-exported here, so this module's surface is unchanged.
|
|
25
35
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
26
36
|
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
import type {
|
|
38
|
+
ConfirmAction,
|
|
39
|
+
ConfirmActionStyle,
|
|
40
|
+
ConfirmCardData,
|
|
41
|
+
ConfirmTone,
|
|
42
|
+
} from '../primitives/card-data-types';
|
|
29
43
|
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ConfirmCardData {
|
|
39
|
-
heading?: string;
|
|
40
|
-
body?: string;
|
|
41
|
-
tone?: ConfirmTone;
|
|
42
|
-
actions: ConfirmAction[]; // 1..4
|
|
43
|
-
dismissible?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type ConfirmCardEnvelope = CardEnvelope<'confirm', ConfirmCardData>;
|
|
44
|
+
export type {
|
|
45
|
+
ConfirmAction,
|
|
46
|
+
ConfirmActionStyle,
|
|
47
|
+
ConfirmCardData,
|
|
48
|
+
ConfirmCardEnvelope,
|
|
49
|
+
ConfirmTone,
|
|
50
|
+
} from '../primitives/card-data-types';
|
|
47
51
|
|
|
48
52
|
export const CONFIRM_CARD_TYPE = 'confirm' as const;
|
|
49
53
|
|
|
@@ -306,7 +306,15 @@ export interface ContextUsageRowProps {
|
|
|
306
306
|
children?: JSX.Element;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
-
|
|
309
|
+
// The four rows share one shape, but each still ships a `<Name>Props` alias: a
|
|
310
|
+
// consumer typing a wrapper around one of them should not have to discover that
|
|
311
|
+
// the shared name exists.
|
|
312
|
+
export type ContextInputUsageProps = ContextUsageRowProps;
|
|
313
|
+
export type ContextOutputUsageProps = ContextUsageRowProps;
|
|
314
|
+
export type ContextReasoningUsageProps = ContextUsageRowProps;
|
|
315
|
+
export type ContextCacheUsageProps = ContextUsageRowProps;
|
|
316
|
+
|
|
317
|
+
export function ContextInputUsage(props: ContextInputUsageProps) {
|
|
310
318
|
const ctx = useContextValue();
|
|
311
319
|
return (
|
|
312
320
|
<Show when={props.children || ctx.inputTokens}>
|
|
@@ -320,7 +328,7 @@ export function ContextInputUsage(props: ContextUsageRowProps) {
|
|
|
320
328
|
);
|
|
321
329
|
}
|
|
322
330
|
|
|
323
|
-
export function ContextOutputUsage(props:
|
|
331
|
+
export function ContextOutputUsage(props: ContextOutputUsageProps) {
|
|
324
332
|
const ctx = useContextValue();
|
|
325
333
|
return (
|
|
326
334
|
<Show when={props.children || ctx.outputTokens}>
|
|
@@ -334,7 +342,7 @@ export function ContextOutputUsage(props: ContextUsageRowProps) {
|
|
|
334
342
|
);
|
|
335
343
|
}
|
|
336
344
|
|
|
337
|
-
export function ContextReasoningUsage(props:
|
|
345
|
+
export function ContextReasoningUsage(props: ContextReasoningUsageProps) {
|
|
338
346
|
const ctx = useContextValue();
|
|
339
347
|
return (
|
|
340
348
|
<Show when={props.children || ctx.reasoningTokens}>
|
|
@@ -348,7 +356,7 @@ export function ContextReasoningUsage(props: ContextUsageRowProps) {
|
|
|
348
356
|
);
|
|
349
357
|
}
|
|
350
358
|
|
|
351
|
-
export function ContextCacheUsage(props:
|
|
359
|
+
export function ContextCacheUsage(props: ContextCacheUsageProps) {
|
|
352
360
|
const ctx = useContextValue();
|
|
353
361
|
return (
|
|
354
362
|
<Show when={props.children || ctx.cacheTokens}>
|
|
@@ -16,7 +16,9 @@ import type { ConversationSummary, ConversationGroup } from '../types';
|
|
|
16
16
|
* surrounding region (the workspace puts the thread beside it, the standalone
|
|
17
17
|
* element stands alone). `onExpand` reopens the rail.
|
|
18
18
|
*/
|
|
19
|
-
export
|
|
19
|
+
export interface CollapsedRailProps { onExpand: () => void; class?: string }
|
|
20
|
+
|
|
21
|
+
export function CollapsedRail(props: CollapsedRailProps) {
|
|
20
22
|
return (
|
|
21
23
|
<Button
|
|
22
24
|
variant="ghost" size="icon-sm" aria-label="Open sidebar"
|
|
@@ -94,7 +96,21 @@ export function ConversationList(props: ConversationListProps) {
|
|
|
94
96
|
return grouped;
|
|
95
97
|
});
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Everything that is NOT filed under a rendered group heading: no `groupId` at
|
|
101
|
+
* all, OR a `groupId` that matches no entry in `groups`.
|
|
102
|
+
*
|
|
103
|
+
* The second half used to be dropped on the floor. `groups` drives the render
|
|
104
|
+
* loop, so a conversation pointing at a group the consumer had not declared
|
|
105
|
+
* (a stale id, a group removed from the array, a filtered/paginated `groups`
|
|
106
|
+
* response) vanished from the sidebar with no error and no empty state — the
|
|
107
|
+
* list just silently held fewer rows than the data it was given. Falling through
|
|
108
|
+
* to "Ungrouped" keeps every conversation the consumer passed in reachable.
|
|
109
|
+
*/
|
|
110
|
+
const ungrouped = createMemo(() => {
|
|
111
|
+
const known = new Set((local.groups ?? []).map((g) => g.id));
|
|
112
|
+
return filteredConversations().filter((c) => c.groupId == null || !known.has(c.groupId));
|
|
113
|
+
});
|
|
98
114
|
|
|
99
115
|
return (
|
|
100
116
|
<div class={cn('flex flex-col h-full bg-sidebar', local.class)}>
|