@kitn.ai/ui 0.28.0 → 0.30.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.
Files changed (615) hide show
  1. package/README.md +11 -7
  2. package/dist/{Icon-DObhsRtm.js → Icon-BzBET3E-.js} +1 -1
  3. package/dist/{action-icons-CcgNN2oT.js → action-icons-DaW2pU6m.js} +1 -1
  4. package/dist/agent-tooling/construct/public.d.ts +15 -0
  5. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  6. package/dist/arrow-down-D783iMJj.js +1 -0
  7. package/dist/arrow-left-0VLM5kyg.js +1 -0
  8. package/dist/artifact-DGjzHYUT.js +1 -0
  9. package/dist/{attachments-Qr4kg-2b.js → attachments-YvXHlg88.js} +1 -1
  10. package/dist/{audio-visualizer-DToYdfSc.js → audio-visualizer-9lz5IHsL.js} +1 -1
  11. package/dist/{badge-CdEu_jn2.js → badge-Dh_vp8A5.js} +1 -1
  12. package/dist/{bell-DQAAOpDz.js → bell-CT7_WUwS.js} +1 -1
  13. package/dist/{button-DkuOnGLy.js → button-C_3te6fm.js} +1 -1
  14. package/dist/{card-renderer-Jx70m6_l.js → card-renderer-DZVaGH2e.js} +1 -1
  15. package/dist/check-CiEOVnEN.js +1 -0
  16. package/dist/{checkbox-D7iRB3nL.js → checkbox-Bu2T2e0U.js} +1 -1
  17. package/dist/{checkbox-group-B2_rpoPM.js → checkbox-group-BiryEXPQ.js} +1 -1
  18. package/dist/chevron-down-CSobuZRG.js +1 -0
  19. package/dist/chevron-right-DR9ZAP-2.js +1 -0
  20. package/dist/{choice-card-m0BYqqOK.js → choice-card-CM6IjkmL.js} +1 -1
  21. package/dist/circle-BC66EYF7.js +1 -0
  22. package/dist/circle-check-BqmahW0O.js +1 -0
  23. package/dist/{circle-x-BPG0iPst.js → circle-x-Bk-dA5Wf.js} +1 -1
  24. package/dist/{code-block-ClMLKb7C.js → code-block-B26t-Q7q.js} +1 -1
  25. package/dist/{collapsible-B4DlWicL.js → collapsible-Bhc636Cf.js} +1 -1
  26. package/dist/components/builder-composer-triggers.d.ts +62 -0
  27. package/dist/components/builder-layout.d.ts +54 -0
  28. package/dist/components/builder-message-actions.d.ts +72 -0
  29. package/dist/components/builder-panel.d.ts +189 -0
  30. package/dist/components/builder-preview.d.ts +11 -0
  31. package/dist/components/builder-shell-controls.d.ts +69 -0
  32. package/dist/components/builder-skeleton.d.ts +58 -0
  33. package/dist/components/builder-start.d.ts +75 -0
  34. package/dist/components/builder-workspace-variants.d.ts +23 -0
  35. package/dist/components/captions.d.ts +66 -0
  36. package/dist/{composer-sQ0HcvyG.js → composer-DMI85B6j.js} +1 -1
  37. package/dist/{confirm-card-rQWDQsnC.js → confirm-card-B0YIAwXp.js} +1 -1
  38. package/dist/construct-cli.es.js +3 -3
  39. package/dist/construct.d.ts +5 -0
  40. package/dist/construct.js +327 -0
  41. package/dist/{context-0kg4ZX1J.js → context-DWgfhqWp.js} +1 -1
  42. package/dist/controllable-BagRpyHv.js +1 -0
  43. package/dist/{conversation-item-BxwQLaFJ.js → conversation-item-BsOsVGmT.js} +1 -1
  44. package/dist/{conversation-list-BCfGN1JU.js → conversation-list-aX3Vtc7L.js} +1 -1
  45. package/dist/{copy-n9u9rqpi.js → copy-BmEwsNhJ.js} +1 -1
  46. package/dist/core-C8fzo39E.js +1 -12
  47. package/dist/{create-tween-uPkArjIG.js → create-tween-CNOAU3Fx.js} +1 -1
  48. package/dist/{create-tween-C-q-JCM-.js → create-tween-WfqiENls.js} +1 -1
  49. package/dist/{create-tween-CRrJXxBd.js → create-tween-wlFtW9Kh.js} +1 -1
  50. package/dist/{create-tween-DZ3RRDHD.js → create-tween-zt79ba32.js} +1 -1
  51. package/dist/{default-input-CaMrJkgH.js → default-input-DMV5Eaze.js} +1 -1
  52. package/dist/define-CI0y3eE4.js +1 -0
  53. package/dist/define.js +40 -40
  54. package/dist/define.server.js +45 -45
  55. package/dist/{disclosure-WUImBbDv.js → disclosure-NnACBxsC.js} +1 -1
  56. package/dist/{dropdown-wZVeJOMd.js → dropdown-DT7G0RGR.js} +1 -1
  57. package/dist/elements/agent-card.js +1 -1
  58. package/dist/elements/artifact.js +1 -1
  59. package/dist/elements/attachments.js +1 -1
  60. package/dist/elements/audio-visualizer.js +1 -1
  61. package/dist/elements/avatar.js +1 -1
  62. package/dist/elements/badge.js +1 -1
  63. package/dist/elements/button.js +1 -1
  64. package/dist/elements/card.js +1 -1
  65. package/dist/elements/cards.js +1 -1
  66. package/dist/elements/chain-of-thought.js +1 -1
  67. package/dist/elements/chat-scope-picker.js +1 -1
  68. package/dist/elements/chat-workspace.js +1 -1
  69. package/dist/elements/chat.js +1 -1
  70. package/dist/elements/checkbox-group.js +1 -1
  71. package/dist/elements/checkbox.js +1 -1
  72. package/dist/elements/checkpoint.js +1 -1
  73. package/dist/elements/choice.js +1 -1
  74. package/dist/elements/coachmark.js +1 -1
  75. package/dist/elements/code-block.js +1 -1
  76. package/dist/elements/command.js +1 -1
  77. package/dist/elements/compare.js +1 -1
  78. package/dist/elements/composer.js +1 -1
  79. package/dist/elements/confirm-card.js +1 -1
  80. package/dist/elements/context-meter.js +1 -1
  81. package/dist/elements/conversation-item.js +1 -1
  82. package/dist/elements/conversation-list.js +1 -1
  83. package/dist/elements/dialog.js +1 -1
  84. package/dist/elements/dock.js +1 -1
  85. package/dist/elements/dropdown.js +1 -1
  86. package/dist/elements/editable-label.js +1 -1
  87. package/dist/elements/embed.js +1 -1
  88. package/dist/elements/empty.js +1 -1
  89. package/dist/elements/feedback-bar.js +1 -1
  90. package/dist/elements/file-tree.js +1 -1
  91. package/dist/elements/file-upload.js +1 -1
  92. package/dist/elements/form.js +1 -1
  93. package/dist/elements/hover-card.js +1 -1
  94. package/dist/elements/icon.js +1 -1
  95. package/dist/elements/image.js +1 -1
  96. package/dist/elements/input.js +1 -1
  97. package/dist/elements/kbd.js +1 -1
  98. package/dist/elements/link-preview.js +1 -1
  99. package/dist/elements/loader.js +1 -1
  100. package/dist/elements/markdown.js +1 -1
  101. package/dist/elements/menu.js +1 -1
  102. package/dist/elements/message-skills.js +1 -1
  103. package/dist/elements/message.js +1 -1
  104. package/dist/elements/model-switcher.js +1 -1
  105. package/dist/elements/nav.js +1 -1
  106. package/dist/elements/notice.js +1 -1
  107. package/dist/elements/pane-grid.js +1 -1
  108. package/dist/elements/pane-group.js +1 -1
  109. package/dist/elements/pane.js +1 -1
  110. package/dist/elements/popover.js +1 -1
  111. package/dist/elements/progress-bar.js +1 -1
  112. package/dist/elements/prompt-dock.js +1 -1
  113. package/dist/elements/prompt-input.js +1 -1
  114. package/dist/elements/prompt-suggestions.js +1 -1
  115. package/dist/elements/radio-group.js +1 -1
  116. package/dist/elements/reasoning.js +1 -1
  117. package/dist/elements/remote.js +1 -1
  118. package/dist/elements/resizable.js +1 -1
  119. package/dist/elements/response-stream.js +1 -1
  120. package/dist/elements/screen.js +1 -1
  121. package/dist/elements/scroll-area.js +1 -1
  122. package/dist/elements/scroll-button.js +1 -1
  123. package/dist/elements/search.js +1 -1
  124. package/dist/elements/segmented.js +1 -1
  125. package/dist/elements/select.js +1 -1
  126. package/dist/elements/separator.js +1 -1
  127. package/dist/elements/setting-item.js +1 -1
  128. package/dist/elements/settings-group.js +1 -1
  129. package/dist/elements/skeleton.js +1 -1
  130. package/dist/elements/slider.js +1 -1
  131. package/dist/elements/source.js +1 -1
  132. package/dist/elements/status.js +1 -1
  133. package/dist/elements/switch.js +1 -1
  134. package/dist/elements/tabs.js +1 -1
  135. package/dist/elements/tasks.js +1 -1
  136. package/dist/elements/text-shimmer.js +1 -1
  137. package/dist/elements/thinking-bar.js +1 -1
  138. package/dist/elements/thread.js +1 -1
  139. package/dist/elements/toast.js +1 -1
  140. package/dist/elements/tool.js +1 -1
  141. package/dist/elements/tooltip.js +1 -1
  142. package/dist/elements/voice-input.js +1 -1
  143. package/dist/elements/voice-output.js +1 -1
  144. package/dist/{ellipsis-CbOpJnU3.js → ellipsis-6pJ7SxYT.js} +1 -1
  145. package/dist/{embed-CrfjkbUG.js → embed-BMje-nxj.js} +1 -1
  146. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  147. package/dist/{external-link-ByXAwBBQ.js → external-link-Beh9DKeR.js} +1 -1
  148. package/dist/{file-text-DMib2qwt.js → file-text-D1GPfZ8Q.js} +1 -1
  149. package/dist/{file-tree-CJqM2aP7.js → file-tree-Dwj2lqg-.js} +1 -1
  150. package/dist/{folder-_BAb929C.js → folder-b6D8x1DY.js} +1 -1
  151. package/dist/{form-DSZgZQZk.js → form-DWgdxDXu.js} +1 -1
  152. package/dist/{hover-card-BQbul9eq.js → hover-card-CWRkqm40.js} +1 -1
  153. package/dist/{icon-CdcfRhYI.js → icon-CL0jdhsf.js} +1 -1
  154. package/dist/index.js +1741 -1725
  155. package/dist/index.server.js +1582 -1566
  156. package/dist/{info-DsFjGuI_.js → info-0cOUherQ.js} +1 -1
  157. package/dist/{input-DKbmkMos.js → input-BH6Ru91Q.js} +1 -1
  158. package/dist/kai.es.js +1 -1
  159. package/dist/{kbd-PvdGhX4s.js → kbd-DRAnVtNX.js} +1 -1
  160. package/dist/{link-zF8PzWfF.js → link-Dlr0vssB.js} +1 -1
  161. package/dist/{link-preview-DbM1866N.js → link-preview-DODgRyV9.js} +1 -1
  162. package/dist/loader-KvJB6NrT.js +1 -0
  163. package/dist/{markdown-LMvmAyBk.js → markdown-DX9tuJVj.js} +1 -1
  164. package/dist/mcp.es.js +9 -5
  165. package/dist/{message-BYZECyek.js → message-BqQ7Ot5q.js} +1 -1
  166. package/dist/{message-BSsgvHvf.js → message-DkaGfBd8.js} +1 -1
  167. package/dist/message-circle-BPpp5QKv.js +1 -0
  168. package/dist/message-square-BLbsd9BJ.js +1 -0
  169. package/dist/{minimize-2-BQRoBV1V.js → minimize-2-CyOHJwcN.js} +1 -1
  170. package/dist/{model-switcher-CMpCOYcB.js → model-switcher-0hrKDiK2.js} +1 -1
  171. package/dist/{overlay-Cb-MkyDa.js → overlay-DBMFXie6.js} +1 -1
  172. package/dist/{panel-right-i8warFxT.js → panel-right-t8SWJL6e.js} +1 -1
  173. package/dist/{paperclip-ByY3UVO6.js → paperclip-CdzuOjbU.js} +1 -1
  174. package/dist/play-BXy1u7rW.js +1 -0
  175. package/dist/primitives/use-auto-resize.d.ts +11 -0
  176. package/dist/{progress-bar-jVAHvMUf.js → progress-bar-CiBtxMWT.js} +1 -1
  177. package/dist/{prompt-suggestion-CD-qtNgC.js → prompt-suggestion-I_DHP21i.js} +1 -1
  178. package/dist/{radio-BsoBMhkF.js → radio-C_p3n39l.js} +1 -1
  179. package/dist/{reasoning-4kBPtlTx.js → reasoning-BDwy_tIe.js} +1 -1
  180. package/dist/register-impl-DvEnhIxx.js +424 -0
  181. package/dist/{resizable-uPmY9VY-.js → resizable-SYC-fStM.js} +1 -1
  182. package/dist/{rotate-ccw-B2xn93py.js → rotate-ccw-B1nwmwuY.js} +1 -1
  183. package/dist/{rotate-cw-CMVLoCyH.js → rotate-cw-CLAnBcm1.js} +1 -1
  184. package/dist/{scroll-area-BqLUo8ZZ.js → scroll-area-zRyXoLhI.js} +1 -1
  185. package/dist/{scroll-button-DslXiJyL.js → scroll-button-jzrbYCG9.js} +1 -1
  186. package/dist/{select-2cLRtPGT.js → select-DM-0nEe0.js} +1 -1
  187. package/dist/{separator-BWQtNJcM.js → separator-BToOOoOt.js} +1 -1
  188. package/dist/{settings-BBR63jLg.js → settings-PaGo_S4U.js} +1 -1
  189. package/dist/{settings-group-B2ciy-Iw.js → settings-group-BFXGIfXq.js} +1 -1
  190. package/dist/{skeleton-CkHI-HgC.js → skeleton-DYpmFnnm.js} +1 -1
  191. package/dist/{slider-DDR9U-i0.js → slider-ebutAmkQ.js} +1 -1
  192. package/dist/{solid-DruVOXnf.js → solid-15v_3WVL.js} +3563 -3412
  193. package/dist/{solid-BzCFdL25.js → solid-5P-otgdi.js} +4502 -4296
  194. package/dist/solid.d.ts +6 -0
  195. package/dist/solid.js +259 -254
  196. package/dist/solid.server.js +259 -254
  197. package/dist/{source-GEnFF528.js → source-c1gpRl9h.js} +1 -1
  198. package/dist/{star-CilHq8GP.js → star-pcV_3LqF.js} +1 -1
  199. package/dist/{store-Ciyk6eZG.js → store-CSgbFFCg.js} +1 -1
  200. package/dist/{switch-KkeQIbuH.js → switch-Bh2OdLV2.js} +1 -1
  201. package/dist/{tasks-card-BrN4bggJ.js → tasks-card-CbqQAn2S.js} +1 -1
  202. package/dist/text-shimmer-BSzgEnDH.js +1 -0
  203. package/dist/textarea-DrYNt_0z.js +1 -0
  204. package/dist/theme.tokens.css +22 -21
  205. package/dist/{thumbs-up-CsT9Wzb9.js → thumbs-up-BL3-NenK.js} +1 -1
  206. package/dist/{toast-store-tgK6MuMv.js → toast-store-DkOlYczt.js} +1 -1
  207. package/dist/{tool-DzUjIBT8.js → tool-CeIWUVUe.js} +1 -1
  208. package/dist/{tooltip-Bkkg_4t0.js → tooltip-GA-nmg06.js} +1 -1
  209. package/dist/{trash-2-jBKxjGGQ.js → trash-2-CT66QWlm.js} +1 -1
  210. package/dist/{triangle-alert-DlQ68ppf.js → triangle-alert-CeHLWxhD.js} +1 -1
  211. package/dist/ui/color-field.d.ts +48 -0
  212. package/dist/ui/textarea.d.ts +4 -0
  213. package/dist/ui/toggle-chip.d.ts +40 -0
  214. package/dist/{upload-TcAHXv9W.js → upload-9Csb0F0J.js} +1 -1
  215. package/dist/{use-card-resolution-DaZqAdWf.js → use-card-resolution-Zg0a08Z-.js} +1 -1
  216. package/dist/{variant-aurora-DbW_OWL2.js → variant-aurora-4VBQHIKV.js} +1 -1
  217. package/dist/{variant-aurora-CNmfHhcx.js → variant-aurora-DBeCAQNk.js} +2 -2
  218. package/dist/{variant-aurora-D6GsdTPA.js → variant-aurora-FzHVXHby.js} +2 -2
  219. package/dist/{variant-aurora-BhLuYxJR.js → variant-aurora-LE3fqxgw.js} +1 -1
  220. package/dist/{variant-custom-BvYHR62b.js → variant-custom-AFRGcOBS.js} +1 -1
  221. package/dist/{variant-custom-DV2x254s.js → variant-custom-BQkNuPpE.js} +2 -2
  222. package/dist/{variant-custom-BRvaNHSi.js → variant-custom-DI5R0rln.js} +1 -1
  223. package/dist/{variant-custom-DMTrEO5w.js → variant-custom-WWnrrRHS.js} +2 -2
  224. package/dist/{variant-wave-CyBueXj9.js → variant-wave-DUCbH5oI.js} +2 -2
  225. package/dist/{variant-wave-BNMGrDfj.js → variant-wave-DuQV7DhQ.js} +2 -2
  226. package/dist/{variant-wave-BpDd8t3Z.js → variant-wave-nSI2sfII.js} +1 -1
  227. package/dist/{variant-wave-sp-qwsdI.js → variant-wave-wTP5v_jU.js} +1 -1
  228. package/dist/x-eiO9V6J6.js +1 -0
  229. package/{src/elements/styles.css → kit-base.css} +27 -44
  230. package/package.json +32 -17
  231. package/solid.css +33 -0
  232. package/theme.css +39 -23
  233. package/bin/route.test.js +0 -58
  234. package/dist/arrow-down-CjRU3JgV.js +0 -1
  235. package/dist/arrow-left-Bnpb1UEW.js +0 -1
  236. package/dist/artifact-Bwt7OgcR.js +0 -1
  237. package/dist/check-njkVdZu2.js +0 -1
  238. package/dist/chevron-down-B72s6PXR.js +0 -1
  239. package/dist/chevron-right-BatuHzUm.js +0 -1
  240. package/dist/circle-check-B62pODB3.js +0 -1
  241. package/dist/circle-zx0ByzY9.js +0 -1
  242. package/dist/controllable-CnGpMF6r.js +0 -1
  243. package/dist/define-By-uL588.js +0 -1
  244. package/dist/loader-BM4CEz4G.js +0 -1
  245. package/dist/message-circle-DruwObfX.js +0 -1
  246. package/dist/message-square-BG6q6mlm.js +0 -1
  247. package/dist/play-BvKKq3fX.js +0 -1
  248. package/dist/register-impl-B1hLkrI8.js +0 -424
  249. package/dist/text-shimmer-Dcj1MHuq.js +0 -1
  250. package/dist/textarea-Dpvbngbg.js +0 -1
  251. package/dist/x-Z5UntkIJ.js +0 -1
  252. package/src/agent-tooling/README.md +0 -192
  253. package/src/agent-tooling/archetypes.ts +0 -205
  254. package/src/agent-tooling/catalog/README.md +0 -676
  255. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  256. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  257. package/src/agent-tooling/catalog/invariants.ts +0 -284
  258. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  259. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  260. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  261. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  262. package/src/agent-tooling/construct/cli.ts +0 -147
  263. package/src/agent-tooling/construct/codegen.ts +0 -1635
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  265. package/src/agent-tooling/construct/dev.ts +0 -148
  266. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  267. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  268. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  269. package/src/agent-tooling/construct/schema.ts +0 -452
  270. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  271. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  272. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  273. package/src/agent-tooling/integrations/mastra.ts +0 -182
  274. package/src/agent-tooling/integrations/mock.ts +0 -148
  275. package/src/agent-tooling/integrations/ollama.ts +0 -97
  276. package/src/agent-tooling/integrations/openai.ts +0 -95
  277. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  278. package/src/agent-tooling/integrations/pi.ts +0 -176
  279. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  280. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  281. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  282. package/src/agent-tooling/mcp/manifest.ts +0 -422
  283. package/src/agent-tooling/mcp/server.ts +0 -116
  284. package/src/agent-tooling/mcp/stdio.ts +0 -18
  285. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  286. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  287. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  288. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  289. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  290. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  291. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  292. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  293. package/src/agent-tooling/recipes/index.ts +0 -22
  294. package/src/agent-tooling/recipes/types.ts +0 -32
  295. package/src/agent-tooling/registry.ts +0 -132
  296. package/src/agent-tooling/route-emit.ts +0 -305
  297. package/src/agent-tooling/types.ts +0 -390
  298. package/src/components/artifact-card.tsx +0 -120
  299. package/src/components/artifact.tsx +0 -914
  300. package/src/components/attachment-types.ts +0 -66
  301. package/src/components/attachments.tsx +0 -536
  302. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  303. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  304. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  305. package/src/components/audio-visualizer/index.tsx +0 -528
  306. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  307. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  308. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  309. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  310. package/src/components/audio-visualizer/sizes.ts +0 -54
  311. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  312. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  313. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  314. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  315. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  316. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  317. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  318. package/src/components/card-fallback.tsx +0 -60
  319. package/src/components/card-renderer.tsx +0 -220
  320. package/src/components/card.tsx +0 -212
  321. package/src/components/chain-of-thought.tsx +0 -348
  322. package/src/components/chat-container.tsx +0 -89
  323. package/src/components/chat-scope-picker.tsx +0 -57
  324. package/src/components/chat-thread.tsx +0 -1014
  325. package/src/components/checkpoint.tsx +0 -88
  326. package/src/components/choice-card.tsx +0 -743
  327. package/src/components/coachmark.tsx +0 -249
  328. package/src/components/code-block.tsx +0 -181
  329. package/src/components/composer-dom.ts +0 -159
  330. package/src/components/composer-highlight.ts +0 -242
  331. package/src/components/composer-history.ts +0 -82
  332. package/src/components/composer.tsx +0 -1075
  333. package/src/components/confirm-card.tsx +0 -402
  334. package/src/components/context.tsx +0 -377
  335. package/src/components/conversation-item.tsx +0 -241
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/conversation-panel.tsx +0 -118
  338. package/src/components/dismissed-stub.tsx +0 -80
  339. package/src/components/embed.tsx +0 -200
  340. package/src/components/empty.tsx +0 -177
  341. package/src/components/feedback-bar.tsx +0 -166
  342. package/src/components/file-tree.tsx +0 -530
  343. package/src/components/file-upload.tsx +0 -167
  344. package/src/components/form-widgets.tsx +0 -525
  345. package/src/components/form.tsx +0 -1296
  346. package/src/components/home-panel.tsx +0 -159
  347. package/src/components/image.tsx +0 -65
  348. package/src/components/link-preview.tsx +0 -195
  349. package/src/components/loader.tsx +0 -367
  350. package/src/components/markdown.tsx +0 -162
  351. package/src/components/message-skills.tsx +0 -40
  352. package/src/components/message.tsx +0 -765
  353. package/src/components/model-switcher.tsx +0 -132
  354. package/src/components/prompt-input.tsx +0 -188
  355. package/src/components/prompt-suggestion.tsx +0 -150
  356. package/src/components/reasoning.tsx +0 -293
  357. package/src/components/response-compare-types.ts +0 -152
  358. package/src/components/response-compare.tsx +0 -455
  359. package/src/components/response-stream.tsx +0 -109
  360. package/src/components/screen.tsx +0 -181
  361. package/src/components/scroll-button.tsx +0 -93
  362. package/src/components/source.tsx +0 -192
  363. package/src/components/tasks-card.tsx +0 -801
  364. package/src/components/text-shimmer.tsx +0 -37
  365. package/src/components/thinking-bar.tsx +0 -50
  366. package/src/components/thread.tsx +0 -228
  367. package/src/components/toast.tsx +0 -503
  368. package/src/components/tool-classify.ts +0 -26
  369. package/src/components/tool-types.ts +0 -49
  370. package/src/components/tool.tsx +0 -190
  371. package/src/components/use-card-resolution.ts +0 -44
  372. package/src/components/voice-input.tsx +0 -222
  373. package/src/components/voice-output.tsx +0 -242
  374. package/src/components/widget-tab-bar.tsx +0 -73
  375. package/src/components/workspace-shell.tsx +0 -285
  376. package/src/diagnostics/hook.ts +0 -352
  377. package/src/diagnostics/index.ts +0 -82
  378. package/src/diagnostics/report-request.ts +0 -296
  379. package/src/elements/agent-card.tsx +0 -67
  380. package/src/elements/artifact.tsx +0 -194
  381. package/src/elements/attachments.tsx +0 -140
  382. package/src/elements/audio-visualizer.tsx +0 -227
  383. package/src/elements/autoloader.ts +0 -89
  384. package/src/elements/avatar.tsx +0 -33
  385. package/src/elements/badge.tsx +0 -32
  386. package/src/elements/button.tsx +0 -149
  387. package/src/elements/card.tsx +0 -133
  388. package/src/elements/cards.tsx +0 -266
  389. package/src/elements/chain-of-thought.tsx +0 -141
  390. package/src/elements/chat-scope-picker.tsx +0 -65
  391. package/src/elements/chat-types.ts +0 -102
  392. package/src/elements/chat-workspace.tsx +0 -188
  393. package/src/elements/chat.tsx +0 -304
  394. package/src/elements/checkbox-group.tsx +0 -164
  395. package/src/elements/checkbox.tsx +0 -134
  396. package/src/elements/checkpoint.tsx +0 -47
  397. package/src/elements/choice.tsx +0 -100
  398. package/src/elements/coachmark.tsx +0 -90
  399. package/src/elements/code-block.tsx +0 -60
  400. package/src/elements/command.tsx +0 -197
  401. package/src/elements/compare.tsx +0 -111
  402. package/src/elements/compiled.css +0 -2
  403. package/src/elements/composer.tsx +0 -162
  404. package/src/elements/confirm-card.tsx +0 -76
  405. package/src/elements/context-meter.tsx +0 -107
  406. package/src/elements/conversation-item.tsx +0 -120
  407. package/src/elements/conversation-list.tsx +0 -203
  408. package/src/elements/css.ts +0 -5
  409. package/src/elements/default-input.tsx +0 -392
  410. package/src/elements/define-entry.ts +0 -12
  411. package/src/elements/define.tsx +0 -563
  412. package/src/elements/diagnostic-events.ts +0 -114
  413. package/src/elements/dialog.tsx +0 -145
  414. package/src/elements/disclosure.ts +0 -95
  415. package/src/elements/dock.tsx +0 -215
  416. package/src/elements/dropdown.tsx +0 -123
  417. package/src/elements/editable-label.tsx +0 -140
  418. package/src/elements/element-data-types.ts +0 -152
  419. package/src/elements/element-diagnostics.ts +0 -392
  420. package/src/elements/element-manifest.json +0 -354
  421. package/src/elements/element-nonscalar.json +0 -187
  422. package/src/elements/element-types.d.ts +0 -4353
  423. package/src/elements/embed.tsx +0 -35
  424. package/src/elements/empty.tsx +0 -29
  425. package/src/elements/feedback-bar.tsx +0 -66
  426. package/src/elements/file-tree.tsx +0 -62
  427. package/src/elements/file-upload.tsx +0 -44
  428. package/src/elements/form.tsx +0 -94
  429. package/src/elements/hover-card.tsx +0 -80
  430. package/src/elements/icon.tsx +0 -41
  431. package/src/elements/image.tsx +0 -32
  432. package/src/elements/input.tsx +0 -492
  433. package/src/elements/kbd.tsx +0 -45
  434. package/src/elements/link-preview.tsx +0 -34
  435. package/src/elements/loader.tsx +0 -25
  436. package/src/elements/markdown.tsx +0 -38
  437. package/src/elements/menu.tsx +0 -241
  438. package/src/elements/message-skills.tsx +0 -83
  439. package/src/elements/message.tsx +0 -361
  440. package/src/elements/model-switcher.tsx +0 -121
  441. package/src/elements/nav.tsx +0 -87
  442. package/src/elements/notice.tsx +0 -53
  443. package/src/elements/pane-grid.tsx +0 -111
  444. package/src/elements/pane-group.tsx +0 -119
  445. package/src/elements/pane.tsx +0 -129
  446. package/src/elements/popover.tsx +0 -81
  447. package/src/elements/progress-bar.tsx +0 -39
  448. package/src/elements/prompt-dock.tsx +0 -82
  449. package/src/elements/prompt-input.tsx +0 -240
  450. package/src/elements/prompt-suggestions.tsx +0 -113
  451. package/src/elements/radio-group.tsx +0 -129
  452. package/src/elements/reasoning.tsx +0 -71
  453. package/src/elements/register-impl.ts +0 -148
  454. package/src/elements/register.ts +0 -76
  455. package/src/elements/remote.tsx +0 -225
  456. package/src/elements/resizable.globals.d.ts +0 -36
  457. package/src/elements/resizable.tsx +0 -704
  458. package/src/elements/response-stream.tsx +0 -40
  459. package/src/elements/screen.tsx +0 -90
  460. package/src/elements/scroll-area.tsx +0 -33
  461. package/src/elements/scroll-button.tsx +0 -179
  462. package/src/elements/search.tsx +0 -185
  463. package/src/elements/segmented.tsx +0 -129
  464. package/src/elements/select.tsx +0 -165
  465. package/src/elements/separator.tsx +0 -36
  466. package/src/elements/setting-item.tsx +0 -50
  467. package/src/elements/settings-group.tsx +0 -37
  468. package/src/elements/skeleton.tsx +0 -45
  469. package/src/elements/slider.tsx +0 -171
  470. package/src/elements/slot-text.ts +0 -73
  471. package/src/elements/slots.ts +0 -787
  472. package/src/elements/source.tsx +0 -126
  473. package/src/elements/status.tsx +0 -42
  474. package/src/elements/switch.tsx +0 -118
  475. package/src/elements/tabs.tsx +0 -95
  476. package/src/elements/tasks.tsx +0 -103
  477. package/src/elements/text-shimmer.tsx +0 -28
  478. package/src/elements/thinking-bar.tsx +0 -43
  479. package/src/elements/thread.tsx +0 -139
  480. package/src/elements/toast.tsx +0 -106
  481. package/src/elements/tool.tsx +0 -78
  482. package/src/elements/tooltip.tsx +0 -85
  483. package/src/elements/validate-messages.ts +0 -76
  484. package/src/elements/voice-input.tsx +0 -100
  485. package/src/elements/voice-output.tsx +0 -82
  486. package/src/index.ts +0 -430
  487. package/src/primitives/audio-bands.ts +0 -174
  488. package/src/primitives/card-component-types.ts +0 -63
  489. package/src/primitives/card-contract.ts +0 -80
  490. package/src/primitives/card-data-types.ts +0 -361
  491. package/src/primitives/card-host.tsx +0 -37
  492. package/src/primitives/card-recovery.ts +0 -160
  493. package/src/primitives/card-registry.tsx +0 -78
  494. package/src/primitives/card-resolution.ts +0 -36
  495. package/src/primitives/card-routing.ts +0 -85
  496. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  497. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  498. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  499. package/src/primitives/card-schemas/choice.schema.json +0 -75
  500. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  501. package/src/primitives/card-schemas/embed.schema.json +0 -63
  502. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  503. package/src/primitives/card-schemas/form.schema.json +0 -53
  504. package/src/primitives/card-schemas/link.schema.json +0 -54
  505. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  506. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  507. package/src/primitives/card-tags.ts +0 -61
  508. package/src/primitives/card-validate-cards.ts +0 -255
  509. package/src/primitives/card-validate-schemas.ts +0 -58
  510. package/src/primitives/card-validate.ts +0 -131
  511. package/src/primitives/chat-config.tsx +0 -103
  512. package/src/primitives/composer-model.ts +0 -49
  513. package/src/primitives/composer-triggers.ts +0 -35
  514. package/src/primitives/controllable.ts +0 -21
  515. package/src/primitives/conversation-store.ts +0 -248
  516. package/src/primitives/create-kai-chat.ts +0 -66
  517. package/src/primitives/create-tween.ts +0 -266
  518. package/src/primitives/embed-providers.ts +0 -254
  519. package/src/primitives/field-mask.ts +0 -256
  520. package/src/primitives/field-semantics.ts +0 -115
  521. package/src/primitives/highlighter.ts +0 -157
  522. package/src/primitives/input-mask.ts +0 -853
  523. package/src/primitives/link-preview.ts +0 -87
  524. package/src/primitives/message-feedback.ts +0 -124
  525. package/src/primitives/pdf-preview.ts +0 -121
  526. package/src/primitives/toast-store.ts +0 -338
  527. package/src/primitives/url-scheme-policy.ts +0 -70
  528. package/src/primitives/use-audio-analysis.ts +0 -340
  529. package/src/primitives/use-auto-resize.ts +0 -31
  530. package/src/primitives/use-resize-observer.ts +0 -45
  531. package/src/primitives/use-sequencer.ts +0 -72
  532. package/src/primitives/use-speech-recognition.ts +0 -146
  533. package/src/primitives/use-stick-to-bottom.ts +0 -75
  534. package/src/primitives/use-text-stream.ts +0 -143
  535. package/src/primitives/use-voice-recorder.ts +0 -62
  536. package/src/primitives/visualizer-sequences.ts +0 -350
  537. package/src/remote/host-embed.ts +0 -345
  538. package/src/remote/index.ts +0 -2
  539. package/src/remote/origin.ts +0 -30
  540. package/src/remote/provider-runtime.ts +0 -262
  541. package/src/remote/provider.ts +0 -2
  542. package/src/remote/validate.ts +0 -22
  543. package/src/remote/version.ts +0 -12
  544. package/src/remote/wire.ts +0 -48
  545. package/src/schemas/from-tool-call.ts +0 -151
  546. package/src/schemas/index.ts +0 -341
  547. package/src/schemas/provider-subsets.ts +0 -538
  548. package/src/schemas/registry.ts +0 -355
  549. package/src/schemas/tool-defs.ts +0 -793
  550. package/src/solid.ts +0 -173
  551. package/src/state/index.ts +0 -44
  552. package/src/state/messages.ts +0 -53
  553. package/src/state/mock.ts +0 -297
  554. package/src/state/parts.ts +0 -295
  555. package/src/state/persistence.ts +0 -180
  556. package/src/state/stream.ts +0 -246
  557. package/src/state/suggestions.ts +0 -9
  558. package/src/state/threads.ts +0 -142
  559. package/src/test-utils/fake-clock.ts +0 -88
  560. package/src/types.ts +0 -95
  561. package/src/ui/action-icons.ts +0 -53
  562. package/src/ui/agent-card.tsx +0 -218
  563. package/src/ui/avatar.tsx +0 -23
  564. package/src/ui/badge.tsx +0 -21
  565. package/src/ui/button.tsx +0 -49
  566. package/src/ui/card.tsx +0 -245
  567. package/src/ui/checkbox-group.tsx +0 -153
  568. package/src/ui/checkbox.tsx +0 -63
  569. package/src/ui/collapsible.tsx +0 -163
  570. package/src/ui/command.tsx +0 -103
  571. package/src/ui/dialog.tsx +0 -223
  572. package/src/ui/dock.tsx +0 -630
  573. package/src/ui/dropdown.tsx +0 -636
  574. package/src/ui/editable-label.tsx +0 -112
  575. package/src/ui/hover-card.tsx +0 -345
  576. package/src/ui/icon.tsx +0 -167
  577. package/src/ui/input.tsx +0 -391
  578. package/src/ui/kbd.tsx +0 -118
  579. package/src/ui/nav.tsx +0 -282
  580. package/src/ui/notice.tsx +0 -84
  581. package/src/ui/overlay.tsx +0 -277
  582. package/src/ui/pane-grid.tsx +0 -117
  583. package/src/ui/pane-group.tsx +0 -291
  584. package/src/ui/pane.tsx +0 -193
  585. package/src/ui/popover.tsx +0 -106
  586. package/src/ui/progress-bar.tsx +0 -83
  587. package/src/ui/prompt-dock.tsx +0 -145
  588. package/src/ui/radio.tsx +0 -150
  589. package/src/ui/resizable.tsx +0 -693
  590. package/src/ui/scroll-area.tsx +0 -26
  591. package/src/ui/segmented.tsx +0 -109
  592. package/src/ui/select.tsx +0 -168
  593. package/src/ui/separator.tsx +0 -10
  594. package/src/ui/settings-group.tsx +0 -67
  595. package/src/ui/skeleton.tsx +0 -73
  596. package/src/ui/slider.tsx +0 -178
  597. package/src/ui/status.tsx +0 -48
  598. package/src/ui/switch.tsx +0 -119
  599. package/src/ui/tabs.tsx +0 -168
  600. package/src/ui/textarea.tsx +0 -21
  601. package/src/ui/tooltip.tsx +0 -118
  602. package/src/utils/cn.ts +0 -30
  603. package/src/wire/chunk.ts +0 -248
  604. package/src/wire/consume.ts +0 -599
  605. package/src/wire/diagnostics.ts +0 -727
  606. package/src/wire/encode-probe.ts +0 -214
  607. package/src/wire/encode.ts +0 -947
  608. package/src/wire/files.ts +0 -342
  609. package/src/wire/formats/anthropic.ts +0 -274
  610. package/src/wire/formats/openai.ts +0 -228
  611. package/src/wire/index.ts +0 -95
  612. package/src/wire/media-types.ts +0 -344
  613. package/src/wire/read.ts +0 -396
  614. package/src/wire/sink-helpers.ts +0 -50
  615. package/src/wire/sse.ts +0 -153
