@kitn.ai/ui 0.25.2 → 0.27.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 +17 -6
- package/bin/mcp.js +16 -3
- package/bin/route.js +23 -0
- package/bin/route.test.js +58 -0
- package/dist/{elements/chunks/Icon-b5A8hlHs.js → Icon-BnFKqqtY.js} +1 -1
- package/dist/action-icons-CBskfBMz.js +1 -0
- package/dist/arrow-down-Br0qtpsz.js +1 -0
- package/dist/arrow-left-Dj7xgE12.js +1 -0
- package/dist/artifact-CvXEm1lS.js +1 -0
- package/dist/assets/dev-5XzXYR21.js +91 -0
- package/dist/attachments-C43ZegEq.js +1 -0
- package/dist/audio-visualizer-B-79y1Tj.js +1 -0
- package/dist/badge-BpUbq8c0.js +1 -0
- package/dist/bash-InADTalH.js +1 -6
- package/dist/bell-sn17Ip9v.js +1 -0
- package/dist/{elements/chunks/button-B9okqG73.js → button-BH6rN0U-.js} +1 -1
- package/dist/card-renderer-Cb1gQmth.js +1 -0
- package/dist/card-routing-DifQgS7n.js +1 -0
- package/dist/check-DPeeMUYx.js +1 -0
- package/dist/checkbox-Dc9Yov_B.js +1 -0
- package/dist/checkbox-group-B1kDLLYk.js +1 -0
- package/dist/chevron-down-CHSWk7ZT.js +1 -0
- package/dist/chevron-right-B7l_fMgx.js +1 -0
- package/dist/choice-card-BT3c1S8g.js +1 -0
- package/dist/circle-Bb0yOpqM.js +1 -0
- package/dist/circle-check-BGZpCiz7.js +1 -0
- package/dist/circle-x-wobWkoSx.js +1 -0
- package/dist/{elements/chunks/cn-CU7UAWzk.js → cn-DN5AWfiS.js} +1 -1
- package/dist/code-block-CUQ5mtv0.js +1 -0
- package/dist/collapsible-CPJbf6FM.js +1 -0
- package/dist/components/attachment-types.d.ts +53 -1
- package/dist/components/attachments.d.ts +31 -0
- package/dist/components/audio-visualizer/fit-scale.d.ts +50 -0
- package/dist/components/audio-visualizer/index.d.ts +15 -1
- package/dist/components/audio-visualizer/variant-bar.d.ts +24 -1
- package/dist/components/card-renderer.d.ts +13 -0
- package/dist/components/card.d.ts +4 -0
- package/dist/components/chat-thread.d.ts +49 -42
- package/dist/components/code-block.d.ts +22 -0
- package/dist/components/conversation-item.d.ts +66 -1
- package/dist/components/conversation-list.d.ts +77 -0
- package/dist/components/form-widgets.d.ts +67 -2
- package/dist/components/form.d.ts +89 -0
- package/dist/components/message.d.ts +29 -0
- package/dist/components/reasoning.d.ts +6 -0
- package/dist/components/scroll-button.d.ts +11 -0
- package/dist/components/thread.d.ts +5 -0
- package/dist/components/toast.d.ts +2 -1
- package/dist/components/tool-types.d.ts +9 -0
- package/dist/components/voice-input.d.ts +8 -0
- package/dist/components/voice-output.d.ts +12 -1
- package/dist/components/workspace-shell.d.ts +87 -0
- package/dist/composer-CjngLzal.js +106 -0
- package/dist/confirm-card-DCx_A4bU.js +1 -0
- package/dist/construct-cli.es.js +1169 -0
- package/dist/context-BY8V-Nlp.js +1 -0
- package/dist/controllable-D43BKmtX.js +1 -0
- package/dist/conversation-list-D4lLU_yS.js +1 -0
- package/dist/copy-B6DO4PqB.js +1 -0
- package/dist/core-AYMC6_lb.js +12 -5874
- package/dist/{create-tween-CUzOlaMS.js → create-tween-BPzaefTp.js} +1 -1
- package/dist/{create-tween-B5Y4Im8G.js → create-tween-CnMHviKB.js} +1 -1
- package/dist/{create-tween-4z1XYLkR.js → create-tween-D1aiGZZh.js} +1 -1
- package/dist/{elements/chunks/create-tween-CUrM6D_o.js → create-tween-DUSQUKpr.js} +2 -2
- package/dist/css-M7EaDHN_.js +1 -6
- package/dist/custom-elements.json +3468 -1927
- package/dist/default-input-CucQEOqH.js +1 -0
- package/dist/define-CGGX-7Vg.js +1 -0
- package/dist/define.d.ts +4 -0
- package/dist/define.js +510 -0
- package/dist/define.server.d.ts +5 -0
- package/dist/define.server.js +506 -0
- package/dist/diagnostics/hook.d.ts +81 -0
- package/dist/diagnostics/index.d.ts +7 -0
- package/dist/diagnostics/report-request.d.ts +61 -0
- package/dist/diagnostics.d.ts +5 -0
- package/dist/diagnostics.js +209 -0
- package/dist/disclosure-CbLtajUQ.js +1 -0
- package/dist/dropdown-BwhViJFd.js +1 -0
- 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/autoloader.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-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkbox-group.d.ts +1 -0
- package/dist/elements/checkbox-group.js +1 -0
- package/dist/elements/checkbox.d.ts +1 -0
- package/dist/elements/checkbox.js +1 -0
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- 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-item.d.ts +1 -0
- package/dist/elements/conversation-item.js +1 -0
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/default-input.d.ts +3 -3
- package/dist/elements/define-entry.d.ts +12 -0
- package/dist/elements/define.d.ts +27 -0
- package/dist/elements/diagnostic-events.d.ts +74 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/dock.d.ts +1 -0
- package/dist/elements/dock.js +243 -0
- package/dist/elements/dropdown.d.ts +1 -0
- package/dist/elements/dropdown.js +1 -0
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +37 -0
- package/dist/elements/element-diagnostics.d.ts +81 -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-grid.d.ts +1 -0
- package/dist/elements/pane-grid.js +1 -0
- 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/radio-group.d.ts +1 -0
- package/dist/elements/radio-group.js +1 -0
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/register.d.ts +2 -0
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +3 -3
- 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/select.d.ts +1 -0
- package/dist/elements/select.js +1 -0
- 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/slider.d.ts +1 -0
- package/dist/elements/slider.js +1 -0
- package/dist/elements/slots.d.ts +36 -4
- 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/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +589 -167
- package/dist/{elements/chunks/ellipsis-CVxqfsDZ.js → ellipsis-DFr4Vqr3.js} +1 -1
- package/dist/embed-5s_vU4J0.js +1 -0
- package/dist/engine-javascript-vq0WuIJl.js +14 -2516
- package/dist/{elements/chunks/external-link-DG2sRdQL.js → external-link-u9d85ORQ.js} +1 -1
- package/dist/file-text-CX7_x42o.js +1 -0
- package/dist/{elements/chunks/file-tree-yGWNK0Js.js → file-tree-D3kBjXI5.js} +1 -1
- package/dist/folder-V-YdIL8f.js +1 -0
- package/dist/form-BRNUMCN2.js +1 -0
- package/dist/github-dark-dimmed-DUshB20C.js +1 -4
- package/dist/github-light-JYsPkUQd.js +1 -4
- package/dist/hover-card-DaeiYrTA.js +1 -0
- package/dist/html-CPZ3oZQ7.js +1 -10
- package/dist/icon-BpixdZNq.js +1 -0
- package/dist/{elements/chunks/index-BCRhi84a.js → index-xu_pdcPi.js} +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +8473 -6470
- package/dist/index.server.js +6495 -4958
- package/dist/info-8mFsIjS3.js +1 -0
- package/dist/input-d1Yuu-hz.js +1 -0
- package/dist/javascript-C25yR2R2.js +1 -6
- package/dist/json-DxJze_jm.js +1 -6
- package/dist/kai-provider.es.js +40 -40
- package/dist/kai.es.js +1 -1
- package/dist/kbd-961zMPFB.js +1 -0
- package/dist/link-DlZZBGaR.js +1 -0
- package/dist/{elements/chunks/link-preview-Cf5KOP-i.js → link-preview-DIIbV2Sd.js} +1 -1
- package/dist/loader-YQszHFaW.js +1 -0
- package/dist/{elements/chunks/markdown-DbozyYqa.js → markdown-CVk1MPsj.js} +1 -1
- package/dist/mcp.es.js +3873 -544
- package/dist/message-CwKVEdZg.js +1 -0
- package/dist/message-DS8lzHc1.js +1 -0
- package/dist/message-circle-Xf8Q-vZp.js +1 -0
- package/dist/message-square-Cxnwgkns.js +1 -0
- package/dist/{elements/chunks/minimize-2-SegJ_oku.js → minimize-2-UEZmP2QT.js} +1 -1
- package/dist/{elements/chunks/model-switcher-D7JrFFHp.js → model-switcher-Kk1jEQ5t.js} +1 -1
- package/dist/{elements/chunks/overlay-CV7z2YuX.js → overlay-C1od6LOz.js} +1 -1
- package/dist/panel-right-ryET0yyn.js +1 -0
- package/dist/paperclip-BDNoZFJP.js +1 -0
- package/dist/play-OFIvYXUQ.js +1 -0
- package/dist/primitives/card-data-types.d.ts +49 -0
- package/dist/primitives/card-routing.d.ts +1 -33
- package/dist/primitives/card-validate.d.ts +2 -2
- package/dist/primitives/chat-config.d.ts +29 -2
- package/dist/primitives/field-mask.d.ts +96 -0
- package/dist/primitives/field-semantics.d.ts +36 -0
- package/dist/primitives/input-mask.d.ts +46 -0
- package/dist/primitives/url-scheme-policy.d.ts +34 -0
- package/dist/primitives/use-resize-observer.d.ts +23 -0
- package/dist/primitives/use-speech-recognition.d.ts +8 -0
- package/dist/primitives/use-text-stream.d.ts +5 -0
- package/dist/progress-bar-BvYX0aoy.js +1 -0
- package/dist/prompt-suggestion-BRFu2lcu.js +1 -0
- package/dist/radio-DcL23cNJ.js +1 -0
- package/dist/react/index.d.ts +306 -283
- package/dist/react.js +309 -247
- package/dist/reasoning-Cackq4Rh.js +1 -0
- package/dist/register-impl-C7rENvPK.js +424 -0
- package/dist/{elements/chunks/resizable-Dpzjlvp4.js → resizable-Cp9HUYih.js} +1 -1
- package/dist/rotate-ccw-0DLRDHH5.js +1 -0
- package/dist/rotate-cw-DOB9IGcU.js +1 -0
- package/dist/schemas/form.schema.json +21 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/tool-defs.d.ts +45 -0
- package/dist/schemas.js +398 -305
- package/dist/scroll-area-emVmWP4K.js +1 -0
- package/dist/scroll-button-CeP_gv1x.js +1 -0
- package/dist/select-CWmu00tS.js +1 -0
- package/dist/{elements/chunks/separator-DH2r_ZSZ.js → separator-CE6vly6z.js} +1 -1
- package/dist/{elements/chunks/settings-BFMOd6yB.js → settings-CE-78SvZ.js} +1 -1
- package/dist/{elements/chunks/settings-group-B3VZKIcz.js → settings-group-ZFWNxFQR.js} +1 -1
- package/dist/{elements/chunks/skeleton-N8BuWYmf.js → skeleton-BebdP4mf.js} +1 -1
- package/dist/slider-BAKRYUlz.js +1 -0
- package/dist/slots-DaNjX0rc.js +1 -0
- package/dist/{solid-BMuDmFo_.js → solid-BE5ui6sy.js} +10672 -8116
- package/dist/{solid-CGYNdLRR.js → solid-DFhsce3O.js} +8137 -6056
- package/dist/solid.d.ts +15 -0
- package/dist/solid.js +248 -235
- package/dist/solid.server.js +248 -235
- package/dist/source-B0FlguSx.js +1 -0
- package/dist/star-CBMZvLuN.js +1 -0
- package/dist/state/index.d.ts +5 -1
- package/dist/state/mock.d.ts +32 -2
- package/dist/state/persistence.d.ts +51 -0
- package/dist/state/stream.d.ts +50 -0
- package/dist/state/threads.d.ts +71 -0
- package/dist/state.js +297 -172
- package/dist/store-7eoadydQ.js +1 -0
- package/dist/svelte--5p79yCD.js +1 -15
- package/dist/switch-CViARZCy.js +1 -0
- package/dist/tasks-card-MjCcOhR_.js +1 -0
- package/dist/text-shimmer-DKlwRF2G.js +1 -0
- package/dist/textarea-3ay2Me2-.js +1 -0
- package/dist/theme.tokens.css +82 -13
- package/dist/{elements/chunks/thumbs-up-DQe0hvkZ.js → thumbs-up-DQcu2HMO.js} +1 -1
- package/dist/toast-store-C6yKOhbk.js +1 -0
- package/dist/{elements/chunks/tool-C1YtxwPu.js → tool-BCYNlfKy.js} +1 -1
- package/dist/{elements/chunks/tooltip-BqwnFWhn.js → tooltip-05zI4hjs.js} +1 -1
- package/dist/trash-2-BR1RxGky.js +1 -0
- package/dist/{elements/chunks/triangle-alert-B6or7F5u.js → triangle-alert-DHohDOCy.js} +1 -1
- package/dist/tsx-B8rCNbgL.js +1 -6
- package/dist/types.d.ts +4 -2
- package/dist/typescript-RycA9KXf.js +1 -6
- package/dist/ui/checkbox-group.d.ts +83 -0
- package/dist/ui/checkbox.d.ts +40 -0
- package/dist/ui/dock.d.ts +131 -0
- package/dist/ui/hover-card.d.ts +44 -0
- package/dist/ui/icon.d.ts +3 -0
- package/dist/ui/input.d.ts +48 -2
- package/dist/ui/radio.d.ts +85 -0
- package/dist/ui/select.d.ts +71 -0
- package/dist/ui/slider.d.ts +65 -0
- package/dist/ui/switch.d.ts +9 -2
- package/dist/upload-BbGW6A_u.js +1 -0
- package/dist/url-scheme-policy-DHpoTJwB.js +1 -0
- package/dist/use-card-resolution-CJW4grFa.js +1 -0
- package/dist/{variant-aurora-DwSOfraQ.js → variant-aurora-BUOVgPOB.js} +27 -27
- package/dist/{variant-aurora-wKvAQ5wp.js → variant-aurora-CUsUJvFI.js} +28 -28
- package/dist/{variant-aurora-XEkPT0_z.js → variant-aurora-CW2i4bfr.js} +2 -2
- package/dist/{elements/chunks/variant-aurora-QXTZPyST.js → variant-aurora-xiMPty8f.js} +2 -2
- package/dist/variant-custom-BQtOnmeO.js +1 -0
- package/dist/{variant-custom-BhS9wIpU.js → variant-custom-CAm9L-E5.js} +65 -65
- package/dist/{variant-custom-eFIg2XWQ.js → variant-custom-CAnzzppW.js} +40 -40
- package/dist/variant-custom-D91HjAKz.js +1 -0
- package/dist/{variant-wave-CUWGx9Bn.js → variant-wave-Ca1Ls4_y.js} +21 -21
- package/dist/{variant-wave-CbVsmgwT.js → variant-wave-CxX39DKd.js} +25 -25
- package/dist/{variant-wave-BwzrHD1s.js → variant-wave-DYyzIIZv.js} +2 -2
- package/dist/{elements/chunks/variant-wave-DDCwhLas.js → variant-wave-uY5crU_K.js} +2 -2
- package/dist/vue-BmIZj4XD.js +1 -33
- package/dist/wire/chunk.d.ts +47 -0
- package/dist/wire/diagnostics.d.ts +575 -0
- package/dist/wire/encode-probe.d.ts +70 -0
- package/dist/wire/encode.d.ts +24 -0
- package/dist/wire/index.d.ts +2 -0
- package/dist/wire/sse.d.ts +10 -2
- package/dist/wire.js +917 -480
- package/dist/x-C5m1JFgi.js +1 -0
- package/frameworks/react/index.tsx +325 -108
- package/llms-full.txt +1354 -82
- package/llms.txt +6 -3
- package/package.json +39 -6
- package/src/agent-tooling/archetypes.ts +41 -9
- package/src/agent-tooling/catalog/README.md +676 -0
- package/src/agent-tooling/catalog/catalog-types.ts +231 -0
- package/src/agent-tooling/catalog/fabrications.ts +96 -0
- package/src/agent-tooling/catalog/invariants.ts +284 -0
- package/src/agent-tooling/catalog/labs-titles.ts +114 -0
- package/src/agent-tooling/catalog/scenarios.ts +87 -0
- package/src/agent-tooling/catalog/surfaces.ts +347 -0
- package/src/agent-tooling/construct/cli-entry.ts +8 -0
- package/src/agent-tooling/construct/cli.ts +131 -0
- package/src/agent-tooling/construct/codegen.ts +1353 -0
- package/src/agent-tooling/construct/construct.v1.schema.json +250 -0
- package/src/agent-tooling/construct/dev.ts +148 -0
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +7 -0
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +44 -0
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +23 -0
- package/src/agent-tooling/construct/schema.ts +371 -0
- package/src/agent-tooling/integrations/anthropic.ts +7 -1
- package/src/agent-tooling/integrations/cloudflare.ts +43 -2
- package/src/agent-tooling/integrations/langgraph.ts +7 -1
- package/src/agent-tooling/integrations/mastra.ts +7 -1
- package/src/agent-tooling/integrations/mock.ts +92 -17
- package/src/agent-tooling/integrations/ollama.ts +7 -1
- package/src/agent-tooling/integrations/openai.ts +7 -1
- package/src/agent-tooling/integrations/openrouter.ts +7 -1
- package/src/agent-tooling/integrations/pi.ts +56 -1
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +7 -1
- package/src/agent-tooling/mcp/css-raw.d.ts +12 -0
- package/src/agent-tooling/mcp/manifest.ts +100 -1
- package/src/agent-tooling/mcp/server.ts +63 -6
- package/src/agent-tooling/mcp/tools/construct.ts +130 -0
- package/src/agent-tooling/mcp/tools/debug.ts +126 -4
- package/src/agent-tooling/mcp/tools/reference.ts +542 -5
- package/src/agent-tooling/mcp/tools/scaffold.ts +1834 -307
- package/src/agent-tooling/mcp/tools/theme.ts +146 -30
- package/src/agent-tooling/mcp/validate-args.ts +141 -0
- package/src/agent-tooling/recipes/composed-thread.ts +714 -0
- package/src/agent-tooling/recipes/index.ts +22 -0
- package/src/agent-tooling/recipes/types.ts +32 -0
- package/src/agent-tooling/registry.ts +24 -7
- package/src/agent-tooling/route-emit.ts +26 -2
- package/src/components/attachment-types.ts +54 -1
- package/src/components/attachments.tsx +169 -22
- package/src/components/audio-visualizer/fit-scale.ts +112 -0
- package/src/components/audio-visualizer/index.tsx +80 -3
- package/src/components/audio-visualizer/variant-aurora.tsx +10 -4
- package/src/components/audio-visualizer/variant-bar.tsx +38 -6
- package/src/components/audio-visualizer/variant-custom.tsx +8 -2
- package/src/components/audio-visualizer/variant-grid.tsx +16 -11
- package/src/components/audio-visualizer/variant-radial.tsx +15 -10
- package/src/components/audio-visualizer/variant-wave.tsx +7 -2
- package/src/components/card-renderer.tsx +39 -8
- package/src/components/card.tsx +10 -2
- package/src/components/chat-container.tsx +4 -1
- package/src/components/chat-scope-picker.tsx +2 -2
- package/src/components/chat-thread.tsx +105 -13
- package/src/components/choice-card.tsx +102 -37
- package/src/components/coachmark.tsx +1 -1
- package/src/components/code-block.tsx +81 -5
- package/src/components/composer.tsx +89 -8
- package/src/components/confirm-card.tsx +20 -4
- package/src/components/conversation-item.tsx +138 -4
- package/src/components/conversation-list.tsx +230 -15
- package/src/components/embed.tsx +4 -0
- package/src/components/empty.tsx +14 -3
- package/src/components/file-tree.tsx +5 -1
- package/src/components/form-widgets.tsx +257 -195
- package/src/components/form.tsx +336 -21
- package/src/components/loader.tsx +12 -5
- package/src/components/message-skills.tsx +1 -1
- package/src/components/message.tsx +142 -12
- package/src/components/prompt-input.tsx +7 -1
- package/src/components/prompt-suggestion.tsx +4 -1
- package/src/components/reasoning.tsx +30 -3
- package/src/components/response-compare.tsx +2 -2
- package/src/components/response-stream.tsx +13 -7
- package/src/components/screen.tsx +5 -0
- package/src/components/scroll-button.tsx +63 -4
- package/src/components/source.tsx +6 -1
- package/src/components/tasks-card.tsx +58 -16
- package/src/components/thread.tsx +10 -1
- package/src/components/toast.tsx +11 -5
- package/src/components/tool-types.ts +9 -0
- package/src/components/voice-input.tsx +35 -3
- package/src/components/voice-output.tsx +46 -6
- package/src/components/workspace-shell.tsx +285 -0
- package/src/diagnostics/hook.ts +352 -0
- package/src/diagnostics/index.ts +82 -0
- package/src/diagnostics/report-request.ts +296 -0
- package/src/elements/attachments.tsx +9 -8
- package/src/elements/audio-visualizer.tsx +48 -4
- package/src/elements/chat-workspace.tsx +159 -287
- package/src/elements/chat.tsx +31 -10
- package/src/elements/checkbox-group.tsx +164 -0
- package/src/elements/checkbox.tsx +134 -0
- package/src/elements/code-block.tsx +19 -1
- package/src/elements/command.tsx +4 -1
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +12 -1
- package/src/elements/conversation-item.tsx +120 -0
- package/src/elements/conversation-list.tsx +60 -11
- package/src/elements/default-input.tsx +5 -5
- package/src/elements/define-entry.ts +12 -0
- package/src/elements/define.tsx +168 -8
- package/src/elements/diagnostic-events.ts +114 -0
- package/src/elements/dialog.tsx +47 -0
- package/src/elements/disclosure.ts +34 -12
- package/src/elements/dock.tsx +215 -0
- package/src/elements/dropdown.tsx +123 -0
- package/src/elements/element-data-types.ts +40 -0
- package/src/elements/element-diagnostics.ts +392 -0
- package/src/elements/element-manifest.json +36 -0
- package/src/elements/element-meta.json +1483 -560
- package/src/elements/element-nonscalar.json +185 -0
- package/src/elements/element-types.d.ts +589 -167
- package/src/elements/feedback-bar.tsx +5 -0
- package/src/elements/icon-names.json +29 -0
- package/src/elements/input.tsx +312 -23
- package/src/elements/menu.tsx +13 -0
- package/src/elements/message.tsx +2 -0
- package/src/elements/pane-grid.tsx +111 -0
- package/src/elements/prompt-dock.tsx +2 -1
- package/src/elements/prompt-input.tsx +16 -10
- package/src/elements/radio-group.tsx +129 -0
- package/src/elements/register-impl.ts +52 -0
- package/src/elements/register.ts +28 -0
- package/src/elements/resizable.tsx +52 -25
- package/src/elements/scroll-button.tsx +59 -6
- package/src/elements/select.tsx +165 -0
- package/src/elements/slider.tsx +171 -0
- package/src/elements/slots.ts +108 -13
- package/src/elements/styles.css +119 -9
- package/src/elements/thinking-bar.tsx +16 -7
- package/src/elements/thread.tsx +2 -0
- package/src/elements/toast.tsx +17 -1
- package/src/elements/tool.tsx +26 -5
- package/src/elements/voice-input.tsx +11 -2
- package/src/elements/voice-output.tsx +16 -3
- package/src/index.ts +4 -1
- package/src/primitives/card-data-types.ts +49 -0
- package/src/primitives/card-host.tsx +4 -2
- package/src/primitives/card-routing.ts +7 -56
- package/src/primitives/card-schemas/form.schema.json +21 -1
- package/src/primitives/card-validate.ts +10 -2
- package/src/primitives/chat-config.tsx +33 -6
- package/src/primitives/field-mask.ts +256 -0
- package/src/primitives/field-semantics.ts +115 -0
- package/src/primitives/input-mask.ts +853 -0
- package/src/primitives/toast-store.ts +66 -4
- package/src/primitives/url-scheme-policy.ts +70 -0
- package/src/primitives/use-resize-observer.ts +33 -0
- package/src/primitives/use-speech-recognition.ts +12 -1
- package/src/primitives/use-stick-to-bottom.ts +34 -2
- package/src/primitives/use-text-stream.ts +33 -2
- package/src/remote/provider-runtime.ts +6 -3
- package/src/schemas/index.ts +1 -0
- package/src/schemas/tool-defs.ts +307 -6
- package/src/solid.ts +15 -0
- package/src/state/index.ts +13 -1
- package/src/state/mock.ts +92 -6
- package/src/state/persistence.ts +180 -0
- package/src/state/stream.ts +71 -4
- package/src/state/threads.ts +142 -0
- package/src/types.ts +4 -2
- package/src/ui/agent-card.tsx +2 -2
- package/src/ui/avatar.tsx +1 -1
- package/src/ui/checkbox-group.tsx +153 -0
- package/src/ui/checkbox.tsx +63 -0
- package/src/ui/dialog.tsx +6 -0
- package/src/ui/dock.tsx +584 -0
- package/src/ui/dropdown.tsx +67 -23
- package/src/ui/hover-card.tsx +156 -6
- package/src/ui/icon.tsx +53 -0
- package/src/ui/input.tsx +275 -16
- package/src/ui/kbd.tsx +1 -1
- package/src/ui/nav.tsx +1 -1
- package/src/ui/pane-group.tsx +2 -2
- package/src/ui/radio.tsx +150 -0
- package/src/ui/resizable.tsx +11 -0
- package/src/ui/select.tsx +168 -0
- package/src/ui/slider.tsx +178 -0
- package/src/ui/switch.tsx +49 -18
- package/src/utils/cn.ts +11 -5
- package/src/wire/chunk.ts +47 -0
- package/src/wire/consume.ts +185 -26
- package/src/wire/diagnostics.ts +727 -0
- package/src/wire/encode-probe.ts +214 -0
- package/src/wire/encode.ts +267 -14
- package/src/wire/formats/anthropic.ts +8 -1
- package/src/wire/formats/openai.ts +5 -0
- package/src/wire/index.ts +22 -0
- package/src/wire/read.ts +250 -6
- package/src/wire/sse.ts +16 -3
- package/theme.css +84 -13
- package/dist/elements/chunks/action-icons-DW9muWrY.js +0 -1
- package/dist/elements/chunks/arrow-left-iJVnQmxA.js +0 -1
- package/dist/elements/chunks/artifact-BSuPYFHY.js +0 -1
- package/dist/elements/chunks/attachments-CL6TaqIb.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BuUqQmaO.js +0 -1
- package/dist/elements/chunks/badge-TIMiJFKc.js +0 -1
- package/dist/elements/chunks/bash-InADTalH.js +0 -1
- package/dist/elements/chunks/card-renderer-CSoTL_e1.js +0 -1
- package/dist/elements/chunks/card-routing-BK09BdmL.js +0 -1
- package/dist/elements/chunks/chat-thread-DxoKaStk.js +0 -1
- package/dist/elements/chunks/check-MdLzbxrm.js +0 -1
- package/dist/elements/chunks/chevron-down-MK7IzDqe.js +0 -1
- package/dist/elements/chunks/chevron-right-C5jXhmtV.js +0 -1
- package/dist/elements/chunks/choice-card-CGMc3kek.js +0 -1
- package/dist/elements/chunks/circle-BG7VkPep.js +0 -1
- package/dist/elements/chunks/circle-check-GqvO2UBs.js +0 -1
- package/dist/elements/chunks/circle-x-mhH7pOK2.js +0 -1
- package/dist/elements/chunks/code-block-ClhQO9RW.js +0 -1
- package/dist/elements/chunks/collapsible-DBcBkFPh.js +0 -1
- package/dist/elements/chunks/composer-CZZmtYOT.js +0 -69
- package/dist/elements/chunks/confirm-card-BWjf2-xo.js +0 -1
- package/dist/elements/chunks/context-hKjNqiyQ.js +0 -1
- package/dist/elements/chunks/conversation-list-CsGJjSKG.js +0 -1
- package/dist/elements/chunks/core-AYMC6_lb.js +0 -12
- package/dist/elements/chunks/css-M7EaDHN_.js +0 -1
- package/dist/elements/chunks/default-input-B1Mem5wu.js +0 -1
- package/dist/elements/chunks/define-B_tXMYRm.js +0 -1
- package/dist/elements/chunks/disclosure-DAoYOKew.js +0 -1
- package/dist/elements/chunks/download-DnCyWFJE.js +0 -1
- package/dist/elements/chunks/dropdown-CmNna5lT.js +0 -1
- package/dist/elements/chunks/embed-CjAD2jSi.js +0 -1
- package/dist/elements/chunks/engine-javascript-vq0WuIJl.js +0 -141
- package/dist/elements/chunks/file-text-D0J9F6M7.js +0 -1
- package/dist/elements/chunks/folder-NV1pi_ud.js +0 -1
- package/dist/elements/chunks/form-Cp8Y00Wn.js +0 -1
- package/dist/elements/chunks/github-dark-dimmed-DUshB20C.js +0 -1
- package/dist/elements/chunks/github-light-JYsPkUQd.js +0 -1
- package/dist/elements/chunks/hover-card-6KtXpLwT.js +0 -1
- package/dist/elements/chunks/html-CPZ3oZQ7.js +0 -1
- package/dist/elements/chunks/icon-97R8SR2p.js +0 -1
- package/dist/elements/chunks/info-C8r5Q6cc.js +0 -1
- package/dist/elements/chunks/input-DrseEjhp.js +0 -1
- package/dist/elements/chunks/javascript-C25yR2R2.js +0 -1
- package/dist/elements/chunks/json-DxJze_jm.js +0 -1
- package/dist/elements/chunks/kbd-OGJDUT-O.js +0 -1
- package/dist/elements/chunks/link-BdsfLB7b.js +0 -1
- package/dist/elements/chunks/loader-B5QzK_8_.js +0 -1
- package/dist/elements/chunks/message-CE4k-qaj.js +0 -1
- package/dist/elements/chunks/message-DtXKPqiR.js +0 -1
- package/dist/elements/chunks/message-square-C9ovmtOo.js +0 -1
- package/dist/elements/chunks/paperclip-Bg0ITU3b.js +0 -1
- package/dist/elements/chunks/progress-bar-D1_rzt6N.js +0 -1
- package/dist/elements/chunks/prompt-suggestion-D5Sm8xF1.js +0 -1
- package/dist/elements/chunks/reasoning-BrxQfpfI.js +0 -1
- package/dist/elements/chunks/rotate-cw-DzVDJOA1.js +0 -1
- package/dist/elements/chunks/scroll-area-93A1bbeG.js +0 -1
- package/dist/elements/chunks/scroll-button-CrTo7wm4.js +0 -1
- package/dist/elements/chunks/share-DgNbkJKY.js +0 -1
- package/dist/elements/chunks/slots-CIw9RlAe.js +0 -1
- package/dist/elements/chunks/source-w9V0NnBn.js +0 -1
- package/dist/elements/chunks/star-DHvACxtm.js +0 -1
- package/dist/elements/chunks/store-HIPGhNz9.js +0 -1
- package/dist/elements/chunks/svelte--5p79yCD.js +0 -1
- package/dist/elements/chunks/tasks-card-lPxoodlA.js +0 -1
- package/dist/elements/chunks/text-shimmer-BY_rI3s5.js +0 -1
- package/dist/elements/chunks/textarea-DPfuhswM.js +0 -1
- package/dist/elements/chunks/toast-store-VUZZBhzH.js +0 -1
- package/dist/elements/chunks/tsx-B8rCNbgL.js +0 -1
- package/dist/elements/chunks/typescript-RycA9KXf.js +0 -1
- package/dist/elements/chunks/use-card-resolution-DJg32jGH.js +0 -1
- package/dist/elements/chunks/variant-custom-D5ZlmziF.js +0 -1
- package/dist/elements/chunks/video-Bb86fVYI.js +0 -1
- package/dist/elements/chunks/vue-BmIZj4XD.js +0 -1
- package/dist/elements/chunks/x-BOhjBeOd.js +0 -1
- package/dist/llms/llms-full.txt +0 -2834
- package/dist/llms/llms.txt +0 -156
- package/dist/primitives/card-validate-generator.testlib.d.ts +0 -20
- package/dist/register-impl-DGmGzrEM.js +0 -145
- package/dist/ui/stat.d.ts +0 -16
- package/dist/variant-custom-MkTNTycd.js +0 -1
- package/src/primitives/card-validate-generator.testlib.ts +0 -38
- package/src/ui/stat.tsx +0 -41
- /package/dist/{elements/chunks/card-tags-D8lZ-C_U.js → card-tags-D8lZ-C_U.js} +0 -0
- /package/dist/{elements/chunks/link-preview-DNILK391.js → link-preview-DNILK391.js} +0 -0
package/src/schemas/tool-defs.ts
CHANGED
|
@@ -27,9 +27,14 @@
|
|
|
27
27
|
// `format: "uri"` (link/embed/artifact), `minimum` (tasks/embed/artifact),
|
|
28
28
|
// `maxItems` (confirm/artifact), `pattern` (embed), `if`/`then` (embed), `oneOf`
|
|
29
29
|
// (artifact), a free-form object (form) and untyped `payload`/`allowOther` members
|
|
30
|
-
// (confirm/choice). Non-strict is therefore
|
|
31
|
-
//
|
|
32
|
-
//
|
|
30
|
+
// (confirm/choice). Non-strict is therefore the default and the mode the
|
|
31
|
+
// five-configuration conformance spike actually proved cards in — but since F-20 it
|
|
32
|
+
// is no longer a raw pass-through either: a root combinator (`anyOf` on artifact,
|
|
33
|
+
// `allOf` on embed) gets HTTP 400 from OpenAI and Anthropic even non-strict, so the
|
|
34
|
+
// non-strict projection relaxes those root combinators LOUDLY (constraint restated in
|
|
35
|
+
// the description, console.warn names the relaxation, registry.validate still
|
|
36
|
+
// enforces at render time). The jsonschema projection stays byte-faithful to the
|
|
37
|
+
// authored schema.
|
|
33
38
|
//
|
|
34
39
|
// The alternative was to silently drop the offending keywords. That is rejected for
|
|
35
40
|
// the reason the plan gives: a dropped `maxItems: 4` means the model emits six
|
|
@@ -126,6 +131,52 @@ export interface CardToolOptions<P extends ToolProvider = ToolProvider> {
|
|
|
126
131
|
* When it throws it names the card, the path and the keyword.
|
|
127
132
|
*/
|
|
128
133
|
readonly strict?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Narrow the DERIVED tool schema per card type, after projection.
|
|
136
|
+
*
|
|
137
|
+
* A card's authored schema is deliberately permissive — `files` is optional on an
|
|
138
|
+
* artifact, its items need only a `path` — because the card CONTRACT must accept
|
|
139
|
+
* what a host may legitimately render. A model filling the tool in, though, is
|
|
140
|
+
* often better served by a tighter tool: requiring `code` on every file, or at
|
|
141
|
+
* least one file at all, moves a class of failures from render time (a card the
|
|
142
|
+
* registry rejects) to generation time (the model literally cannot emit one).
|
|
143
|
+
*
|
|
144
|
+
* This narrows the WIRE projection only — the authored schema and
|
|
145
|
+
* `registry.validate()` are untouched, so a hand-built envelope still validates.
|
|
146
|
+
* Applied for every provider, `jsonschema` included, and merged loudly: an
|
|
147
|
+
* unknown path or a required name the node has no property for is a TypeError
|
|
148
|
+
* naming the card, the path and the field, because a tool that can never be
|
|
149
|
+
* satisfied must not ship quietly.
|
|
150
|
+
*
|
|
151
|
+
* IT CANNOT REACH A FORM CARD'S FIELDS, and that is a known limitation rather
|
|
152
|
+
* than an oversight. The form
|
|
153
|
+
* card's payload IS a JSON Schema, so `form.schema.json` describes `properties`
|
|
154
|
+
* as a map of field definitions and there is no node at `properties.ticketId`
|
|
155
|
+
* for a rule to land on — `require: { form: [{ path: 'properties.ticketId' }] }`
|
|
156
|
+
* raises the TypeError above, correctly. So an app cannot pin
|
|
157
|
+
* `x-kai-format: 'custom'` onto one field of a form the model authors. The
|
|
158
|
+
* enum on that hint is what makes a small model pick a valid token; an app that
|
|
159
|
+
* needs a guarantee checks the envelope when it arrives.
|
|
160
|
+
*/
|
|
161
|
+
readonly require?: Readonly<Record<string, readonly CardRequireRule[]>>;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* One narrowing instruction for one node of one card's projected schema.
|
|
166
|
+
*
|
|
167
|
+
* `path` is a dot-path from the envelope-data root through `properties` keys
|
|
168
|
+
* (`''` names the root node itself). On an ARRAY node, `required` narrows
|
|
169
|
+
* `items.required` and `minItems` lands on the array; on an object node,
|
|
170
|
+
* `required` lands on the node's own `required`. Existing requirements merge,
|
|
171
|
+
* never replace.
|
|
172
|
+
*/
|
|
173
|
+
export interface CardRequireRule {
|
|
174
|
+
/** Dot-path from the envelope-data root to a schema node, e.g. 'files'. */
|
|
175
|
+
readonly path: string;
|
|
176
|
+
/** Property names to require. On an ARRAY node this narrows `items.required`; on an object node, the node's own `required`. */
|
|
177
|
+
readonly required?: readonly string[];
|
|
178
|
+
/** Sets `minItems` (array nodes only). */
|
|
179
|
+
readonly minItems?: number;
|
|
129
180
|
}
|
|
130
181
|
|
|
131
182
|
/**
|
|
@@ -225,7 +276,7 @@ function formatUnsupported(subset: ProviderSubset, cards: readonly UnsupportedCa
|
|
|
225
276
|
lines.push('');
|
|
226
277
|
lines.push(` subset source: ${subset.source} (read ${subset.checkedOn})`);
|
|
227
278
|
lines.push(
|
|
228
|
-
' Fix: drop `strict: true`. Non-strict
|
|
279
|
+
' Fix: drop `strict: true`. Non-strict mode projects a provider-valid schema (root combinators are relaxed with the constraint restated in the description and still enforced by card validation). Rewriting a built-in card schema to fit a strict subset would change what a valid card IS, which is a card-contract change, not a projection setting.',
|
|
229
280
|
);
|
|
230
281
|
return lines.join('\n');
|
|
231
282
|
}
|
|
@@ -237,6 +288,227 @@ function formatUnsupported(subset: ProviderSubset, cards: readonly UnsupportedCa
|
|
|
237
288
|
const isRecord = (v: unknown): v is Record<string, unknown> =>
|
|
238
289
|
typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
239
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Root combinators the two largest providers refuse on a tool schema's root node
|
|
293
|
+
* (measured: OpenAI and Anthropic 400 before the model runs — findings F-20;
|
|
294
|
+
* DeepSeek's OpenAI-compatible route requires the same workaround). The AUTHORED
|
|
295
|
+
* schemas keep them — card validation keeps every constraint. Only the WIRE
|
|
296
|
+
* projection relaxes, loudly: the constraint is restated in the description the
|
|
297
|
+
* model reads, a console.warn names the relaxation, and a violating envelope
|
|
298
|
+
* still fails registry.validate() at render time with a hard diagnostic.
|
|
299
|
+
*/
|
|
300
|
+
const ROOT_RELAXATIONS: Readonly<Record<string, string>> = {
|
|
301
|
+
artifact:
|
|
302
|
+
'Provide `src` (a preview URL) or `files` — at least one. An envelope with neither is rejected.',
|
|
303
|
+
embed:
|
|
304
|
+
"For provider 'generic', include `url`. For 'youtube'/'vimeo', include `id` or `url`.",
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
/** Strip a banned combinator key from the projected ROOT node only (nested
|
|
308
|
+
* combinators are accepted by every provider measured and stay). Returns the
|
|
309
|
+
* relaxation note to restate in the TOOL description the model reads. Two
|
|
310
|
+
* distinct no-note return paths: `undefined` when NOTHING was banned (the wire
|
|
311
|
+
* projection is faithful, nothing was widened), and GENERIC_NOTE when something
|
|
312
|
+
* WAS banned but no curated copy exists (a custom card) — that path still
|
|
313
|
+
* restates the relaxation, because deleting a combinator without telling the
|
|
314
|
+
* model would be a silent widening. */
|
|
315
|
+
const GENERIC_RELAXATION_NOTE =
|
|
316
|
+
'The root constraint of this schema was relaxed for this provider; consult the card registry for what a valid payload is.';
|
|
317
|
+
|
|
318
|
+
const BANNED_ROOT_KEYS = ['anyOf', 'allOf', 'oneOf', 'not', 'enum', 'const'] as const;
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* The object shape a literal `enum` / `const` VALUE implies.
|
|
322
|
+
*
|
|
323
|
+
* `const: { op: 'ping' }` is a whole-instance constraint, which a provider refuses
|
|
324
|
+
* at the root exactly like a combinator. The instance it admits is an object, so
|
|
325
|
+
* the shape survives the relaxation as `properties: { op: { const: 'ping' } }` with
|
|
326
|
+
* `op` required — nothing widened that the branch did not already allow.
|
|
327
|
+
*/
|
|
328
|
+
function branchFromLiteral(value: unknown): Record<string, unknown> | null {
|
|
329
|
+
if (!isRecord(value)) return null;
|
|
330
|
+
const properties: Record<string, unknown> = {};
|
|
331
|
+
for (const [key, member] of Object.entries(value)) properties[key] = { const: member };
|
|
332
|
+
return { type: 'object', properties, required: Object.keys(value) };
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** The branch schemas one banned root keyword contributes, or `[]` for one that has none. */
|
|
336
|
+
function branchesOfRootKeyword(keyword: string, value: unknown): Record<string, unknown>[] {
|
|
337
|
+
if (keyword === 'anyOf' || keyword === 'oneOf' || keyword === 'allOf') {
|
|
338
|
+
return Array.isArray(value) ? value.filter(isRecord) : [];
|
|
339
|
+
}
|
|
340
|
+
if (keyword === 'const') return [branchFromLiteral(value)].filter((b): b is Record<string, unknown> => b !== null);
|
|
341
|
+
if (keyword === 'enum') {
|
|
342
|
+
return Array.isArray(value)
|
|
343
|
+
? value.map(branchFromLiteral).filter((b): b is Record<string, unknown> => b !== null)
|
|
344
|
+
: [];
|
|
345
|
+
}
|
|
346
|
+
// `not` is a NEGATIVE constraint: nothing it says is a property the instance may
|
|
347
|
+
// carry, so there is nothing sound to merge back. It is dropped and restated in
|
|
348
|
+
// the description like every other relaxation.
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Fold a root combinator's branches back into the object root that replaces it.
|
|
354
|
+
*
|
|
355
|
+
* The two built-ins showed the shape of the rule and this generalises it rather
|
|
356
|
+
* than special-casing them. `artifact`'s root `anyOf` is `[{required:['src']},
|
|
357
|
+
* {required:['files']}]`: a DISJUNCTION guarantees only what EVERY branch
|
|
358
|
+
* guarantees, so the intersection is empty and `required` stays absent — which is
|
|
359
|
+
* exactly what the artifact projection already did. `embed`'s root `allOf` is two
|
|
360
|
+
* `if`/`then` pairs: a CONJUNCTION guarantees every branch's own top-level
|
|
361
|
+
* `required`, and an `if`/`then` branch declares none, so again nothing is added.
|
|
362
|
+
* A consumer card whose branches carry real `properties` is the case neither
|
|
363
|
+
* built-in reaches, and the one this exists for.
|
|
364
|
+
*
|
|
365
|
+
* Properties are UNIONed (each branch's shape must remain expressible — dropping
|
|
366
|
+
* one is the silent narrowing the whole F-20 fix exists to avoid); a name already
|
|
367
|
+
* on the root keeps the root's definition. `required` is the intersection for
|
|
368
|
+
* `anyOf`/`oneOf`/`enum`/`const` and the union for `allOf`, unioned in turn with
|
|
369
|
+
* whatever the root already required, and filtered to names the merged
|
|
370
|
+
* `properties` actually carries so the tool can never be unsatisfiable.
|
|
371
|
+
*/
|
|
372
|
+
function mergeBranchesIntoRoot(parameters: Record<string, unknown>, banned: readonly string[]): void {
|
|
373
|
+
const properties: Record<string, unknown> = isRecord(parameters.properties)
|
|
374
|
+
? { ...parameters.properties }
|
|
375
|
+
: {};
|
|
376
|
+
const guaranteed = new Set<string>(
|
|
377
|
+
Array.isArray(parameters.required) ? parameters.required.map(String) : [],
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
for (const keyword of banned) {
|
|
381
|
+
const branches = branchesOfRootKeyword(keyword, parameters[keyword]);
|
|
382
|
+
if (branches.length === 0) continue;
|
|
383
|
+
|
|
384
|
+
for (const branch of branches) {
|
|
385
|
+
if (!isRecord(branch.properties)) continue;
|
|
386
|
+
for (const [name, sub] of Object.entries(branch.properties)) {
|
|
387
|
+
if (!(name in properties)) properties[name] = sub;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const perBranch = branches.map(
|
|
392
|
+
(branch) => new Set(Array.isArray(branch.required) ? branch.required.map(String) : []),
|
|
393
|
+
);
|
|
394
|
+
if (keyword === 'allOf') {
|
|
395
|
+
for (const set of perBranch) for (const name of set) guaranteed.add(name);
|
|
396
|
+
} else {
|
|
397
|
+
// Disjunction: keep only what every branch requires.
|
|
398
|
+
const [first, ...rest] = perBranch;
|
|
399
|
+
for (const name of first) {
|
|
400
|
+
if (rest.every((set) => set.has(name))) guaranteed.add(name);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (Object.keys(properties).length > 0) parameters.properties = properties;
|
|
406
|
+
const required = [...guaranteed].filter((name) => name in properties);
|
|
407
|
+
if (required.length > 0) parameters.required = required;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Make the projected ROOT the object shape every provider demands.
|
|
412
|
+
*
|
|
413
|
+
* Deleting a root combinator is only half of F-20. A schema whose root was NOTHING
|
|
414
|
+
* BUT the combinator projects to `{"title":…,"description":…}` once it is gone —
|
|
415
|
+
* accepted by no provider (measured: OpenAI 400, "schema must be a JSON Schema of
|
|
416
|
+
* type \"object\"") and unfillable by any model. Every built-in declares
|
|
417
|
+
* `type: "object"` at its root, so nothing in the suite reached this until a
|
|
418
|
+
* consumer card did.
|
|
419
|
+
*
|
|
420
|
+
* A root that declares a NON-object type cannot be a tool schema at all, and
|
|
421
|
+
* asserting `type: "object"` over it would be a lie about the card. That refuses,
|
|
422
|
+
* naming the card.
|
|
423
|
+
*/
|
|
424
|
+
function ensureObjectRoot(parameters: Record<string, unknown>, cardType: string): void {
|
|
425
|
+
const declared = parameters.type;
|
|
426
|
+
if (declared !== undefined && declared !== 'object') {
|
|
427
|
+
throw new TypeError(
|
|
428
|
+
`cardTools: the '${cardType}' card schema declares root type '${String(declared)}', but a provider tool ` +
|
|
429
|
+
`schema root must be an object (OpenAI and Anthropic reject anything else with HTTP 400). ` +
|
|
430
|
+
`Wrap the payload in an object, or project this card with provider 'jsonschema'.`,
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
parameters.type = 'object';
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function relaxRootCombinators(parameters: Record<string, unknown>, cardType: string): string | undefined {
|
|
437
|
+
const note = ROOT_RELAXATIONS[cardType];
|
|
438
|
+
const banned = BANNED_ROOT_KEYS.filter((k) => k in parameters);
|
|
439
|
+
// The object-root guarantee holds for EVERY provider projection, banned keys or
|
|
440
|
+
// not: it is what the provider requires, not what the relaxation broke.
|
|
441
|
+
ensureObjectRoot(parameters, cardType);
|
|
442
|
+
if (banned.length === 0) return undefined;
|
|
443
|
+
mergeBranchesIntoRoot(parameters, banned);
|
|
444
|
+
for (const k of banned) delete parameters[k];
|
|
445
|
+
// eslint-disable-next-line no-console
|
|
446
|
+
console.warn(
|
|
447
|
+
`[kai-card-tools] relaxed root ${banned.join('/')} on the projected '${toolNameForCardType(cardType)}' tool schema ` +
|
|
448
|
+
`for this provider (it would be refused with HTTP 400); the constraint now lives in the ` +
|
|
449
|
+
`description and is still enforced by card validation.`,
|
|
450
|
+
);
|
|
451
|
+
return note ?? GENERIC_RELAXATION_NOTE;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Apply one card's `require` rules to its PROJECTED parameters.
|
|
456
|
+
*
|
|
457
|
+
* Runs after `project()` and `relaxRootCombinators()`, on the copy the projection
|
|
458
|
+
* built — never on the authored schema, which `registry.validate()` keeps reading.
|
|
459
|
+
* Merges into whatever `required` already exists rather than replacing it, so a
|
|
460
|
+
* rule can only ever NARROW what the model may emit, never widen it.
|
|
461
|
+
*/
|
|
462
|
+
function applyRequire(
|
|
463
|
+
parameters: Record<string, unknown>,
|
|
464
|
+
cardType: string,
|
|
465
|
+
rules: readonly CardRequireRule[],
|
|
466
|
+
): void {
|
|
467
|
+
for (const rule of rules) {
|
|
468
|
+
// Resolve the dot-path through `properties` keys. `''` names the root node;
|
|
469
|
+
// every other segment must name a property of the node reached so far.
|
|
470
|
+
let node: Record<string, unknown> = parameters;
|
|
471
|
+
if (rule.path !== '') {
|
|
472
|
+
for (const segment of rule.path.split('.')) {
|
|
473
|
+
const props = isRecord(node.properties) ? node.properties : undefined;
|
|
474
|
+
const next = props?.[segment];
|
|
475
|
+
if (!isRecord(next)) {
|
|
476
|
+
throw new TypeError(
|
|
477
|
+
`cardTools: require on '${cardType}': path '${rule.path}' does not resolve in the schema`,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
node = next;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const isArrayNode = node.type === 'array' || (node.type === undefined && 'items' in node);
|
|
485
|
+
if (isArrayNode && rule.minItems !== undefined) node.minItems = rule.minItems;
|
|
486
|
+
if (!isArrayNode && rule.minItems !== undefined) {
|
|
487
|
+
throw new TypeError(
|
|
488
|
+
`cardTools: minItems at require path '${rule.path}' applies to array nodes only, ` +
|
|
489
|
+
`but '${rule.path}' in the '${cardType}' schema is not one`,
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (rule.required !== undefined) {
|
|
494
|
+
// On an array node the requirement lives on the ITEMS (each element must carry
|
|
495
|
+
// the field), not on the array itself.
|
|
496
|
+
const target = isArrayNode && isRecord(node.items) ? node.items : node;
|
|
497
|
+
const props = isRecord(target.properties) ? target.properties : undefined;
|
|
498
|
+
for (const field of rule.required) {
|
|
499
|
+
if (!props || !(field in props)) {
|
|
500
|
+
throw new TypeError(
|
|
501
|
+
`cardTools: require on '${cardType}' at path '${rule.path}': '${field}' is not a property of that node — ` +
|
|
502
|
+
`a required name with no property would make the tool unsatisfiable`,
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
const existing = Array.isArray(target.required) ? target.required.map(String) : [];
|
|
507
|
+
target.required = [...new Set([...existing, ...rule.required])];
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
240
512
|
/**
|
|
241
513
|
* Keywords stripped from every projection, strict or not.
|
|
242
514
|
*
|
|
@@ -430,11 +702,40 @@ export function cardTools(a: CardToolInput | CardToolOptions, b?: CardToolOption
|
|
|
430
702
|
const defs: ToolDef[] = [];
|
|
431
703
|
const failures: UnsupportedCardTool[] = [];
|
|
432
704
|
|
|
705
|
+
// A `require` key naming a card the call does not carry is a typo, and a typo here
|
|
706
|
+
// would otherwise narrow NOTHING while looking like it narrowed something — the
|
|
707
|
+
// same decide-loudly class as an unknown dot-path below.
|
|
708
|
+
if (opts.require !== undefined) {
|
|
709
|
+
for (const key of Object.keys(opts.require)) {
|
|
710
|
+
if (!(key in schemas)) {
|
|
711
|
+
throw new TypeError(
|
|
712
|
+
`cardTools: require names card type '${key}', which this call does not carry ` +
|
|
713
|
+
`(carries: ${Object.keys(schemas).join(', ') || 'none'})`,
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
433
719
|
for (const [cardType, schema] of Object.entries(schemas)) {
|
|
434
720
|
const name = toolNameForCardType(cardType);
|
|
435
721
|
const description = describe(cardType, schema, descriptions);
|
|
436
722
|
const parameters = project(schema, projectOptions) as ToolParameters;
|
|
437
723
|
|
|
724
|
+
// F-20: non-strict only. Strict mode already refuses these cards with the full
|
|
725
|
+
// subset check, so the relaxation must never mask it. The note is restated in the
|
|
726
|
+
// TOOL description — the envelope field the model reads when choosing the tool.
|
|
727
|
+
const relaxedNote =
|
|
728
|
+
subset === null && opts.provider !== 'jsonschema'
|
|
729
|
+
? relaxRootCombinators(parameters as Record<string, unknown>, cardType)
|
|
730
|
+
: undefined;
|
|
731
|
+
const wireDescription = relaxedNote ? `${description} ${relaxedNote}` : description;
|
|
732
|
+
|
|
733
|
+
// F-23: every provider, jsonschema included — a consumer handing the bare schema
|
|
734
|
+
// to the Vercel AI SDK narrows their tool the same way. Runs BEFORE the strict
|
|
735
|
+
// subset check so that check judges the schema that actually ships.
|
|
736
|
+
const requireRules = opts.require?.[cardType];
|
|
737
|
+
if (requireRules !== undefined) applyRequire(parameters as Record<string, unknown>, cardType, requireRules);
|
|
738
|
+
|
|
438
739
|
if (subset) {
|
|
439
740
|
const violations = checkProviderSubset(parameters, subset);
|
|
440
741
|
if (violations.length > 0) {
|
|
@@ -444,9 +745,9 @@ export function cardTools(a: CardToolInput | CardToolOptions, b?: CardToolOption
|
|
|
444
745
|
}
|
|
445
746
|
|
|
446
747
|
if (opts.provider === 'openai') {
|
|
447
|
-
defs.push({ type: 'function', function: { name, description, parameters, ...(strict ? { strict: true as const } : {}) } });
|
|
748
|
+
defs.push({ type: 'function', function: { name, description: wireDescription, parameters, ...(strict ? { strict: true as const } : {}) } });
|
|
448
749
|
} else if (opts.provider === 'anthropic') {
|
|
449
|
-
defs.push({ name, description, input_schema: parameters, ...(strict ? { strict: true as const } : {}) });
|
|
750
|
+
defs.push({ name, description: wireDescription, input_schema: parameters, ...(strict ? { strict: true as const } : {}) });
|
|
450
751
|
} else {
|
|
451
752
|
defs.push({ name, description, schema: parameters });
|
|
452
753
|
}
|
package/src/solid.ts
CHANGED
|
@@ -53,8 +53,18 @@ export { Input } from './ui/input';
|
|
|
53
53
|
export type { InputProps } from './ui/input';
|
|
54
54
|
export { Kbd } from './ui/kbd';
|
|
55
55
|
export type { KbdProps, KbdPlatform } from './ui/kbd';
|
|
56
|
+
export { Checkbox } from './ui/checkbox';
|
|
57
|
+
export type { CheckboxProps } from './ui/checkbox';
|
|
58
|
+
export { Radio, RadioGroup } from './ui/radio';
|
|
59
|
+
export type { RadioProps, RadioGroupProps, RadioOption } from './ui/radio';
|
|
60
|
+
export { CheckboxGroup } from './ui/checkbox-group';
|
|
61
|
+
export type { CheckboxGroupProps, CheckboxOption } from './ui/checkbox-group';
|
|
56
62
|
export { Switch } from './ui/switch';
|
|
57
63
|
export type { SwitchProps } from './ui/switch';
|
|
64
|
+
export { Slider } from './ui/slider';
|
|
65
|
+
export type { SliderProps } from './ui/slider';
|
|
66
|
+
export { Select } from './ui/select';
|
|
67
|
+
export type { SelectProps, SelectOption } from './ui/select';
|
|
58
68
|
export { Tabs } from './ui/tabs';
|
|
59
69
|
export type { TabsProps, TabsVariant, KaiTabItem } from './ui/tabs';
|
|
60
70
|
export { Segmented } from './ui/segmented';
|
|
@@ -69,6 +79,8 @@ export { EditableLabel } from './ui/editable-label';
|
|
|
69
79
|
export type { EditableLabelProps } from './ui/editable-label';
|
|
70
80
|
export { Dialog } from './ui/dialog';
|
|
71
81
|
export type { DialogProps, DialogController } from './ui/dialog';
|
|
82
|
+
export { Dock, DockLauncherGlyph, DockCloseGlyph } from './ui/dock';
|
|
83
|
+
export type { DockProps, DockController, DockPosition, DockFocusOnOpen } from './ui/dock';
|
|
72
84
|
export { Popover } from './ui/popover';
|
|
73
85
|
export type { PopoverProps, PopoverController } from './ui/popover';
|
|
74
86
|
export { Nav } from './ui/nav';
|
|
@@ -148,3 +160,6 @@ export type {
|
|
|
148
160
|
AudioVisualizerProps, VisualizerVariant, ShaderSpec, ShaderVariantProps,
|
|
149
161
|
} from './components/audio-visualizer';
|
|
150
162
|
export type { VisualizerSize } from './components/audio-visualizer/sizes';
|
|
163
|
+
export { WorkspaceShell, type WorkspaceShellProps, type WorkspaceShellController, type WorkspaceAsideSide, type WorkspaceAsideToggleDetail, type WorkspaceAsideResizeDetail } from './components/workspace-shell';
|
|
164
|
+
export { createConversationItemsController, readConversationItemId } from './components/conversation-list';
|
|
165
|
+
export type { ConversationItemsController, ConversationItemsControllerOptions } from './components/conversation-list';
|
package/src/state/index.ts
CHANGED
|
@@ -7,11 +7,23 @@ export type { SetMessages, AssistantStream } from './stream';
|
|
|
7
7
|
export { appendTextPart, appendReasoningPart, upsertToolPart, upsertCardPart, fingerprint } from './parts';
|
|
8
8
|
export type { ReasoningOpts } from './parts';
|
|
9
9
|
|
|
10
|
+
// Multi-thread mechanics (the workspace recast, spec §3b): the id-bound
|
|
11
|
+
// SetMessages fold + the in-flight-turn bookkeeping. The consumer's record
|
|
12
|
+
// shape and every persistence/retention decision stay outside — see ./threads.
|
|
13
|
+
export { updateThreadMessages, bindThreadMessages, createThreadSessions } from './threads';
|
|
14
|
+
export type { ThreadLike, SetThreads, BindThreadOptions, ThreadSessions } from './threads';
|
|
15
|
+
|
|
16
|
+
// The persistence SEAM, not persistence: the stored-thread validator (F-18,
|
|
17
|
+
// variant list derived from the MessagePart union) and the debounce/flush
|
|
18
|
+
// shape. No storage backend, no default delay — policy is the consumer's.
|
|
19
|
+
export { parseStoredThread, createSaveScheduler } from './persistence';
|
|
20
|
+
export type { ParsedThread, DroppedStored, SaveScheduler, SaveSchedulerOptions } from './persistence';
|
|
21
|
+
|
|
10
22
|
// The zero-config mock. Produces SSE frames rather than folding parts directly,
|
|
11
23
|
// so the no-backend preview runs through the SAME parser a real provider does —
|
|
12
24
|
// and is deliberately impossible to mistake for one. See ./mock.
|
|
13
25
|
export { createMockResponder, DEFAULT_MOCK_REPLIES, MOCK_BANNER, MOCK_MARKER, MOCK_MARKER_KEY, MOCK_MODEL_ID } from './mock';
|
|
14
|
-
export type { MockResponder, MockResponderOptions } from './mock';
|
|
26
|
+
export type { MockReply, MockResponder, MockResponderOptions, MockToolCall, MockTurn } from './mock';
|
|
15
27
|
|
|
16
28
|
// The content-model types every signature above mentions. Without these a
|
|
17
29
|
// consumer importing only from '@kitn.ai/ui/state' cannot annotate the very
|
package/src/state/mock.ts
CHANGED
|
@@ -96,9 +96,42 @@ export const DEFAULT_MOCK_REPLIES: readonly string[] = [
|
|
|
96
96
|
'Mock again. Every frame I send is tagged `_kai_mock` and my usage reports zero tokens, so nothing here can be mistaken for a real turn.',
|
|
97
97
|
];
|
|
98
98
|
|
|
99
|
+
/** One scripted tool call for a mock turn. Framed exactly the way the OpenAI
|
|
100
|
+
* chat-completions wire frames a real one — an announce fragment carrying
|
|
101
|
+
* `id`/`function.name`, then the argument JSON streamed in fragments — so the
|
|
102
|
+
* kit's own reader (`readOpenAIStream`) reassembles it through the same path a
|
|
103
|
+
* real provider's call takes. */
|
|
104
|
+
export interface MockToolCall {
|
|
105
|
+
/** The tool name, e.g. `'get_weather'` or a card tool like `'kai_confirm'`. */
|
|
106
|
+
name: string;
|
|
107
|
+
/** The call's arguments. Serialized with `JSON.stringify` and streamed as
|
|
108
|
+
* fragments, like a real provider. Defaults to `{}`. */
|
|
109
|
+
arguments?: unknown;
|
|
110
|
+
/** Explicit tool-call id. Defaults to `call_kai-mock-<turn>-<n>`, which keeps
|
|
111
|
+
* the mock's naming tell (see tell 3): no provider issues ids in that shape. */
|
|
112
|
+
id?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** A scripted mock turn: optional text, then optional tool calls. A turn with
|
|
116
|
+
* tool calls finishes `finish_reason: 'tool_calls'`, exactly as a real
|
|
117
|
+
* tool-calling turn does; a turn without them finishes `'stop'`. */
|
|
118
|
+
export interface MockTurn {
|
|
119
|
+
/** Text streamed (token by token) before the tool calls. */
|
|
120
|
+
text?: string;
|
|
121
|
+
/** Tool calls announced this turn, in order. */
|
|
122
|
+
toolCalls?: readonly MockToolCall[];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** A canned reply: plain text, or a scripted turn. A string is exactly
|
|
126
|
+
* `{ text }` — the pre-tool-call API unchanged. */
|
|
127
|
+
export type MockReply = string | MockTurn;
|
|
128
|
+
|
|
99
129
|
export interface MockResponderOptions {
|
|
100
|
-
/** Canned replies, cycled one per turn.
|
|
101
|
-
|
|
130
|
+
/** Canned replies, cycled one per turn. Plain strings stream as text; a
|
|
131
|
+
* `MockTurn` can also script tool calls (`{ text, toolCalls }`), which is
|
|
132
|
+
* what lets the zero-config mock exercise the kit's tool/card path without
|
|
133
|
+
* hand-rolled SSE framing. Defaults to `DEFAULT_MOCK_REPLIES`. */
|
|
134
|
+
replies?: readonly MockReply[];
|
|
102
135
|
/** Delay between chunks, in ms. Defaults to 24 — fast enough to feel alive,
|
|
103
136
|
* slow enough that the streaming is visible. `0` streams as fast as the
|
|
104
137
|
* event loop allows, which is what tests want. */
|
|
@@ -144,6 +177,27 @@ function frame(id: string, body: Record<string, unknown>): string {
|
|
|
144
177
|
const delay = (ms: number): Promise<void> =>
|
|
145
178
|
ms > 0 ? new Promise((r) => setTimeout(r, ms)) : Promise.resolve();
|
|
146
179
|
|
|
180
|
+
/** Normalize a canned reply: a plain string is exactly `{ text }`. */
|
|
181
|
+
const asTurn = (reply: MockReply): MockTurn => (typeof reply === 'string' ? { text: reply } : reply);
|
|
182
|
+
|
|
183
|
+
/** How many characters of argument JSON ride in each tool-call fragment. Small
|
|
184
|
+
* enough that any realistic argument object spans several frames, so the
|
|
185
|
+
* reader's fragment-reassembly path — the one a real provider exercises — is
|
|
186
|
+
* exercised here too, rather than a single-frame shortcut it would never see
|
|
187
|
+
* in production. */
|
|
188
|
+
const TOOL_ARG_FRAGMENT_CHARS = 16;
|
|
189
|
+
|
|
190
|
+
/** Split argument JSON into the fragments a provider streams. Never empty: an
|
|
191
|
+
* empty-object call still sends its `'{}'` so the reader has arguments to
|
|
192
|
+
* parse. */
|
|
193
|
+
function argumentFragments(json: string): string[] {
|
|
194
|
+
const out: string[] = [];
|
|
195
|
+
for (let i = 0; i < json.length; i += TOOL_ARG_FRAGMENT_CHARS) {
|
|
196
|
+
out.push(json.slice(i, i + TOOL_ARG_FRAGMENT_CHARS));
|
|
197
|
+
}
|
|
198
|
+
return out.length > 0 ? out : [''];
|
|
199
|
+
}
|
|
200
|
+
|
|
147
201
|
/**
|
|
148
202
|
* Build a mock responder.
|
|
149
203
|
*
|
|
@@ -170,8 +224,9 @@ export function createMockResponder(options: MockResponderOptions = {}): MockRes
|
|
|
170
224
|
let announced = false;
|
|
171
225
|
|
|
172
226
|
return function respond(_prompt?: string): AsyncIterable<string> {
|
|
173
|
-
const
|
|
227
|
+
const scripted = asTurn(pool[turn % pool.length]);
|
|
174
228
|
const id = `kai-mock-${turn + 1}`;
|
|
229
|
+
const turnNumber = turn + 1;
|
|
175
230
|
turn += 1;
|
|
176
231
|
|
|
177
232
|
return {
|
|
@@ -193,15 +248,46 @@ export function createMockResponder(options: MockResponderOptions = {}): MockRes
|
|
|
193
248
|
// exercises the reader's empty-delta path.
|
|
194
249
|
yield frame(id, { choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] });
|
|
195
250
|
|
|
196
|
-
for (const token of tokenize(
|
|
251
|
+
for (const token of tokenize(scripted.text ?? '', chunkSize)) {
|
|
197
252
|
await delay(delayMs);
|
|
198
253
|
yield frame(id, { choices: [{ index: 0, delta: { content: token }, finish_reason: null }] });
|
|
199
254
|
}
|
|
200
255
|
|
|
256
|
+
// Scripted tool calls, framed the way the OpenAI wire frames real ones:
|
|
257
|
+
// one announce fragment per call (`index`/`id`/`function.name` + empty
|
|
258
|
+
// arguments), then the argument JSON in fragments. The kit's reader
|
|
259
|
+
// reassembles them through the exact path a real provider's call takes.
|
|
260
|
+
const toolCalls = scripted.toolCalls ?? [];
|
|
261
|
+
for (let index = 0; index < toolCalls.length; index += 1) {
|
|
262
|
+
const call = toolCalls[index];
|
|
263
|
+
// Tell 3's shape, extended to call ids: no provider issues these.
|
|
264
|
+
const callId = call.id ?? `call_${MOCK_MODEL_ID}-${turnNumber}-${index + 1}`;
|
|
265
|
+
await delay(delayMs);
|
|
266
|
+
yield frame(id, {
|
|
267
|
+
choices: [{
|
|
268
|
+
index: 0,
|
|
269
|
+
delta: { tool_calls: [{ index, id: callId, function: { name: call.name, arguments: '' } }] },
|
|
270
|
+
finish_reason: null,
|
|
271
|
+
}],
|
|
272
|
+
});
|
|
273
|
+
for (const fragment of argumentFragments(JSON.stringify(call.arguments ?? {}))) {
|
|
274
|
+
await delay(delayMs);
|
|
275
|
+
yield frame(id, {
|
|
276
|
+
choices: [{
|
|
277
|
+
index: 0,
|
|
278
|
+
delta: { tool_calls: [{ index, function: { arguments: fragment } }] },
|
|
279
|
+
finish_reason: null,
|
|
280
|
+
}],
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
201
285
|
// Tell 4: zero usage. A real turn that produced this much text cannot
|
|
202
|
-
// report zero completion tokens.
|
|
286
|
+
// report zero completion tokens. A turn that announced tool calls ends
|
|
287
|
+
// `tool_calls`, exactly as a real one does, so the consumer's tool loop
|
|
288
|
+
// branches the same way it would against a provider.
|
|
203
289
|
yield frame(id, {
|
|
204
|
-
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
|
|
290
|
+
choices: [{ index: 0, delta: {}, finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop' }],
|
|
205
291
|
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
206
292
|
});
|
|
207
293
|
yield 'data: [DONE]\n\n';
|