@kitn.ai/ui 0.27.0 → 0.29.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 (612) hide show
  1. package/README.md +10 -2
  2. package/dist/{Icon-BnFKqqtY.js → Icon-DObhsRtm.js} +1 -1
  3. package/dist/{action-icons-CBskfBMz.js → action-icons-CcgNN2oT.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-CjRU3JgV.js +1 -0
  7. package/dist/arrow-left-Bnpb1UEW.js +1 -0
  8. package/dist/{artifact-CvXEm1lS.js → artifact-Bwt7OgcR.js} +1 -1
  9. package/dist/{attachments-C43ZegEq.js → attachments-Qr4kg-2b.js} +1 -1
  10. package/dist/{audio-visualizer-B-79y1Tj.js → audio-visualizer-DToYdfSc.js} +1 -1
  11. package/dist/{badge-BpUbq8c0.js → badge-CdEu_jn2.js} +1 -1
  12. package/dist/{bell-sn17Ip9v.js → bell-DQAAOpDz.js} +1 -1
  13. package/dist/{button-BH6rN0U-.js → button-DkuOnGLy.js} +1 -1
  14. package/dist/{card-renderer-Cb1gQmth.js → card-renderer-Jx70m6_l.js} +1 -1
  15. package/dist/{card-routing-DifQgS7n.js → card-routing-0YidER_3.js} +1 -1
  16. package/dist/check-njkVdZu2.js +1 -0
  17. package/dist/{checkbox-Dc9Yov_B.js → checkbox-D7iRB3nL.js} +1 -1
  18. package/dist/{checkbox-group-B1kDLLYk.js → checkbox-group-B2_rpoPM.js} +1 -1
  19. package/dist/chevron-down-B72s6PXR.js +1 -0
  20. package/dist/chevron-right-BatuHzUm.js +1 -0
  21. package/dist/{choice-card-BT3c1S8g.js → choice-card-m0BYqqOK.js} +1 -1
  22. package/dist/circle-check-B62pODB3.js +1 -0
  23. package/dist/{circle-x-wobWkoSx.js → circle-x-BPG0iPst.js} +1 -1
  24. package/dist/circle-zx0ByzY9.js +1 -0
  25. package/dist/code-block-ClMLKb7C.js +1 -0
  26. package/dist/{collapsible-CPJbf6FM.js → collapsible-B4DlWicL.js} +1 -1
  27. package/dist/components/chat-thread.d.ts +89 -1
  28. package/dist/components/conversation-item.d.ts +16 -0
  29. package/dist/components/conversation-panel.d.ts +29 -0
  30. package/dist/components/home-panel.d.ts +34 -0
  31. package/dist/components/widget-tab-bar.d.ts +16 -0
  32. package/dist/{composer-CjngLzal.js → composer-sQ0HcvyG.js} +3 -3
  33. package/dist/{confirm-card-DCx_A4bU.js → confirm-card-rQWDQsnC.js} +1 -1
  34. package/dist/construct-cli.es.js +185 -17
  35. package/dist/construct.d.ts +5 -0
  36. package/dist/construct.js +327 -0
  37. package/dist/{context-BY8V-Nlp.js → context-0kg4ZX1J.js} +1 -1
  38. package/dist/controllable-CnGpMF6r.js +1 -0
  39. package/dist/conversation-item-BxwQLaFJ.js +1 -0
  40. package/dist/conversation-list-BCfGN1JU.js +1 -0
  41. package/dist/{copy-B6DO4PqB.js → copy-n9u9rqpi.js} +1 -1
  42. package/dist/core-C8fzo39E.js +1 -12
  43. package/dist/{create-tween-CnMHviKB.js → create-tween-C-q-JCM-.js} +1 -1
  44. package/dist/{create-tween-D1aiGZZh.js → create-tween-CRrJXxBd.js} +1 -1
  45. package/dist/{create-tween-BPzaefTp.js → create-tween-DZ3RRDHD.js} +1 -1
  46. package/dist/{create-tween-DUSQUKpr.js → create-tween-uPkArjIG.js} +1 -1
  47. package/dist/custom-elements.json +51 -2
  48. package/dist/{default-input-CucQEOqH.js → default-input-CaMrJkgH.js} +1 -1
  49. package/dist/define-By-uL588.js +1 -0
  50. package/dist/define.js +2 -2
  51. package/dist/define.server.js +2 -2
  52. package/dist/{disclosure-CbLtajUQ.js → disclosure-WUImBbDv.js} +1 -1
  53. package/dist/{dropdown-BwhViJFd.js → dropdown-wZVeJOMd.js} +1 -1
  54. package/dist/elements/agent-card.js +1 -1
  55. package/dist/elements/artifact.js +1 -1
  56. package/dist/elements/attachments.js +1 -1
  57. package/dist/elements/audio-visualizer.js +1 -1
  58. package/dist/elements/avatar.js +1 -1
  59. package/dist/elements/badge.js +1 -1
  60. package/dist/elements/button.js +1 -1
  61. package/dist/elements/card.js +1 -1
  62. package/dist/elements/cards.js +1 -1
  63. package/dist/elements/chain-of-thought.js +1 -1
  64. package/dist/elements/chat-scope-picker.js +1 -1
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkbox-group.js +1 -1
  68. package/dist/elements/checkbox.js +1 -1
  69. package/dist/elements/checkpoint.js +1 -1
  70. package/dist/elements/choice.js +1 -1
  71. package/dist/elements/coachmark.js +1 -1
  72. package/dist/elements/code-block.js +1 -1
  73. package/dist/elements/command.js +1 -1
  74. package/dist/elements/compare.js +1 -1
  75. package/dist/elements/composer.js +1 -1
  76. package/dist/elements/confirm-card.js +1 -1
  77. package/dist/elements/context-meter.js +1 -1
  78. package/dist/elements/conversation-item.js +1 -1
  79. package/dist/elements/conversation-list.js +1 -1
  80. package/dist/elements/dialog.js +1 -1
  81. package/dist/elements/dock.js +3 -3
  82. package/dist/elements/dropdown.js +1 -1
  83. package/dist/elements/editable-label.js +1 -1
  84. package/dist/elements/embed.js +1 -1
  85. package/dist/elements/empty.js +1 -1
  86. package/dist/elements/feedback-bar.js +1 -1
  87. package/dist/elements/file-tree.js +1 -1
  88. package/dist/elements/file-upload.js +1 -1
  89. package/dist/elements/form.js +1 -1
  90. package/dist/elements/hover-card.js +1 -1
  91. package/dist/elements/icon.js +1 -1
  92. package/dist/elements/image.js +1 -1
  93. package/dist/elements/input.js +1 -1
  94. package/dist/elements/kbd.js +1 -1
  95. package/dist/elements/link-preview.js +1 -1
  96. package/dist/elements/loader.js +1 -1
  97. package/dist/elements/markdown.js +1 -1
  98. package/dist/elements/menu.js +1 -1
  99. package/dist/elements/message-skills.js +1 -1
  100. package/dist/elements/message.js +1 -1
  101. package/dist/elements/model-switcher.js +1 -1
  102. package/dist/elements/nav.js +1 -1
  103. package/dist/elements/notice.js +1 -1
  104. package/dist/elements/pane-grid.js +1 -1
  105. package/dist/elements/pane-group.js +1 -1
  106. package/dist/elements/pane.js +1 -1
  107. package/dist/elements/popover.js +1 -1
  108. package/dist/elements/progress-bar.js +1 -1
  109. package/dist/elements/prompt-dock.js +1 -1
  110. package/dist/elements/prompt-input.js +1 -1
  111. package/dist/elements/prompt-suggestions.js +1 -1
  112. package/dist/elements/radio-group.js +1 -1
  113. package/dist/elements/reasoning.js +1 -1
  114. package/dist/elements/remote.js +1 -1
  115. package/dist/elements/resizable.js +1 -1
  116. package/dist/elements/response-stream.js +1 -1
  117. package/dist/elements/screen.js +1 -1
  118. package/dist/elements/scroll-area.js +1 -1
  119. package/dist/elements/scroll-button.js +1 -1
  120. package/dist/elements/search.js +1 -1
  121. package/dist/elements/segmented.js +1 -1
  122. package/dist/elements/select.js +1 -1
  123. package/dist/elements/separator.js +1 -1
  124. package/dist/elements/setting-item.js +1 -1
  125. package/dist/elements/settings-group.js +1 -1
  126. package/dist/elements/skeleton.js +1 -1
  127. package/dist/elements/slider.js +1 -1
  128. package/dist/elements/source.js +1 -1
  129. package/dist/elements/status.js +1 -1
  130. package/dist/elements/switch.js +1 -1
  131. package/dist/elements/tabs.js +1 -1
  132. package/dist/elements/tasks.js +1 -1
  133. package/dist/elements/text-shimmer.js +1 -1
  134. package/dist/elements/thinking-bar.js +1 -1
  135. package/dist/elements/thread.js +1 -1
  136. package/dist/elements/toast.js +1 -1
  137. package/dist/elements/tool.js +1 -1
  138. package/dist/elements/tooltip.js +1 -1
  139. package/dist/elements/voice-input.js +1 -1
  140. package/dist/elements/voice-output.js +1 -1
  141. package/dist/elements.d.ts +20 -4
  142. package/dist/{ellipsis-DFr4Vqr3.js → ellipsis-CbOpJnU3.js} +1 -1
  143. package/dist/{embed-5s_vU4J0.js → embed-CrfjkbUG.js} +1 -1
  144. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  145. package/dist/{external-link-u9d85ORQ.js → external-link-ByXAwBBQ.js} +1 -1
  146. package/dist/{file-text-CX7_x42o.js → file-text-DMib2qwt.js} +1 -1
  147. package/dist/{file-tree-D3kBjXI5.js → file-tree-CJqM2aP7.js} +1 -1
  148. package/dist/{folder-V-YdIL8f.js → folder-_BAb929C.js} +1 -1
  149. package/dist/{form-BRNUMCN2.js → form-DSZgZQZk.js} +1 -1
  150. package/dist/{hover-card-DaeiYrTA.js → hover-card-BQbul9eq.js} +1 -1
  151. package/dist/{icon-BpixdZNq.js → icon-CdcfRhYI.js} +1 -1
  152. package/dist/index.d.ts +3 -1
  153. package/dist/index.js +2842 -2703
  154. package/dist/index.server.js +2820 -2681
  155. package/dist/{info-8mFsIjS3.js → info-DsFjGuI_.js} +1 -1
  156. package/dist/{input-d1Yuu-hz.js → input-DKbmkMos.js} +1 -1
  157. package/dist/kai.es.js +1 -1
  158. package/dist/{kbd-961zMPFB.js → kbd-PvdGhX4s.js} +1 -1
  159. package/dist/{link-preview-DIIbV2Sd.js → link-preview-DbM1866N.js} +1 -1
  160. package/dist/{link-DlZZBGaR.js → link-zF8PzWfF.js} +1 -1
  161. package/dist/{loader-YQszHFaW.js → loader-BM4CEz4G.js} +1 -1
  162. package/dist/{markdown-CVk1MPsj.js → markdown-LMvmAyBk.js} +7 -7
  163. package/dist/mcp.es.js +79 -5
  164. package/dist/{message-CwKVEdZg.js → message-BSsgvHvf.js} +1 -1
  165. package/dist/{message-DS8lzHc1.js → message-BYZECyek.js} +1 -1
  166. package/dist/message-circle-DruwObfX.js +1 -0
  167. package/dist/message-square-BG6q6mlm.js +1 -0
  168. package/dist/{minimize-2-UEZmP2QT.js → minimize-2-BQRoBV1V.js} +1 -1
  169. package/dist/{model-switcher-Kk1jEQ5t.js → model-switcher-CMpCOYcB.js} +1 -1
  170. package/dist/{overlay-C1od6LOz.js → overlay-Cb-MkyDa.js} +1 -1
  171. package/dist/{panel-right-ryET0yyn.js → panel-right-i8warFxT.js} +1 -1
  172. package/dist/{paperclip-BDNoZFJP.js → paperclip-ByY3UVO6.js} +1 -1
  173. package/dist/play-BvKKq3fX.js +1 -0
  174. package/dist/primitives/conversation-store.d.ts +54 -0
  175. package/dist/{progress-bar-BvYX0aoy.js → progress-bar-jVAHvMUf.js} +1 -1
  176. package/dist/{prompt-suggestion-BRFu2lcu.js → prompt-suggestion-CD-qtNgC.js} +1 -1
  177. package/dist/{radio-DcL23cNJ.js → radio-BsoBMhkF.js} +1 -1
  178. package/dist/react/index.d.ts +393 -0
  179. package/dist/react.js +20 -20
  180. package/dist/{reasoning-Cackq4Rh.js → reasoning-4kBPtlTx.js} +1 -1
  181. package/dist/register-impl-B1hLkrI8.js +424 -0
  182. package/dist/{resizable-Cp9HUYih.js → resizable-uPmY9VY-.js} +1 -1
  183. package/dist/{rotate-ccw-0DLRDHH5.js → rotate-ccw-B2xn93py.js} +1 -1
  184. package/dist/{rotate-cw-DOB9IGcU.js → rotate-cw-CMVLoCyH.js} +1 -1
  185. package/dist/{scroll-area-emVmWP4K.js → scroll-area-BqLUo8ZZ.js} +1 -1
  186. package/dist/{scroll-button-CeP_gv1x.js → scroll-button-DslXiJyL.js} +1 -1
  187. package/dist/{select-CWmu00tS.js → select-2cLRtPGT.js} +1 -1
  188. package/dist/{separator-CE6vly6z.js → separator-BWQtNJcM.js} +1 -1
  189. package/dist/{settings-CE-78SvZ.js → settings-BBR63jLg.js} +1 -1
  190. package/dist/{settings-group-ZFWNxFQR.js → settings-group-B2ciy-Iw.js} +1 -1
  191. package/dist/{skeleton-BebdP4mf.js → skeleton-CkHI-HgC.js} +1 -1
  192. package/dist/{slider-BAKRYUlz.js → slider-DDR9U-i0.js} +1 -1
  193. package/dist/{solid-BE5ui6sy.js → solid-BzCFdL25.js} +7720 -7058
  194. package/dist/{solid-DFhsce3O.js → solid-DruVOXnf.js} +5864 -5283
  195. package/dist/solid.d.ts +6 -2
  196. package/dist/solid.js +217 -210
  197. package/dist/solid.server.js +217 -210
  198. package/dist/{source-B0FlguSx.js → source-GEnFF528.js} +1 -1
  199. package/dist/{star-CBMZvLuN.js → star-CilHq8GP.js} +1 -1
  200. package/dist/store-Ciyk6eZG.js +1 -0
  201. package/dist/{switch-CViARZCy.js → switch-KkeQIbuH.js} +1 -1
  202. package/dist/{tasks-card-MjCcOhR_.js → tasks-card-BrN4bggJ.js} +1 -1
  203. package/dist/{text-shimmer-DKlwRF2G.js → text-shimmer-Dcj1MHuq.js} +1 -1
  204. package/dist/{textarea-3ay2Me2-.js → textarea-Dpvbngbg.js} +1 -1
  205. package/dist/theme.tokens.css +28 -0
  206. package/dist/{thumbs-up-DQcu2HMO.js → thumbs-up-CsT9Wzb9.js} +1 -1
  207. package/dist/{toast-store-C6yKOhbk.js → toast-store-tgK6MuMv.js} +1 -1
  208. package/dist/{tool-BCYNlfKy.js → tool-DzUjIBT8.js} +1 -1
  209. package/dist/{tooltip-05zI4hjs.js → tooltip-Bkkg_4t0.js} +1 -1
  210. package/dist/{trash-2-BR1RxGky.js → trash-2-jBKxjGGQ.js} +1 -1
  211. package/dist/{triangle-alert-DHohDOCy.js → triangle-alert-DlQ68ppf.js} +1 -1
  212. package/dist/types.d.ts +48 -3
  213. package/dist/ui/dock.d.ts +29 -0
  214. package/dist/{upload-BbGW6A_u.js → upload-TcAHXv9W.js} +1 -1
  215. package/dist/{url-scheme-policy-DHpoTJwB.js → url-scheme-policy-DR5DgvkM.js} +1 -1
  216. package/dist/{use-card-resolution-CJW4grFa.js → use-card-resolution-DaZqAdWf.js} +1 -1
  217. package/dist/{variant-aurora-xiMPty8f.js → variant-aurora-BhLuYxJR.js} +1 -1
  218. package/dist/{variant-aurora-BUOVgPOB.js → variant-aurora-CNmfHhcx.js} +2 -2
  219. package/dist/{variant-aurora-CUsUJvFI.js → variant-aurora-D6GsdTPA.js} +2 -2
  220. package/dist/{variant-aurora-CW2i4bfr.js → variant-aurora-DbW_OWL2.js} +1 -1
  221. package/dist/{variant-custom-D91HjAKz.js → variant-custom-BRvaNHSi.js} +1 -1
  222. package/dist/{variant-custom-BQtOnmeO.js → variant-custom-BvYHR62b.js} +1 -1
  223. package/dist/{variant-custom-CAnzzppW.js → variant-custom-DMTrEO5w.js} +2 -2
  224. package/dist/{variant-custom-CAm9L-E5.js → variant-custom-DV2x254s.js} +2 -2
  225. package/dist/{variant-wave-Ca1Ls4_y.js → variant-wave-BNMGrDfj.js} +2 -2
  226. package/dist/{variant-wave-uY5crU_K.js → variant-wave-BpDd8t3Z.js} +1 -1
  227. package/dist/{variant-wave-CxX39DKd.js → variant-wave-CyBueXj9.js} +2 -2
  228. package/dist/{variant-wave-DYyzIIZv.js → variant-wave-sp-qwsdI.js} +1 -1
  229. package/dist/x-Z5UntkIJ.js +1 -0
  230. package/frameworks/react/index.tsx +14 -4
  231. package/llms-full.txt +7 -2
  232. package/package.json +16 -16
  233. package/src/elements/element-meta.json +49 -6
  234. package/theme.css +28 -0
  235. package/bin/route.test.js +0 -58
  236. package/dist/arrow-down-Br0qtpsz.js +0 -1
  237. package/dist/arrow-left-Dj7xgE12.js +0 -1
  238. package/dist/check-DPeeMUYx.js +0 -1
  239. package/dist/chevron-down-CHSWk7ZT.js +0 -1
  240. package/dist/chevron-right-B7l_fMgx.js +0 -1
  241. package/dist/circle-Bb0yOpqM.js +0 -1
  242. package/dist/circle-check-BGZpCiz7.js +0 -1
  243. package/dist/code-block-CUQ5mtv0.js +0 -1
  244. package/dist/controllable-D43BKmtX.js +0 -1
  245. package/dist/conversation-list-D4lLU_yS.js +0 -1
  246. package/dist/define-CGGX-7Vg.js +0 -1
  247. package/dist/message-circle-Xf8Q-vZp.js +0 -1
  248. package/dist/message-square-Cxnwgkns.js +0 -1
  249. package/dist/play-OFIvYXUQ.js +0 -1
  250. package/dist/register-impl-C7rENvPK.js +0 -424
  251. package/dist/store-7eoadydQ.js +0 -1
  252. package/dist/x-C5m1JFgi.js +0 -1
  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 -131
  263. package/src/agent-tooling/construct/codegen.ts +0 -1353
  264. package/src/agent-tooling/construct/construct.v1.schema.json +0 -250
  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 -23
  269. package/src/agent-tooling/construct/schema.ts +0 -371
  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 -518
  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 -218
  336. package/src/components/conversation-list.tsx +0 -429
  337. package/src/components/dismissed-stub.tsx +0 -80
  338. package/src/components/embed.tsx +0 -200
  339. package/src/components/empty.tsx +0 -177
  340. package/src/components/feedback-bar.tsx +0 -166
  341. package/src/components/file-tree.tsx +0 -530
  342. package/src/components/file-upload.tsx +0 -167
  343. package/src/components/form-widgets.tsx +0 -525
  344. package/src/components/form.tsx +0 -1296
  345. package/src/components/image.tsx +0 -65
  346. package/src/components/link-preview.tsx +0 -195
  347. package/src/components/loader.tsx +0 -367
  348. package/src/components/markdown.tsx +0 -162
  349. package/src/components/message-skills.tsx +0 -40
  350. package/src/components/message.tsx +0 -765
  351. package/src/components/model-switcher.tsx +0 -132
  352. package/src/components/prompt-input.tsx +0 -188
  353. package/src/components/prompt-suggestion.tsx +0 -150
  354. package/src/components/reasoning.tsx +0 -293
  355. package/src/components/response-compare-types.ts +0 -152
  356. package/src/components/response-compare.tsx +0 -455
  357. package/src/components/response-stream.tsx +0 -109
  358. package/src/components/screen.tsx +0 -181
  359. package/src/components/scroll-button.tsx +0 -93
  360. package/src/components/source.tsx +0 -192
  361. package/src/components/tasks-card.tsx +0 -801
  362. package/src/components/text-shimmer.tsx +0 -37
  363. package/src/components/thinking-bar.tsx +0 -50
  364. package/src/components/thread.tsx +0 -228
  365. package/src/components/toast.tsx +0 -503
  366. package/src/components/tool-classify.ts +0 -26
  367. package/src/components/tool-types.ts +0 -49
  368. package/src/components/tool.tsx +0 -190
  369. package/src/components/use-card-resolution.ts +0 -44
  370. package/src/components/voice-input.tsx +0 -222
  371. package/src/components/voice-output.tsx +0 -242
  372. package/src/components/workspace-shell.tsx +0 -285
  373. package/src/diagnostics/hook.ts +0 -352
  374. package/src/diagnostics/index.ts +0 -82
  375. package/src/diagnostics/report-request.ts +0 -296
  376. package/src/elements/agent-card.tsx +0 -67
  377. package/src/elements/artifact.tsx +0 -194
  378. package/src/elements/attachments.tsx +0 -140
  379. package/src/elements/audio-visualizer.tsx +0 -227
  380. package/src/elements/autoloader.ts +0 -89
  381. package/src/elements/avatar.tsx +0 -33
  382. package/src/elements/badge.tsx +0 -32
  383. package/src/elements/button.tsx +0 -149
  384. package/src/elements/card.tsx +0 -133
  385. package/src/elements/cards.tsx +0 -266
  386. package/src/elements/chain-of-thought.tsx +0 -141
  387. package/src/elements/chat-scope-picker.tsx +0 -65
  388. package/src/elements/chat-types.ts +0 -102
  389. package/src/elements/chat-workspace.tsx +0 -188
  390. package/src/elements/chat.tsx +0 -212
  391. package/src/elements/checkbox-group.tsx +0 -164
  392. package/src/elements/checkbox.tsx +0 -134
  393. package/src/elements/checkpoint.tsx +0 -47
  394. package/src/elements/choice.tsx +0 -100
  395. package/src/elements/coachmark.tsx +0 -90
  396. package/src/elements/code-block.tsx +0 -60
  397. package/src/elements/command.tsx +0 -197
  398. package/src/elements/compare.tsx +0 -111
  399. package/src/elements/compiled.css +0 -2
  400. package/src/elements/composer.tsx +0 -162
  401. package/src/elements/confirm-card.tsx +0 -76
  402. package/src/elements/context-meter.tsx +0 -107
  403. package/src/elements/conversation-item.tsx +0 -120
  404. package/src/elements/conversation-list.tsx +0 -203
  405. package/src/elements/css.ts +0 -5
  406. package/src/elements/default-input.tsx +0 -392
  407. package/src/elements/define-entry.ts +0 -12
  408. package/src/elements/define.tsx +0 -563
  409. package/src/elements/diagnostic-events.ts +0 -114
  410. package/src/elements/dialog.tsx +0 -145
  411. package/src/elements/disclosure.ts +0 -95
  412. package/src/elements/dock.tsx +0 -215
  413. package/src/elements/dropdown.tsx +0 -123
  414. package/src/elements/editable-label.tsx +0 -140
  415. package/src/elements/element-data-types.ts +0 -152
  416. package/src/elements/element-diagnostics.ts +0 -392
  417. package/src/elements/element-manifest.json +0 -354
  418. package/src/elements/element-nonscalar.json +0 -185
  419. package/src/elements/element-types.d.ts +0 -4337
  420. package/src/elements/embed.tsx +0 -35
  421. package/src/elements/empty.tsx +0 -29
  422. package/src/elements/feedback-bar.tsx +0 -66
  423. package/src/elements/file-tree.tsx +0 -62
  424. package/src/elements/file-upload.tsx +0 -44
  425. package/src/elements/form.tsx +0 -94
  426. package/src/elements/hover-card.tsx +0 -80
  427. package/src/elements/icon.tsx +0 -41
  428. package/src/elements/image.tsx +0 -32
  429. package/src/elements/input.tsx +0 -492
  430. package/src/elements/kbd.tsx +0 -45
  431. package/src/elements/link-preview.tsx +0 -34
  432. package/src/elements/loader.tsx +0 -25
  433. package/src/elements/markdown.tsx +0 -38
  434. package/src/elements/menu.tsx +0 -241
  435. package/src/elements/message-skills.tsx +0 -83
  436. package/src/elements/message.tsx +0 -361
  437. package/src/elements/model-switcher.tsx +0 -121
  438. package/src/elements/nav.tsx +0 -87
  439. package/src/elements/notice.tsx +0 -53
  440. package/src/elements/pane-grid.tsx +0 -111
  441. package/src/elements/pane-group.tsx +0 -119
  442. package/src/elements/pane.tsx +0 -129
  443. package/src/elements/popover.tsx +0 -81
  444. package/src/elements/progress-bar.tsx +0 -39
  445. package/src/elements/prompt-dock.tsx +0 -82
  446. package/src/elements/prompt-input.tsx +0 -240
  447. package/src/elements/prompt-suggestions.tsx +0 -113
  448. package/src/elements/radio-group.tsx +0 -129
  449. package/src/elements/reasoning.tsx +0 -71
  450. package/src/elements/register-impl.ts +0 -148
  451. package/src/elements/register.ts +0 -76
  452. package/src/elements/remote.tsx +0 -225
  453. package/src/elements/resizable.globals.d.ts +0 -36
  454. package/src/elements/resizable.tsx +0 -704
  455. package/src/elements/response-stream.tsx +0 -40
  456. package/src/elements/screen.tsx +0 -90
  457. package/src/elements/scroll-area.tsx +0 -33
  458. package/src/elements/scroll-button.tsx +0 -179
  459. package/src/elements/search.tsx +0 -185
  460. package/src/elements/segmented.tsx +0 -129
  461. package/src/elements/select.tsx +0 -165
  462. package/src/elements/separator.tsx +0 -36
  463. package/src/elements/setting-item.tsx +0 -50
  464. package/src/elements/settings-group.tsx +0 -37
  465. package/src/elements/skeleton.tsx +0 -45
  466. package/src/elements/slider.tsx +0 -171
  467. package/src/elements/slot-text.ts +0 -73
  468. package/src/elements/slots.ts +0 -787
  469. package/src/elements/source.tsx +0 -126
  470. package/src/elements/status.tsx +0 -42
  471. package/src/elements/styles.css +0 -328
  472. package/src/elements/switch.tsx +0 -118
  473. package/src/elements/tabs.tsx +0 -95
  474. package/src/elements/tasks.tsx +0 -103
  475. package/src/elements/text-shimmer.tsx +0 -28
  476. package/src/elements/thinking-bar.tsx +0 -43
  477. package/src/elements/thread.tsx +0 -139
  478. package/src/elements/toast.tsx +0 -106
  479. package/src/elements/tool.tsx +0 -78
  480. package/src/elements/tooltip.tsx +0 -85
  481. package/src/elements/validate-messages.ts +0 -76
  482. package/src/elements/voice-input.tsx +0 -100
  483. package/src/elements/voice-output.tsx +0 -82
  484. package/src/index.ts +0 -428
  485. package/src/primitives/audio-bands.ts +0 -174
  486. package/src/primitives/card-component-types.ts +0 -63
  487. package/src/primitives/card-contract.ts +0 -80
  488. package/src/primitives/card-data-types.ts +0 -361
  489. package/src/primitives/card-host.tsx +0 -37
  490. package/src/primitives/card-recovery.ts +0 -160
  491. package/src/primitives/card-registry.tsx +0 -78
  492. package/src/primitives/card-resolution.ts +0 -36
  493. package/src/primitives/card-routing.ts +0 -85
  494. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  495. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  496. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  497. package/src/primitives/card-schemas/choice.schema.json +0 -75
  498. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  499. package/src/primitives/card-schemas/embed.schema.json +0 -63
  500. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  501. package/src/primitives/card-schemas/form.schema.json +0 -53
  502. package/src/primitives/card-schemas/link.schema.json +0 -54
  503. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  504. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  505. package/src/primitives/card-tags.ts +0 -61
  506. package/src/primitives/card-validate-cards.ts +0 -255
  507. package/src/primitives/card-validate-schemas.ts +0 -58
  508. package/src/primitives/card-validate.ts +0 -131
  509. package/src/primitives/chat-config.tsx +0 -103
  510. package/src/primitives/composer-model.ts +0 -49
  511. package/src/primitives/composer-triggers.ts +0 -35
  512. package/src/primitives/controllable.ts +0 -21
  513. package/src/primitives/create-kai-chat.ts +0 -66
  514. package/src/primitives/create-tween.ts +0 -266
  515. package/src/primitives/embed-providers.ts +0 -254
  516. package/src/primitives/field-mask.ts +0 -256
  517. package/src/primitives/field-semantics.ts +0 -115
  518. package/src/primitives/highlighter.ts +0 -157
  519. package/src/primitives/input-mask.ts +0 -853
  520. package/src/primitives/link-preview.ts +0 -87
  521. package/src/primitives/message-feedback.ts +0 -124
  522. package/src/primitives/pdf-preview.ts +0 -121
  523. package/src/primitives/toast-store.ts +0 -338
  524. package/src/primitives/url-scheme-policy.ts +0 -70
  525. package/src/primitives/use-audio-analysis.ts +0 -340
  526. package/src/primitives/use-auto-resize.ts +0 -31
  527. package/src/primitives/use-resize-observer.ts +0 -45
  528. package/src/primitives/use-sequencer.ts +0 -72
  529. package/src/primitives/use-speech-recognition.ts +0 -146
  530. package/src/primitives/use-stick-to-bottom.ts +0 -75
  531. package/src/primitives/use-text-stream.ts +0 -143
  532. package/src/primitives/use-voice-recorder.ts +0 -62
  533. package/src/primitives/visualizer-sequences.ts +0 -350
  534. package/src/remote/host-embed.ts +0 -345
  535. package/src/remote/index.ts +0 -2
  536. package/src/remote/origin.ts +0 -30
  537. package/src/remote/provider-runtime.ts +0 -262
  538. package/src/remote/provider.ts +0 -2
  539. package/src/remote/validate.ts +0 -22
  540. package/src/remote/version.ts +0 -12
  541. package/src/remote/wire.ts +0 -48
  542. package/src/schemas/from-tool-call.ts +0 -151
  543. package/src/schemas/index.ts +0 -341
  544. package/src/schemas/provider-subsets.ts +0 -538
  545. package/src/schemas/registry.ts +0 -355
  546. package/src/schemas/tool-defs.ts +0 -793
  547. package/src/solid.ts +0 -165
  548. package/src/state/index.ts +0 -44
  549. package/src/state/messages.ts +0 -53
  550. package/src/state/mock.ts +0 -297
  551. package/src/state/parts.ts +0 -295
  552. package/src/state/persistence.ts +0 -180
  553. package/src/state/stream.ts +0 -246
  554. package/src/state/suggestions.ts +0 -9
  555. package/src/state/threads.ts +0 -142
  556. package/src/test-utils/fake-clock.ts +0 -88
  557. package/src/types.ts +0 -53
  558. package/src/ui/action-icons.ts +0 -53
  559. package/src/ui/agent-card.tsx +0 -218
  560. package/src/ui/avatar.tsx +0 -23
  561. package/src/ui/badge.tsx +0 -21
  562. package/src/ui/button.tsx +0 -49
  563. package/src/ui/card.tsx +0 -245
  564. package/src/ui/checkbox-group.tsx +0 -153
  565. package/src/ui/checkbox.tsx +0 -63
  566. package/src/ui/collapsible.tsx +0 -163
  567. package/src/ui/command.tsx +0 -103
  568. package/src/ui/dialog.tsx +0 -223
  569. package/src/ui/dock.tsx +0 -584
  570. package/src/ui/dropdown.tsx +0 -636
  571. package/src/ui/editable-label.tsx +0 -112
  572. package/src/ui/hover-card.tsx +0 -345
  573. package/src/ui/icon.tsx +0 -167
  574. package/src/ui/input.tsx +0 -391
  575. package/src/ui/kbd.tsx +0 -118
  576. package/src/ui/nav.tsx +0 -282
  577. package/src/ui/notice.tsx +0 -84
  578. package/src/ui/overlay.tsx +0 -277
  579. package/src/ui/pane-grid.tsx +0 -117
  580. package/src/ui/pane-group.tsx +0 -291
  581. package/src/ui/pane.tsx +0 -193
  582. package/src/ui/popover.tsx +0 -106
  583. package/src/ui/progress-bar.tsx +0 -83
  584. package/src/ui/prompt-dock.tsx +0 -145
  585. package/src/ui/radio.tsx +0 -150
  586. package/src/ui/resizable.tsx +0 -693
  587. package/src/ui/scroll-area.tsx +0 -26
  588. package/src/ui/segmented.tsx +0 -109
  589. package/src/ui/select.tsx +0 -168
  590. package/src/ui/separator.tsx +0 -10
  591. package/src/ui/settings-group.tsx +0 -67
  592. package/src/ui/skeleton.tsx +0 -73
  593. package/src/ui/slider.tsx +0 -178
  594. package/src/ui/status.tsx +0 -48
  595. package/src/ui/switch.tsx +0 -119
  596. package/src/ui/tabs.tsx +0 -168
  597. package/src/ui/textarea.tsx +0 -21
  598. package/src/ui/tooltip.tsx +0 -118
  599. package/src/utils/cn.ts +0 -30
  600. package/src/wire/chunk.ts +0 -248
  601. package/src/wire/consume.ts +0 -599
  602. package/src/wire/diagnostics.ts +0 -727
  603. package/src/wire/encode-probe.ts +0 -214
  604. package/src/wire/encode.ts +0 -947
  605. package/src/wire/files.ts +0 -342
  606. package/src/wire/formats/anthropic.ts +0 -274
  607. package/src/wire/formats/openai.ts +0 -228
  608. package/src/wire/index.ts +0 -95
  609. package/src/wire/media-types.ts +0 -344
  610. package/src/wire/read.ts +0 -396
  611. package/src/wire/sink-helpers.ts +0 -50
  612. 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
- }