@@ -1,793 +0,0 @@
1
- // Card schemas -> provider tool definitions.
2
- //
3
- // THE PROBLEM THIS SOLVES
4
- // -----------------------
5
- // A developer who wants a model to produce a `confirm` card today hand-writes a tool
6
- // definition that approximates a schema they cannot import, then hand-writes a mapper
7
- // from the model's arguments back to a CardEnvelope. This repo's own reference
8
- // harness does exactly that and says so in a comment
9
- // (examples/internal/openrouter-spike/src/tools.ts). That is the same shape written
10
- // in five places. This file removes two of them: the tool definition is GENERATED
11
- // from the schema the card already validates against, so it cannot drift.
12
- //
13
- // WHAT THIS FILE IS NOT
14
- // ---------------------
15
- // It is not a provider client and it never becomes one. No `openai`, no
16
- // `@anthropic-ai/sdk`, no `fetch`. The provider envelope shapes below are declared
17
- // here as plain structural types, which is what lets `@kitn.ai/ui` keep its rule that
18
- // nothing under `src/` depends on a provider SDK. The kit PARSES and PROJECTS; the
19
- // consumer FETCHES.
20
- //
21
- // THE HEADLINE, MEASURED, NOT RECALLED
22
- // ------------------------------------
23
- // `strict: true` currently throws for EVERY built-in card on BOTH providers. That is
24
- // not a bug in this file, it is what the schemas say when you hold them against the
25
- // two documented subsets (see provider-subsets.ts for the two source docs). The
26
- // authored schemas use `minLength` (confirm/choice/tasks), `maxLength` +
27
- // `format: "uri"` (link/embed/artifact), `minimum` (tasks/embed/artifact),
28
- // `maxItems` (confirm/artifact), `pattern` (embed), `if`/`then` (embed), `oneOf`
29
- // (artifact), a free-form object (form) and untyped `payload`/`allowOther` members
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.
38
- //
39
- // The alternative was to silently drop the offending keywords. That is rejected for
40
- // the reason the plan gives: a dropped `maxItems: 4` means the model emits six
41
- // actions and the card renders six buttons, with nothing anywhere saying the contract
42
- // was quietly loosened. A throw that NAMES the card, the path and the keyword is a
43
- // signal on the developer's own machine, which is the whole point.
44
-
45
- import { toolNameForCardType } from './from-tool-call';
46
- import { cardSchemas } from './index';
47
- import type { CardSchema, CardSchemaName } from './index';
48
- import {
49
- ANTHROPIC_STRICT,
50
- OPENAI_STRICT,
51
- checkProviderSubset,
52
- type ProviderSubset,
53
- type StrictProviderId,
54
- type SubsetViolation,
55
- } from './provider-subsets';
56
-
57
- // THE TOOL NAME IS NOT SPELLED HERE
58
- // ---------------------------------
59
- // `kai_confirm` is produced by `toolNameForCardType()` in ./from-tool-call, which
60
- // also owns the inverse (`cardTypeFromToolName`). Both directions come off one
61
- // string in one module on purpose. If this file wrote `'kai_' + type` instead, the
62
- // two halves could drift, and the symptom would be a model dutifully calling
63
- // `kai_confirm` while the loop's parser looks for something else and routes it to
64
- // `runTool`, where it disappears with no error anywhere.
65
- //
66
- // A `toolPrefix` OVERRIDE IS NOT SHIPPED, AND THAT IS A DECISION.
67
- // The plan reserves `createCardRegistry({ toolPrefix })` for Phase 2. It is
68
- // deliberately NOT stubbed in here, because the inverse hard-codes the `kai_` prefix:
69
- // a `toolPrefix` honoured on this side alone would generate tools the parser cannot
70
- // recognise, which is a worse failure than not having the option. The seam is the
71
- // `CardToolSource` interface below; the override lands in both directions in one
72
- // change, or not at all.
73
-
74
- // ---------------------------------------------------------------------------
75
- // Provider envelope shapes, declared here rather than imported from an SDK
76
- // ---------------------------------------------------------------------------
77
-
78
- /** A projected schema. Deliberately loose: `type` may become `['string','null']`. */
79
- export type ToolParameters = Readonly<Record<string, unknown>>;
80
-
81
- /** `POST /v1/chat/completions` and `/v1/responses` tool entries. */
82
- export interface OpenAIToolDef {
83
- readonly type: 'function';
84
- readonly function: {
85
- readonly name: string;
86
- readonly description: string;
87
- readonly parameters: ToolParameters;
88
- readonly strict?: true;
89
- };
90
- }
91
-
92
- /** `POST /v1/messages` tool entries. Note `input_schema`, NOT `function.parameters`. */
93
- export interface AnthropicToolDef {
94
- readonly name: string;
95
- readonly description: string;
96
- readonly input_schema: ToolParameters;
97
- readonly strict?: true;
98
- }
99
-
100
- /**
101
- * The bare form, for the Vercel AI SDK and anything else that wants the schema
102
- * without a provider envelope: `tool({ inputSchema: jsonSchema(def.schema) })`.
103
- *
104
- * First-class, not a fallback. A developer on `ai@7` defines tools with Zod, and
105
- * handing them an OpenAI-shaped envelope they have to unwrap makes our JSON Schema an
106
- * awkward second source of truth instead of the one they use.
107
- */
108
- export interface JsonSchemaToolDef {
109
- readonly name: string;
110
- readonly description: string;
111
- readonly schema: ToolParameters;
112
- }
113
-
114
- export type ToolProvider = 'openai' | 'anthropic' | 'jsonschema';
115
-
116
- export type ToolDefFor<P extends ToolProvider> = P extends 'openai'
117
- ? OpenAIToolDef
118
- : P extends 'anthropic'
119
- ? AnthropicToolDef
120
- : JsonSchemaToolDef;
121
-
122
- export type ToolDef = OpenAIToolDef | AnthropicToolDef | JsonSchemaToolDef;
123
-
124
- export interface CardToolOptions<P extends ToolProvider = ToolProvider> {
125
- readonly provider: P;
126
- /**
127
- * Opt in to the provider's grammar-constrained mode.
128
- *
129
- * Default `false`, because that is the mode the conformance sweep proved cards in
130
- * and because, today, `true` throws for every built-in card on both providers.
131
- * When it throws it names the card, the path and the keyword.
132
- */
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;
180
- }
181
-
182
- /**
183
- * Where the card types come from.
184
- *
185
- * Phase 1 hands this the built-in `cardSchemas` map directly. Phase 2's
186
- * `createCardRegistry()` returns an object that is structurally a `CardToolSource`,
187
- * so `cardTools(registry, opts)` starts working on custom card types without this
188
- * signature changing. That is the seam, left open on purpose and not built yet.
189
- */
190
- export interface CardToolSource {
191
- readonly schemas: Readonly<Record<string, CardSchema>>;
192
- /** Tool descriptions by card type. Falls back to the built-in copy, then the schema's own. */
193
- readonly descriptions?: Readonly<Record<string, string>>;
194
- }
195
-
196
- export type CardToolInput = CardToolSource | Readonly<Record<string, CardSchema>>;
197
-
198
- // ---------------------------------------------------------------------------
199
- // Tool descriptions
200
- // ---------------------------------------------------------------------------
201
-
202
- /**
203
- * What each card is FOR, addressed to a model.
204
- *
205
- * This is not a sixth copy of a shape. The shape stays in the JSON Schema and is
206
- * never restated here; these are one sentence each of purpose, which exists nowhere
207
- * else, and which a schema's own `description` ("Data payload for a `confirm` card")
208
- * does not provide because it is written for a developer reading the contract.
209
- *
210
- * Typed as an exhaustive `Record<CardSchemaName, string>`, so adding an eighth card
211
- * type fails `tsc` here rather than silently shipping a tool with no description.
212
- */
213
- export const CARD_TOOL_DESCRIPTIONS: Readonly<Record<CardSchemaName, string>> = Object.freeze({
214
- confirm:
215
- 'Show the user an approval card and wait for their decision before you act. Use this whenever you are about to do something consequential, destructive or irreversible.',
216
- choice:
217
- 'Ask the user to pick exactly one option from a list of rich choices. Use this instead of asking in prose when the options are known and finite.',
218
- tasks:
219
- 'Show the user a checklist they can tick, either to select several items for you to act on or to track progress through a sequence of steps.',
220
- form: 'Ask the user for structured input by rendering a form. The data is itself a JSON Schema describing the fields to collect.',
221
- link: 'Show a rich preview of a web page: title, description, image and domain. The card renders what you supply and never fetches the page itself.',
222
- embed: 'Embed a video player (YouTube, Vimeo, or a direct player URL) inline in the conversation.',
223
- artifact:
224
- 'Show something you built (a page, an app, a set of files) in a framed preview with its source alongside, so the user can look at both.',
225
- });
226
-
227
- // ---------------------------------------------------------------------------
228
- // The error
229
- // ---------------------------------------------------------------------------
230
-
231
- export interface UnsupportedCardTool {
232
- readonly cardType: string;
233
- readonly toolName: string;
234
- readonly violations: readonly SubsetViolation[];
235
- }
236
-
237
- /**
238
- * Thrown by `cardTools(..., { strict: true })` when a card cannot be expressed in the
239
- * provider's strict subset.
240
- *
241
- * Carries the structured detail as well as the message, so a build script can render
242
- * it however it likes rather than parsing prose.
243
- */
244
- export class UnsupportedCardToolSchemaError extends Error {
245
- override readonly name = 'UnsupportedCardToolSchemaError';
246
- readonly provider: StrictProviderId;
247
- readonly source: string;
248
- readonly cards: readonly UnsupportedCardTool[];
249
-
250
- constructor(subset: ProviderSubset, cards: readonly UnsupportedCardTool[]) {
251
- super(formatUnsupported(subset, cards));
252
- this.provider = subset.id;
253
- this.source = subset.source;
254
- this.cards = cards;
255
- }
256
-
257
- /** Every distinct keyword named across every failing card, deduped, in order. */
258
- get keywords(): string[] {
259
- const seen = new Set<string>();
260
- for (const card of this.cards) for (const v of card.violations) seen.add(v.keyword);
261
- return [...seen];
262
- }
263
- }
264
-
265
- function formatUnsupported(subset: ProviderSubset, cards: readonly UnsupportedCardTool[]): string {
266
- const lines: string[] = [];
267
- const plural = cards.length === 1 ? 'card type' : 'card types';
268
- lines.push(`${cards.length} ${plural} cannot be a STRICT tool definition under ${subset.label}:`);
269
- for (const card of cards) {
270
- lines.push('');
271
- lines.push(` ${card.toolName} (card type "${card.cardType}") — ${card.violations.length} problem(s):`);
272
- for (const v of card.violations) {
273
- lines.push(` ${v.path}: \`${v.keyword}\` — ${v.reason}`);
274
- }
275
- }
276
- lines.push('');
277
- lines.push(` subset source: ${subset.source} (read ${subset.checkedOn})`);
278
- lines.push(
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.',
280
- );
281
- return lines.join('\n');
282
- }
283
-
284
- // ---------------------------------------------------------------------------
285
- // The projection
286
- // ---------------------------------------------------------------------------
287
-
288
- const isRecord = (v: unknown): v is Record<string, unknown> =>
289
- typeof v === 'object' && v !== null && !Array.isArray(v);
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
-
512
- /**
513
- * Keywords stripped from every projection, strict or not.
514
- *
515
- * `$schema` and `$id` are meta: they address the document, they do not describe the
516
- * instance, and neither provider's subset lists them. `x-kai-*` are our own UI hints
517
- * (`x-kai-control: "tone"` tells a renderer to draw a tone picker); a model has no
518
- * use for them, they cost tokens in every request, and under strict they are an
519
- * unlisted keyword. Stripping them is not a downgrade of the contract, because they
520
- * never constrained an instance in the first place.
521
- */
522
- function isStrippedKeyword(key: string): boolean {
523
- return key === '$schema' || key === '$id' || key.startsWith('x-');
524
- }
525
-
526
- const SUBSCHEMA_KEYS = ['items', 'if', 'then', 'else', 'not', 'contains', 'propertyNames', 'unevaluatedItems', 'additionalItems'];
527
- const SUBSCHEMA_MAP_KEYS = ['properties', 'patternProperties', '$defs', 'definitions', 'dependentSchemas'];
528
- const SUBSCHEMA_LIST_KEYS = ['allOf', 'anyOf', 'oneOf', 'prefixItems'];
529
-
530
- interface ProjectOptions {
531
- /** Force `additionalProperties: false` on every object. Both strict subsets demand it. */
532
- readonly closeObjects: boolean;
533
- /** Put every property in `required`, widening the newly-required ones with `null`. OpenAI only. */
534
- readonly requireEveryProperty: boolean;
535
- }
536
-
537
- /**
538
- * Rewrite a schema for the wire.
539
- *
540
- * Only ever REMOVES metadata or ADDS what a provider mandates. It never drops a
541
- * constraint, which is the invariant that keeps a projected tool definition and the
542
- * card's own validator describing the same set of valid cards.
543
- */
544
- function project(node: unknown, opts: ProjectOptions): unknown {
545
- if (!isRecord(node)) return node;
546
-
547
- const out: Record<string, unknown> = {};
548
- for (const [key, value] of Object.entries(node)) {
549
- if (isStrippedKeyword(key)) continue;
550
- out[key] = value;
551
- }
552
-
553
- // Recurse. `properties` KEYS are arbitrary names, not keywords: form.schema.json
554
- // has properties literally called `properties` and `x-kai-order`, and stripping
555
- // those would delete real fields rather than metadata.
556
- for (const key of SUBSCHEMA_MAP_KEYS) {
557
- const map = out[key];
558
- if (!isRecord(map)) continue;
559
- const next: Record<string, unknown> = {};
560
- for (const [name, child] of Object.entries(map)) next[name] = project(child, opts);
561
- out[key] = next;
562
- }
563
- for (const key of SUBSCHEMA_KEYS) {
564
- if (!(key in out) || typeof out[key] === 'boolean') continue;
565
- out[key] = project(out[key], opts);
566
- }
567
- if (isRecord(out.additionalProperties)) out.additionalProperties = project(out.additionalProperties, opts);
568
- for (const key of SUBSCHEMA_LIST_KEYS) {
569
- const list = out[key];
570
- if (!Array.isArray(list)) continue;
571
- out[key] = list.map((child) => project(child, opts));
572
- }
573
-
574
- const props = isRecord(out.properties) ? out.properties : undefined;
575
- const looksLikeObject = out.type === 'object' || props !== undefined;
576
-
577
- if (looksLikeObject && opts.closeObjects && !('additionalProperties' in out)) {
578
- out.additionalProperties = false;
579
- }
580
-
581
- if (looksLikeObject && opts.requireEveryProperty && props) {
582
- const originallyRequired = Array.isArray(out.required) ? out.required.map(String) : [];
583
- const all = Object.keys(props);
584
- for (const name of all) {
585
- if (originallyRequired.includes(name)) continue;
586
- props[name] = widenWithNull(props[name]);
587
- }
588
- out.required = all;
589
- }
590
-
591
- return out;
592
- }
593
-
594
- /**
595
- * OpenAI's documented emulation of an optional field: keep it in `required` and let
596
- * its type admit `null`.
597
- *
598
- * The `enum` half matters. `{ type: ['string','null'], enum: ['a','b'] }` admits
599
- * nothing new, because the enum still excludes null, so the field would be required
600
- * AND unsatisfiable-as-absent. `null` therefore joins the enum too.
601
- *
602
- * A subschema with nothing to widen (no `type`, no `anyOf`) is returned untouched.
603
- * That is not a silent pass: `checkProviderSubset` reports it as an untyped
604
- * subschema, which is the real problem and a truer message than "could not widen".
605
- */
606
- function widenWithNull(sub: unknown): unknown {
607
- if (!isRecord(sub)) return sub;
608
- const out: Record<string, unknown> = { ...sub };
609
-
610
- if ('type' in out) {
611
- const declared = Array.isArray(out.type) ? out.type.map(String) : [String(out.type)];
612
- if (!declared.includes('null')) out.type = [...declared, 'null'];
613
- } else if (Array.isArray(out.anyOf)) {
614
- if (!out.anyOf.some((b) => isRecord(b) && b.type === 'null')) out.anyOf = [...out.anyOf, { type: 'null' }];
615
- } else {
616
- return out;
617
- }
618
-
619
- if (Array.isArray(out.enum) && !out.enum.includes(null)) out.enum = [...out.enum, null];
620
- return out;
621
- }
622
-
623
- // ---------------------------------------------------------------------------
624
- // cardTools
625
- // ---------------------------------------------------------------------------
626
-
627
- function normalizeSource(input: CardToolInput): {
628
- schemas: Readonly<Record<string, CardSchema>>;
629
- descriptions: Readonly<Record<string, string>>;
630
- } {
631
- // A `CardToolSource` is recognised by carrying a `schemas` map. A bare
632
- // `Record<type, CardSchema>` cannot collide with that unless someone names a card
633
- // type "schemas" AND its schema document is itself a map of schema documents,
634
- // which is not a shape the card contract can produce.
635
- const maybe = input as Partial<CardToolSource>;
636
- if (isRecord(maybe.schemas)) {
637
- return { schemas: maybe.schemas, descriptions: maybe.descriptions ?? {} };
638
- }
639
- return { schemas: input as Readonly<Record<string, CardSchema>>, descriptions: {} };
640
- }
641
-
642
- function describe(cardType: string, schema: CardSchema, overrides: Readonly<Record<string, string>>): string {
643
- const custom = overrides[cardType];
644
- if (typeof custom === 'string' && custom.length > 0) return custom;
645
- const builtIn = (CARD_TOOL_DESCRIPTIONS as Readonly<Record<string, string>>)[cardType];
646
- if (typeof builtIn === 'string' && builtIn.length > 0) return builtIn;
647
- // Last resort for a custom card type registered without a description. The schema's
648
- // own prose is worse guidance than a purpose sentence, but it beats an empty string,
649
- // and Phase 2's registry warns when a type arrives with neither.
650
- const own = schema.description;
651
- return typeof own === 'string' && own.length > 0 ? own : `Render a \`${cardType}\` card.`;
652
- }
653
-
654
- /**
655
- * Project the card schemas into tool definitions for one provider.
656
- *
657
- * ```ts
658
- * const tools = [...myTools, ...cardTools({ provider: 'openai' })];
659
- * const tools = cardTools(cards, { provider: 'anthropic' });
660
- * const tools = cardTools({ provider: 'jsonschema' }).map((t) =>
661
- * tool({ description: t.description, inputSchema: jsonSchema(t.schema) }));
662
- * ```
663
- *
664
- * @throws {UnsupportedCardToolSchemaError} with `strict: true`, naming every card,
665
- * path and keyword the provider cannot express. See the file header: today that is
666
- * every built-in card on both providers.
667
- */
668
- export function cardTools<P extends ToolProvider>(opts: CardToolOptions<P>): ToolDefFor<P>[];
669
- export function cardTools<P extends ToolProvider>(registry: CardToolInput, opts: CardToolOptions<P>): ToolDefFor<P>[];
670
- export function cardTools(a: CardToolInput | CardToolOptions, b?: CardToolOptions): ToolDef[] {
671
- // Single-argument form: `cardTools({ provider: 'openai' })` defaults the registry
672
- // to the built-ins, which is the shape the developer-facing docs lead with.
673
- const optionsOnly = b === undefined;
674
- const opts = (optionsOnly ? (a as CardToolOptions) : (b as CardToolOptions));
675
- if (!isRecord(opts) || typeof opts.provider !== 'string') {
676
- throw new TypeError('cardTools: an options object with a `provider` is required, e.g. cardTools({ provider: "openai" })');
677
- }
678
- const { schemas, descriptions } = normalizeSource(
679
- optionsOnly ? (builtInSchemas() as CardToolInput) : (a as CardToolInput),
680
- );
681
- const strict = opts.strict === true;
682
-
683
- if (opts.provider === 'jsonschema' && strict) {
684
- throw new TypeError(
685
- 'cardTools: `strict: true` is provider-specific and cannot be checked for `provider: "jsonschema"`, ' +
686
- 'because the two documented strict subsets differ (see @kitn.ai/ui/schemas provider-subsets). ' +
687
- 'Pass provider "openai" or "anthropic" to project and check strictly, or drop `strict`.',
688
- );
689
- }
690
-
691
- const subset: ProviderSubset | null = strict
692
- ? opts.provider === 'openai'
693
- ? OPENAI_STRICT
694
- : ANTHROPIC_STRICT
695
- : null;
696
-
697
- const projectOptions: ProjectOptions = {
698
- closeObjects: subset !== null,
699
- requireEveryProperty: subset !== null && subset.requireAllPropertiesRequired,
700
- };
701
-
702
- const defs: ToolDef[] = [];
703
- const failures: UnsupportedCardTool[] = [];
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
-
719
- for (const [cardType, schema] of Object.entries(schemas)) {
720
- const name = toolNameForCardType(cardType);
721
- const description = describe(cardType, schema, descriptions);
722
- const parameters = project(schema, projectOptions) as ToolParameters;
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
-
739
- if (subset) {
740
- const violations = checkProviderSubset(parameters, subset);
741
- if (violations.length > 0) {
742
- failures.push({ cardType, toolName: name, violations });
743
- continue;
744
- }
745
- }
746
-
747
- if (opts.provider === 'openai') {
748
- defs.push({ type: 'function', function: { name, description: wireDescription, parameters, ...(strict ? { strict: true as const } : {}) } });
749
- } else if (opts.provider === 'anthropic') {
750
- defs.push({ name, description: wireDescription, input_schema: parameters, ...(strict ? { strict: true as const } : {}) });
751
- } else {
752
- defs.push({ name, description, schema: parameters });
753
- }
754
- }
755
-
756
- if (subset && failures.length > 0) throw new UnsupportedCardToolSchemaError(subset, failures);
757
- return defs;
758
- }
759
-
760
- /**
761
- * The built-in map, read at CALL time.
762
- *
763
- * `./index` re-exports this module, and this module imports `cardSchemas` back out
764
- * of it, which is a genuine ESM import cycle. It is safe because the value is only
765
- * ever read inside a function body: by the time anyone calls `cardTools()`, both
766
- * module bodies have finished evaluating and the live binding is populated. Reading
767
- * it at TOP level here would be a temporal-dead-zone crash, so do not hoist it into
768
- * a `const`.
769
- */
770
- function builtInSchemas(): Readonly<Record<string, CardSchema>> {
771
- return cardSchemas;
772
- }
773
-
774
- /** `cardTools(registry, { provider: 'openai' })`, spelled out. */
775
- export function toOpenAITools(registry?: CardToolInput, opts?: { strict?: boolean }): OpenAIToolDef[] {
776
- return registry === undefined
777
- ? cardTools({ provider: 'openai', strict: opts?.strict })
778
- : cardTools(registry, { provider: 'openai', strict: opts?.strict });
779
- }
780
-
781
- /** `cardTools(registry, { provider: 'anthropic' })`, spelled out. */
782
- export function toAnthropicTools(registry?: CardToolInput, opts?: { strict?: boolean }): AnthropicToolDef[] {
783
- return registry === undefined
784
- ? cardTools({ provider: 'anthropic', strict: opts?.strict })
785
- : cardTools(registry, { provider: 'anthropic', strict: opts?.strict });
786
- }
787
-
788
- /** `cardTools(registry, { provider: 'jsonschema' })`, spelled out. */
789
- export function toJsonSchemaTools(registry?: CardToolInput): JsonSchemaToolDef[] {
790
- return registry === undefined
791
- ? cardTools({ provider: 'jsonschema' })
792
- : cardTools(registry, { provider: 'jsonschema' });
793
- }