@kitn.ai/ui 0.20.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/README.md +44 -45
  2. package/dist/components/artifact-card.d.ts +51 -0
  3. package/dist/components/artifact.d.ts +1 -1
  4. package/dist/components/attachments.d.ts +2 -2
  5. package/dist/components/audio-visualizer/index.d.ts +3 -3
  6. package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
  7. package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
  8. package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
  9. package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
  10. package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
  11. package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
  12. package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
  13. package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
  14. package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
  15. package/dist/components/card-fallback.d.ts +12 -2
  16. package/dist/components/card-renderer.d.ts +63 -2
  17. package/dist/components/chat-container.d.ts +3 -0
  18. package/dist/components/chat-scope-picker.d.ts +2 -2
  19. package/dist/components/chat-thread.d.ts +77 -18
  20. package/dist/components/choice-card.d.ts +3 -28
  21. package/dist/components/composer-dom.d.ts +1 -1
  22. package/dist/components/composer-highlight.d.ts +1 -1
  23. package/dist/components/composer-history.d.ts +1 -1
  24. package/dist/components/composer.d.ts +1 -1
  25. package/dist/components/confirm-card.d.ts +3 -18
  26. package/dist/components/context.d.ts +8 -4
  27. package/dist/components/conversation-item.d.ts +1 -1
  28. package/dist/components/conversation-list.d.ts +4 -3
  29. package/dist/components/embed.d.ts +3 -3
  30. package/dist/components/file-tree.d.ts +11 -22
  31. package/dist/components/form-widgets.d.ts +1 -1
  32. package/dist/components/form.d.ts +3 -44
  33. package/dist/components/link-preview.d.ts +3 -3
  34. package/dist/components/loader.d.ts +30 -48
  35. package/dist/components/message-skills.d.ts +4 -0
  36. package/dist/components/message.d.ts +84 -21
  37. package/dist/components/model-switcher.d.ts +2 -2
  38. package/dist/components/prompt-input.d.ts +2 -2
  39. package/dist/components/response-compare-types.d.ts +11 -2
  40. package/dist/components/response-compare.d.ts +3 -3
  41. package/dist/components/source.d.ts +12 -3
  42. package/dist/components/tasks-card.d.ts +3 -31
  43. package/dist/components/thread.d.ts +17 -5
  44. package/dist/components/toast.d.ts +2 -2
  45. package/dist/components/tool-classify.d.ts +8 -0
  46. package/dist/components/tool-types.d.ts +29 -1
  47. package/dist/components/tool.d.ts +3 -3
  48. package/dist/components/use-card-resolution.d.ts +1 -1
  49. package/dist/create-tween-COnPwAQN.js +338 -0
  50. package/dist/create-tween-DmTUaXWE.js +341 -0
  51. package/dist/create-tween-qs-jjvNA.js +7 -0
  52. package/dist/custom-elements.json +1726 -463
  53. package/dist/elements/agent-card.js +1 -1
  54. package/dist/elements/artifact.js +1 -1
  55. package/dist/elements/attachments.js +1 -1
  56. package/dist/elements/audio-visualizer.js +1 -1
  57. package/dist/elements/avatar.js +1 -1
  58. package/dist/elements/badge.js +1 -1
  59. package/dist/elements/button.js +1 -1
  60. package/dist/elements/card.js +1 -1
  61. package/dist/elements/cards.js +1 -1
  62. package/dist/elements/chain-of-thought.js +1 -1
  63. package/dist/elements/chat-scope-picker.js +1 -1
  64. package/dist/elements/chat-types.d.ts +70 -10
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkpoint.js +1 -1
  68. package/dist/elements/choice.js +1 -1
  69. package/dist/elements/chunks/{Icon-Tj58ES_d.js → Icon-CHG5z5L7.js} +1 -1
  70. package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-BAtCEEgg.js} +1 -1
  71. package/dist/elements/chunks/arrow-left-CFPTeL1Y.js +1 -0
  72. package/dist/elements/chunks/artifact-fBZOE4SO.js +1 -0
  73. package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-DpYMe5VQ.js} +1 -1
  74. package/dist/elements/chunks/audio-visualizer-DFwzAcuL.js +1 -0
  75. package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-D6zodm6E.js} +1 -1
  76. package/dist/elements/chunks/{button-ZWNif3--.js → button-C42vrGvO.js} +1 -1
  77. package/dist/elements/chunks/card-renderer-DMZsSuvU.js +1 -0
  78. package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
  79. package/dist/elements/chunks/chat-thread-CNNEhol-.js +1 -0
  80. package/dist/elements/chunks/check-7Q3K-iXE.js +1 -0
  81. package/dist/elements/chunks/chevron-down-CpNYLn7E.js +1 -0
  82. package/dist/elements/chunks/chevron-right-DrH85Fha.js +1 -0
  83. package/dist/elements/chunks/choice-card-YoWjpsFV.js +1 -0
  84. package/dist/elements/chunks/circle-C9KRjKYv.js +1 -0
  85. package/dist/elements/chunks/circle-check-Dmi7Y4zw.js +1 -0
  86. package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-QIxXda6k.js} +1 -1
  87. package/dist/elements/chunks/code-block-CqeugReY.js +1 -0
  88. package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-sTv-_5lF.js} +1 -1
  89. package/dist/elements/chunks/{composer-BguS0QL_.js → composer-ldQyeVEB.js} +2 -2
  90. package/dist/elements/chunks/confirm-card-C0RNOwfn.js +1 -0
  91. package/dist/elements/chunks/context-5qgypNHC.js +1 -0
  92. package/dist/elements/chunks/conversation-list-DLzOacXz.js +1 -0
  93. package/dist/elements/chunks/create-tween-V4TXZ93X.js +7 -0
  94. package/dist/elements/chunks/default-input-DeeRSDHc.js +1 -0
  95. package/dist/elements/chunks/define-lE-QvQFn.js +1 -0
  96. package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DZSa9jog.js} +1 -1
  97. package/dist/elements/chunks/{download-Dsbg3ste.js → download-B2ZmnGqW.js} +1 -1
  98. package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-R3B7cSRE.js} +1 -1
  99. package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BmxceY4l.js} +1 -1
  100. package/dist/elements/chunks/embed-BVrtTZPo.js +1 -0
  101. package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-BbdR7YO7.js} +1 -1
  102. package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-D7dijo1A.js} +1 -1
  103. package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-0upJ5jeb.js} +1 -1
  104. package/dist/elements/chunks/{folder-glP5rha4.js → folder-D8z58t7B.js} +1 -1
  105. package/dist/elements/chunks/form-p5BKJNw5.js +1 -0
  106. package/dist/elements/chunks/hover-card-CN9s2md5.js +1 -0
  107. package/dist/elements/chunks/{icon-BLb8beoi.js → icon-CNiKP37E.js} +1 -1
  108. package/dist/elements/chunks/{info-CIsv92JK.js → info-BSnuJiHI.js} +1 -1
  109. package/dist/elements/chunks/{input-Dds1kFyt.js → input-BauDmzxX.js} +1 -1
  110. package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-BlHJaP9b.js} +1 -1
  111. package/dist/elements/chunks/{link-i4r_k7z4.js → link-DEi5iUWC.js} +1 -1
  112. package/dist/elements/chunks/link-preview-BaHyM6W4.js +1 -0
  113. package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-CmJG_Fkq.js} +1 -1
  114. package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-D2jaMpCN.js} +1 -1
  115. package/dist/elements/chunks/message-C5UfXZ2Z.js +1 -0
  116. package/dist/elements/chunks/message-CXWLmmLn.js +1 -0
  117. package/dist/elements/chunks/message-square-hXylwsy0.js +1 -0
  118. package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-C9ytZFMU.js} +1 -1
  119. package/dist/elements/chunks/model-switcher-CivGfD7-.js +1 -0
  120. package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-DJL_sbOm.js} +1 -1
  121. package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CFaB8naM.js} +1 -1
  122. package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-Br5SksfR.js} +1 -1
  123. package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-CMIvtAhU.js} +1 -1
  124. package/dist/elements/chunks/reasoning-DpZcNzLq.js +1 -0
  125. package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-Q8i3T9a_.js} +1 -1
  126. package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-B5IHCBFV.js} +1 -1
  127. package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-eLeydBje.js} +1 -1
  128. package/dist/elements/chunks/scroll-button-DWbz0yA1.js +1 -0
  129. package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-Xic78AD_.js} +1 -1
  130. package/dist/elements/chunks/{settings-B8lmec4D.js → settings-B8H51pAx.js} +1 -1
  131. package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-CsG9eYLe.js} +1 -1
  132. package/dist/elements/chunks/{share-C3lTiYGt.js → share-CNTx0z__.js} +1 -1
  133. package/dist/elements/chunks/skeleton-CLlHTcMI.js +1 -0
  134. package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
  135. package/dist/elements/chunks/source-BoVcU5ok.js +1 -0
  136. package/dist/elements/chunks/{star-CSJtGxgv.js → star-CxQVTVhI.js} +1 -1
  137. package/dist/elements/chunks/{store-CHyW95TP.js → store-CLtS5CUG.js} +1 -1
  138. package/dist/elements/chunks/tasks-card-CzlkLmUt.js +1 -0
  139. package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D5NhpIQ1.js} +1 -1
  140. package/dist/elements/chunks/textarea-x5Uxsmtm.js +1 -0
  141. package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-UobcJnx9.js} +1 -1
  142. package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-BOfs9eXq.js} +1 -1
  143. package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-Be6Dh_dt.js} +1 -1
  144. package/dist/elements/chunks/tooltip-RxMxyCLF.js +1 -0
  145. package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C4yxH2XN.js} +1 -1
  146. package/dist/elements/chunks/use-card-resolution-jva9ehH6.js +1 -0
  147. package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Dx4VRcjS.js} +2 -2
  148. package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-Y1ZTWgEa.js} +1 -1
  149. package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-B9gml9Cg.js} +2 -2
  150. package/dist/elements/chunks/{video-B7vmenoC.js → video-CrPHsytT.js} +1 -1
  151. package/dist/elements/chunks/x-_-OPHept.js +1 -0
  152. package/dist/elements/coachmark.js +1 -1
  153. package/dist/elements/code-block.js +1 -1
  154. package/dist/elements/command.js +1 -1
  155. package/dist/elements/compare.js +1 -1
  156. package/dist/elements/composer.js +1 -1
  157. package/dist/elements/confirm-card.js +1 -1
  158. package/dist/elements/context-meter.js +1 -1
  159. package/dist/elements/conversation-list.js +1 -1
  160. package/dist/elements/default-input.d.ts +34 -7
  161. package/dist/elements/define.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -1
  163. package/dist/elements/disclosure.d.ts +1 -1
  164. package/dist/elements/editable-label.js +1 -1
  165. package/dist/elements/element-data-types.d.ts +107 -0
  166. package/dist/elements/embed.js +1 -1
  167. package/dist/elements/empty.js +1 -1
  168. package/dist/elements/feedback-bar.js +1 -1
  169. package/dist/elements/file-tree.js +1 -1
  170. package/dist/elements/file-upload.js +1 -1
  171. package/dist/elements/form.js +1 -1
  172. package/dist/elements/hover-card.js +1 -1
  173. package/dist/elements/icon.js +1 -1
  174. package/dist/elements/image.js +1 -1
  175. package/dist/elements/input.js +1 -1
  176. package/dist/elements/kbd.js +1 -1
  177. package/dist/elements/link-preview.js +1 -1
  178. package/dist/elements/loader.js +1 -1
  179. package/dist/elements/markdown.js +1 -1
  180. package/dist/elements/menu.js +1 -1
  181. package/dist/elements/message-skills.js +1 -1
  182. package/dist/elements/message.js +1 -1
  183. package/dist/elements/model-switcher.js +1 -1
  184. package/dist/elements/nav.js +1 -1
  185. package/dist/elements/notice.js +1 -1
  186. package/dist/elements/pane-group.js +1 -1
  187. package/dist/elements/pane.js +1 -1
  188. package/dist/elements/popover.js +1 -1
  189. package/dist/elements/progress-bar.js +1 -1
  190. package/dist/elements/prompt-dock.js +1 -1
  191. package/dist/elements/prompt-input.js +1 -1
  192. package/dist/elements/prompt-suggestions.js +1 -1
  193. package/dist/elements/reasoning.js +1 -1
  194. package/dist/elements/register.d.ts +8 -6
  195. package/dist/elements/remote.js +1 -1
  196. package/dist/elements/resizable.js +1 -1
  197. package/dist/elements/response-stream.js +1 -1
  198. package/dist/elements/screen.js +1 -1
  199. package/dist/elements/scroll-area.js +1 -1
  200. package/dist/elements/scroll-button.js +1 -1
  201. package/dist/elements/search.js +1 -1
  202. package/dist/elements/segmented.js +1 -1
  203. package/dist/elements/separator.js +1 -1
  204. package/dist/elements/setting-item.js +1 -1
  205. package/dist/elements/settings-group.js +1 -1
  206. package/dist/elements/skeleton.js +1 -1
  207. package/dist/elements/slot-text.d.ts +51 -0
  208. package/dist/elements/slots.d.ts +21 -0
  209. package/dist/elements/source.js +1 -1
  210. package/dist/elements/status.js +1 -1
  211. package/dist/elements/switch.js +1 -1
  212. package/dist/elements/tabs.js +1 -1
  213. package/dist/elements/tasks.js +1 -1
  214. package/dist/elements/text-shimmer.js +1 -1
  215. package/dist/elements/thinking-bar.js +1 -1
  216. package/dist/elements/thread.js +1 -1
  217. package/dist/elements/toast.js +1 -1
  218. package/dist/elements/tool.js +1 -1
  219. package/dist/elements/tooltip.js +1 -1
  220. package/dist/elements/validate-messages.d.ts +25 -0
  221. package/dist/elements/voice-input.js +1 -1
  222. package/dist/elements/voice-output.js +1 -1
  223. package/dist/elements.d.ts +2734 -217
  224. package/dist/index.d.ts +163 -125
  225. package/dist/index.js +6572 -5990
  226. package/dist/index.server.d.ts +5 -0
  227. package/dist/index.server.js +5403 -4860
  228. package/dist/kai-provider.es.d.ts +5 -0
  229. package/dist/kai-provider.es.js +79 -77
  230. package/dist/kai.es.d.ts +5 -0
  231. package/dist/kai.es.js +1 -1
  232. package/dist/llms/llms-full.txt +774 -151
  233. package/dist/llms/llms.txt +57 -5
  234. package/dist/mcp.es.js +4756 -782
  235. package/dist/primitives/card-component-types.d.ts +11 -0
  236. package/dist/primitives/card-data-types.d.ts +196 -0
  237. package/dist/primitives/card-host.d.ts +1 -1
  238. package/dist/primitives/card-recovery.d.ts +3 -3
  239. package/dist/primitives/card-registry.d.ts +4 -14
  240. package/dist/primitives/card-resolution.d.ts +1 -1
  241. package/dist/primitives/card-routing.d.ts +1 -1
  242. package/dist/primitives/card-tags.d.ts +11 -0
  243. package/dist/primitives/card-validate-cards.d.ts +57 -0
  244. package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
  245. package/dist/primitives/card-validate-schemas.d.ts +17 -0
  246. package/dist/primitives/card-validate.d.ts +24 -0
  247. package/dist/primitives/create-kai-chat.d.ts +3 -3
  248. package/dist/primitives/embed-providers.d.ts +1 -1
  249. package/dist/primitives/link-preview.d.ts +1 -1
  250. package/dist/primitives/message-feedback.d.ts +2 -2
  251. package/dist/primitives/toast-store.d.ts +1 -1
  252. package/dist/react/index.d.ts +730 -302
  253. package/dist/react/use-kai-chat.d.ts +8 -4
  254. package/dist/react.d.ts +5 -0
  255. package/dist/react.js +418 -317
  256. package/dist/register-impl-AxIlqjo7.js +145 -0
  257. package/dist/remote/host-embed.d.ts +1 -1
  258. package/dist/remote/index.d.ts +2 -2
  259. package/dist/remote/provider-runtime.d.ts +2 -2
  260. package/dist/remote/provider.d.ts +2 -2
  261. package/dist/remote/validate.d.ts +1 -1
  262. package/dist/remote/wire.d.ts +1 -1
  263. package/dist/schemas/artifact.schema.json +92 -0
  264. package/dist/schemas/embed.schema.json +0 -2
  265. package/dist/schemas/from-tool-call.d.ts +48 -0
  266. package/dist/schemas/index.d.ts +48 -0
  267. package/dist/schemas/link.schema.json +0 -2
  268. package/dist/schemas/provider-subsets.d.ts +136 -0
  269. package/dist/schemas/registry.d.ts +140 -0
  270. package/dist/schemas/tool-defs.d.ts +121 -0
  271. package/dist/schemas.d.ts +5 -0
  272. package/dist/schemas.js +717 -0
  273. package/dist/solid-BGYSJyHG.js +22960 -0
  274. package/dist/solid-Dt2nEwfl.js +20194 -0
  275. package/dist/solid.d.ts +66 -0
  276. package/dist/solid.js +261 -0
  277. package/dist/solid.server.d.ts +5 -0
  278. package/dist/solid.server.js +261 -0
  279. package/dist/state/index.d.ts +14 -4
  280. package/dist/state/messages.d.ts +8 -3
  281. package/dist/state/mock.d.ts +46 -0
  282. package/dist/state/parts.d.ts +85 -0
  283. package/dist/state/stream.d.ts +15 -9
  284. package/dist/state.d.ts +5 -0
  285. package/dist/state.js +253 -84
  286. package/dist/ui/action-icons.d.ts +1 -1
  287. package/dist/ui/collapsible.d.ts +11 -6
  288. package/dist/ui/dropdown.d.ts +47 -42
  289. package/dist/ui/pane-group.d.ts +1 -1
  290. package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-B44X69AG.js} +1 -1
  291. package/dist/variant-aurora-BRhV8Flk.js +391 -0
  292. package/dist/variant-aurora-Ds5ou9BH.js +381 -0
  293. package/dist/variant-custom-B20FhtYj.js +170 -0
  294. package/dist/{variant-custom-Dif-IV4u.js → variant-custom-BvA1Schl.js} +1 -1
  295. package/dist/variant-custom-D6Rtvneb.js +200 -0
  296. package/dist/{variant-wave-DbfNdvSi.js → variant-wave-BUQtkryq.js} +1 -1
  297. package/dist/variant-wave-BVYnqy9L.js +218 -0
  298. package/dist/variant-wave-DXC6_LcH.js +208 -0
  299. package/dist/wire/chunk.d.ts +171 -0
  300. package/dist/wire/consume.d.ts +26 -0
  301. package/dist/wire/encode.d.ts +221 -0
  302. package/dist/wire/files.d.ts +116 -0
  303. package/dist/wire/formats/anthropic.d.ts +2 -0
  304. package/dist/wire/formats/openai.d.ts +5 -0
  305. package/dist/wire/index.d.ts +16 -0
  306. package/dist/wire/media-types.d.ts +106 -0
  307. package/dist/wire/read.d.ts +26 -0
  308. package/dist/wire/sink-helpers.d.ts +21 -0
  309. package/dist/wire/sse.d.ts +33 -0
  310. package/dist/wire.d.ts +5 -53
  311. package/dist/wire.js +1126 -0
  312. package/frameworks/react/index.tsx +191 -158
  313. package/frameworks/react/runtime.tsx +21 -1
  314. package/frameworks/react/use-kai-chat.tsx +11 -1
  315. package/llms-full.txt +774 -151
  316. package/llms.txt +57 -5
  317. package/package.json +62 -8
  318. package/src/agent-tooling/archetypes.ts +127 -0
  319. package/src/agent-tooling/integrations/anthropic.ts +436 -0
  320. package/src/agent-tooling/integrations/cloudflare.ts +141 -52
  321. package/src/agent-tooling/integrations/langgraph.ts +80 -13
  322. package/src/agent-tooling/integrations/mastra.ts +161 -12
  323. package/src/agent-tooling/integrations/mock.ts +47 -8
  324. package/src/agent-tooling/integrations/ollama.ts +68 -24
  325. package/src/agent-tooling/integrations/openai.ts +89 -0
  326. package/src/agent-tooling/integrations/openrouter.ts +58 -8
  327. package/src/agent-tooling/integrations/pi.ts +104 -23
  328. package/src/agent-tooling/integrations/pydantic-ai.ts +61 -5
  329. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +120 -13
  330. package/src/agent-tooling/mcp/manifest.ts +206 -25
  331. package/src/agent-tooling/mcp/tools/debug.ts +13 -7
  332. package/src/agent-tooling/mcp/tools/reference.ts +285 -6
  333. package/src/agent-tooling/mcp/tools/scaffold.ts +4152 -661
  334. package/src/agent-tooling/registry.ts +74 -0
  335. package/src/agent-tooling/types.ts +361 -1
  336. package/src/components/artifact-card.tsx +120 -0
  337. package/src/components/audio-visualizer/index.tsx +9 -0
  338. package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
  339. package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
  340. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
  341. package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
  342. package/src/components/card-fallback.tsx +42 -10
  343. package/src/components/card-renderer.tsx +146 -9
  344. package/src/components/chat-container.tsx +4 -0
  345. package/src/components/chat-thread.tsx +128 -52
  346. package/src/components/choice-card.tsx +17 -29
  347. package/src/components/composer.tsx +12 -2
  348. package/src/components/confirm-card.tsx +24 -20
  349. package/src/components/context.tsx +30 -16
  350. package/src/components/conversation-item.tsx +6 -0
  351. package/src/components/conversation-list.tsx +18 -2
  352. package/src/components/file-tree.tsx +11 -22
  353. package/src/components/file-upload.tsx +14 -8
  354. package/src/components/form.tsx +14 -47
  355. package/src/components/loader.tsx +39 -12
  356. package/src/components/message-skills.tsx +4 -0
  357. package/src/components/message.tsx +294 -46
  358. package/src/components/model-switcher.tsx +38 -8
  359. package/src/components/reasoning.tsx +92 -5
  360. package/src/components/response-compare-types.ts +25 -0
  361. package/src/components/response-compare.tsx +4 -9
  362. package/src/components/source.tsx +50 -24
  363. package/src/components/tasks-card.tsx +10 -33
  364. package/src/components/thread.tsx +84 -42
  365. package/src/components/toast.tsx +17 -6
  366. package/src/components/tool-classify.ts +26 -0
  367. package/src/components/tool-types.ts +31 -1
  368. package/src/elements/agent-card.tsx +11 -11
  369. package/src/elements/artifact.tsx +15 -7
  370. package/src/elements/attachments.tsx +6 -4
  371. package/src/elements/avatar.tsx +1 -1
  372. package/src/elements/button.tsx +29 -6
  373. package/src/elements/card.tsx +2 -2
  374. package/src/elements/cards.tsx +109 -14
  375. package/src/elements/chain-of-thought.tsx +14 -10
  376. package/src/elements/chat-scope-picker.tsx +9 -7
  377. package/src/elements/chat-types.ts +59 -6
  378. package/src/elements/chat-workspace.tsx +50 -9
  379. package/src/elements/chat.tsx +90 -3
  380. package/src/elements/choice.tsx +8 -8
  381. package/src/elements/coachmark.tsx +1 -1
  382. package/src/elements/command.tsx +8 -23
  383. package/src/elements/compare.tsx +7 -6
  384. package/src/elements/compiled.css +1 -1
  385. package/src/elements/composer.tsx +8 -8
  386. package/src/elements/confirm-card.tsx +9 -9
  387. package/src/elements/context-meter.tsx +4 -18
  388. package/src/elements/conversation-list.tsx +14 -9
  389. package/src/elements/default-input.tsx +131 -8
  390. package/src/elements/define.tsx +178 -43
  391. package/src/elements/editable-label.tsx +17 -2
  392. package/src/elements/element-data-types.ts +112 -0
  393. package/src/elements/element-meta.json +1624 -306
  394. package/src/elements/element-types.d.ts +2645 -214
  395. package/src/elements/feedback-bar.tsx +1 -1
  396. package/src/elements/file-tree.tsx +1 -1
  397. package/src/elements/file-upload.tsx +1 -1
  398. package/src/elements/form.tsx +14 -6
  399. package/src/elements/input.tsx +1 -1
  400. package/src/elements/kbd.tsx +1 -1
  401. package/src/elements/menu.tsx +40 -32
  402. package/src/elements/message-skills.tsx +7 -9
  403. package/src/elements/message.tsx +200 -32
  404. package/src/elements/model-switcher.tsx +5 -3
  405. package/src/elements/pane.tsx +1 -1
  406. package/src/elements/prompt-dock.tsx +8 -8
  407. package/src/elements/prompt-input.tsx +10 -10
  408. package/src/elements/prompt-suggestions.tsx +7 -4
  409. package/src/elements/reasoning.tsx +1 -1
  410. package/src/elements/register.ts +9 -0
  411. package/src/elements/resizable.globals.d.ts +36 -0
  412. package/src/elements/resizable.tsx +24 -13
  413. package/src/elements/response-stream.tsx +1 -1
  414. package/src/elements/scroll-button.tsx +1 -1
  415. package/src/elements/search.tsx +6 -1
  416. package/src/elements/segmented.tsx +5 -11
  417. package/src/elements/separator.tsx +1 -1
  418. package/src/elements/slot-text.ts +73 -0
  419. package/src/elements/slots.ts +67 -24
  420. package/src/elements/source.tsx +21 -22
  421. package/src/elements/switch.tsx +3 -3
  422. package/src/elements/tasks.tsx +5 -4
  423. package/src/elements/thread.tsx +36 -4
  424. package/src/elements/toast.tsx +3 -2
  425. package/src/elements/tool.tsx +1 -1
  426. package/src/elements/validate-messages.ts +76 -0
  427. package/src/elements/voice-input.tsx +7 -7
  428. package/src/elements/voice-output.tsx +4 -4
  429. package/src/index.ts +145 -6
  430. package/src/primitives/card-component-types.ts +63 -0
  431. package/src/primitives/card-data-types.ts +312 -0
  432. package/src/primitives/card-recovery.ts +13 -2
  433. package/src/primitives/card-registry.tsx +34 -23
  434. package/src/primitives/card-schemas/artifact.schema.json +92 -0
  435. package/src/primitives/card-schemas/embed.schema.json +0 -2
  436. package/src/primitives/card-schemas/link.schema.json +0 -2
  437. package/src/primitives/card-tags.ts +61 -0
  438. package/src/primitives/card-validate-cards.ts +255 -0
  439. package/src/primitives/card-validate-generator.testlib.ts +38 -0
  440. package/src/primitives/card-validate-schemas.ts +58 -0
  441. package/src/primitives/card-validate.ts +48 -20
  442. package/src/primitives/create-tween.ts +54 -2
  443. package/src/primitives/message-feedback.ts +3 -2
  444. package/src/primitives/use-audio-analysis.ts +20 -1
  445. package/src/primitives/use-sequencer.ts +20 -1
  446. package/src/schemas/from-tool-call.ts +151 -0
  447. package/src/schemas/index.ts +340 -0
  448. package/src/schemas/provider-subsets.ts +538 -0
  449. package/src/schemas/registry.ts +355 -0
  450. package/src/schemas/tool-defs.ts +492 -0
  451. package/src/solid.ts +150 -0
  452. package/src/state/index.ts +27 -1
  453. package/src/state/messages.ts +21 -4
  454. package/src/state/mock.ts +211 -0
  455. package/src/state/parts.ts +295 -0
  456. package/src/state/stream.ts +56 -58
  457. package/src/ui/collapsible.tsx +17 -5
  458. package/src/ui/dropdown.tsx +46 -12
  459. package/src/ui/overlay.tsx +10 -4
  460. package/src/wire/chunk.ts +201 -0
  461. package/src/wire/consume.ts +440 -0
  462. package/src/wire/encode.ts +689 -0
  463. package/src/wire/files.ts +342 -0
  464. package/src/wire/formats/anthropic.ts +267 -0
  465. package/src/wire/formats/openai.ts +187 -0
  466. package/src/wire/index.ts +73 -0
  467. package/src/wire/media-types.ts +344 -0
  468. package/src/wire/read.ts +152 -0
  469. package/src/wire/sink-helpers.ts +50 -0
  470. package/src/wire/sse.ts +140 -0
  471. package/dist/create-tween-hvpmSuwW.js +0 -7
  472. package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
  473. package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
  474. package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
  475. package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
  476. package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
  477. package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
  478. package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
  479. package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
  480. package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
  481. package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
  482. package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
  483. package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
  484. package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
  485. package/dist/elements/chunks/default-input-Cqqilg9t.js +0 -1
  486. package/dist/elements/chunks/define-D1din7Ld.js +0 -1
  487. package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
  488. package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
  489. package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
  490. package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
  491. package/dist/elements/chunks/model-switcher-B94YAKsM.js +0 -1
  492. package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
  493. package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
  494. package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
  495. package/dist/elements/chunks/slots--V19HwUb.js +0 -1
  496. package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
  497. package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
  498. package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
  499. package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
  500. package/dist/host-embed.d.ts +0 -33
  501. package/dist/kai-provider.d.ts +0 -2
  502. package/dist/origin.d.ts +0 -5
  503. package/dist/provider-runtime.d.ts +0 -27
  504. package/dist/register-impl-DQyejdfb.js +0 -145
  505. package/dist/validate.d.ts +0 -4
  506. package/dist/version.d.ts +0 -4
  507. package/src/components/component-meta.json +0 -4550
  508. package/src/elements/card-media.jpg +0 -0
  509. package/src/elements/resizable.d.ts +0 -27
  510. package/src/elements/video-poster.jpg +0 -0
@@ -1,4 +1,6 @@
1
1
  import type { Integration, Archetype } from './types';
2
+ import openai from './integrations/openai';
3
+ import anthropic from './integrations/anthropic';
2
4
  import openrouter from './integrations/openrouter';
3
5
  import vercelAiSdk from './integrations/vercel-ai-sdk';
4
6
  import langgraph from './integrations/langgraph';
@@ -10,7 +12,22 @@ import pydanticAi from './integrations/pydantic-ai';
10
12
  import mock from './integrations/mock';
11
13
  import { archetypes as _archetypes } from './archetypes';
12
14
 
15
+ // The surface axis for the scaffolder's gate, derived from the presets above.
16
+ // Re-exported here because `scripts/verify-scaffold-compiles.mjs` bundles this
17
+ // module for its axes and must not reach past the registry for one of them.
18
+ export {
19
+ BASE_COMPONENT,
20
+ listCapabilityGroups,
21
+ listSurfaceProbes,
22
+ type CapabilityGroup,
23
+ type SurfaceProbe,
24
+ } from './archetypes';
25
+
26
+ // Order is the order a scaffolding agent reads them in. `openai` and `anthropic`
27
+ // lead because they are the two keys a developer is most likely to already hold.
13
28
  export const integrations: Integration[] = [
29
+ openai,
30
+ anthropic,
14
31
  openrouter,
15
32
  vercelAiSdk,
16
33
  langgraph,
@@ -36,6 +53,63 @@ export function listIntegrations(): Integration[] {
36
53
  return integrations;
37
54
  }
38
55
 
56
+ /** One heading in `create-kai`'s gateway prompt. */
57
+ export interface GatewayGroup {
58
+ id: 'no-backend' | 'bring-a-key' | 'bring-a-server';
59
+ title: string;
60
+ integrations: Integration[];
61
+ }
62
+
63
+ /**
64
+ * The gateway prompt's three groups, DERIVED — the thing the spec described and
65
+ * the catalog could not answer.
66
+ *
67
+ * It is here, and not in the CLI, for the reason `deps` is not in the spec's
68
+ * prose: a grouping maintained next to the menu that renders it is a second copy
69
+ * of the catalog, and it goes stale the first time an integration lands. Adding
70
+ * one now moves these groups by itself, because the only inputs are declared
71
+ * fields.
72
+ *
73
+ * THE ORDER OF THE TESTS IS THE DESIGN, not an implementation detail:
74
+ *
75
+ * 1. No route at all -> **No backend**. Exactly `mock` today, and derived from
76
+ * the absence rather than from `id === 'mock'` or `category === 'mock'`: a
77
+ * second no-backend entry (a canned transcript player, say) should land in
78
+ * this group without editing this function.
79
+ * 2. `outOfBand !== 'none'` -> **Bring a server or runtime**, and this is
80
+ * checked BEFORE the key test on purpose. `pydantic-ai` needs both a python
81
+ * runtime and OPENAI_API_KEY; the groups are not disjoint in reality, so
82
+ * something has to win, and the prerequisite does — a key is useless until
83
+ * the service it authenticates is running. The prompt still asks for the
84
+ * key afterwards; only the HEADING is decided here.
85
+ * 3. Everything else -> **Bring a key**.
86
+ *
87
+ * WHERE THIS DIVERGES FROM THE SPEC, ON PURPOSE. The spec's third group reads
88
+ * "Ollama, LangGraph, Mastra, Pydantic AI, Pi". `langgraph` comes out of this
89
+ * function in **Bring a key** instead, because its emitted route compiles the
90
+ * graph in process and asks for nothing but `OPENAI_API_KEY` — see the comment on
91
+ * its `outOfBand`. The spec sentence was written before the field existed and is
92
+ * wrong about that one entry; this is the derivation, so this is the answer.
93
+ */
94
+ export function listGatewayGroups(): GatewayGroup[] {
95
+ const hasRoute = (i: Integration) =>
96
+ i.webRoute !== undefined || Object.keys(i.routeTemplates).length > 0;
97
+
98
+ const groups: GatewayGroup[] = [
99
+ { id: 'no-backend', title: 'No backend', integrations: [] },
100
+ { id: 'bring-a-key', title: 'Bring a key', integrations: [] },
101
+ { id: 'bring-a-server', title: 'Bring a server or runtime', integrations: [] },
102
+ ];
103
+ const into = (id: GatewayGroup['id']) => groups.find((g) => g.id === id)!;
104
+
105
+ for (const integration of integrations) {
106
+ if (!hasRoute(integration)) into('no-backend').integrations.push(integration);
107
+ else if (integration.outOfBand !== 'none') into('bring-a-server').integrations.push(integration);
108
+ else into('bring-a-key').integrations.push(integration);
109
+ }
110
+ return groups;
111
+ }
112
+
39
113
  export function listArchetypes(): Archetype[] {
40
114
  return archetypes;
41
115
  }
@@ -3,9 +3,159 @@ import { z } from 'zod';
3
3
  export const Category = z.enum(['provider', 'gateway', 'framework', 'harness', 'mock']);
4
4
  export const Language = z.enum(['ts', 'python']);
5
5
  export const StreamFormat = z.enum(['openai-sse', 'ai-sdk', 'native']);
6
- export const Framework = z.enum(['html', 'react', 'next', 'vue', 'svelte', 'fastapi', 'express', 'worker', 'tanstack-start']);
6
+ /**
7
+ * The scaffold's target.
8
+ *
9
+ * Two of these are NOT web-component consumers, and the difference is load-bearing:
10
+ * - `angular` consumes `kai-*` like vue/svelte/html, but needs
11
+ * `CUSTOM_ELEMENTS_SCHEMA` and binds arrays/objects with `[prop]="…"`.
12
+ * - `solid` consumes the SolidJS components DIRECTLY from the `@kitn.ai/ui`
13
+ * root entry. The kit is authored in Solid, so routing a Solid consumer
14
+ * through the custom-element facade would ship the Solid runtime twice and
15
+ * cross a reactive-context boundary for nothing.
16
+ */
17
+ export const Framework = z.enum(['html', 'react', 'next', 'vue', 'svelte', 'angular', 'solid', 'fastapi', 'express', 'worker', 'tanstack-start']);
7
18
  export const Placement = z.enum(['side', 'full-page', 'docked-widget', 'inline']);
8
19
 
20
+ /**
21
+ * Whether this integration's SECRET may sit in the browser bundle.
22
+ *
23
+ * Read `'needs-proxy'` as "a server hop is mandatory" and `'frontend-safe'` as
24
+ * "the browser may call the upstream itself". This is the flag `create-kai`
25
+ * consults before it decides where a key goes, so getting it wrong in the
26
+ * permissive direction writes an API key into client code. There is deliberately
27
+ * no default and no boolean: the refinement below REJECTS an integration that
28
+ * declares neither, because "absent" must never read as "safe".
29
+ *
30
+ * `'needs-proxy'` covers two cases, and the second is easy to miss:
31
+ * 1. a secret. The route holds a key, so a static bundle cannot.
32
+ * 2. a server-only CAPABILITY. `pi` spawns a local process; no key is involved
33
+ * and a browser still cannot do it.
34
+ *
35
+ * `'frontend-safe'` is the narrow claim: nothing secret AND no server-only
36
+ * capability. Two integrations qualify, and both were read off their routes —
37
+ * `ollama` fetches `localhost:11434` with no auth header at all, and `mock`
38
+ * ships no route to reach.
39
+ *
40
+ * Do not infer this from the provider's name. A provider with a CORS-friendly
41
+ * public endpoint and one that requires a proxy look identical from outside; only
42
+ * the route says which it is. That is the same lesson `forwardsFromClient` and
43
+ * `clientToolFormat` were each added to record.
44
+ */
45
+ export const KeyExposure = z.enum(['frontend-safe', 'needs-proxy']);
46
+
47
+ /**
48
+ * What this integration needs the developer to supply OUT OF BAND — beyond an
49
+ * install and a key.
50
+ *
51
+ * `create-kai` groups its gateway prompt three ways: **No backend**, **Bring a
52
+ * key**, **Bring a server or runtime**. The third group is defined by exactly
53
+ * this question, and until now the catalog could not answer it. Every derivation
54
+ * that reproduced the spec's split did so by accident and broke on inspection:
55
+ * · `category` does not separate them at all — `provider` holds `openai` and
56
+ * `ollama`, `framework` holds `vercel-ai-sdk` and `langgraph`.
57
+ * · a non-empty `routeTemplates` picks out `cloudflare`/`pi`/`pydantic-ai`,
58
+ * which is a fact about how a route is EXPRESSED, not about what it needs.
59
+ * · "declares a secret env var" puts `langgraph` and `pydantic-ai` in the key
60
+ * group, which is right for one and wrong for the other.
61
+ * So it is declared, for the reason `keyExposure`, `forwardsFromClient` and
62
+ * `clientToolFormat` are each declared: only the route knows.
63
+ *
64
+ * The four values, and what makes each its own case for the CLI rather than a
65
+ * boolean it could have been:
66
+ *
67
+ * · `'none'` ......... `npm install` plus (maybe) a key is the whole story.
68
+ * The upstream is a remote HTTPS endpoint, or the agent runs IN the route.
69
+ * `langgraph` is the one worth reading twice: it is in the spec's "server or
70
+ * runtime" group and does not belong there — its emitted route builds the
71
+ * graph in process (`createReactAgent` + `new ChatOpenAI(...)`), so there is
72
+ * no LangGraph server anywhere and its runNote asks only for a key.
73
+ * · `'local-server'` . a separate process must already be LISTENING before the
74
+ * app works. The CLI cannot create it and must say so: `ollama serve` on
75
+ * 11434, a `mastra dev` server behind `MASTRA_URL`.
76
+ * · `'local-binary'` . an executable must be on PATH; the route spawns it on
77
+ * demand rather than talking to a port. Nothing is listening beforehand, so
78
+ * "start the server" is the wrong instruction — `pi` is the case.
79
+ * · `'language-runtime'` the emitted backend runs on a runtime the JS toolchain
80
+ * does not provide, and the user starts it themselves. `pydantic-ai` is a
81
+ * FastAPI service: `deps.pip`, `uvicorn main:app`, a second port.
82
+ *
83
+ * A boolean would collapse the last three, and they are three different sentences
84
+ * to print next to a menu item. The refinement below REFUSES an integration that
85
+ * declares nothing, for the same reason `keyExposure` does: a missing value read
86
+ * as `'none'` is a scaffold that says "npm run dev" to someone who needs to start
87
+ * Ollama first, and then reports as a broken kit.
88
+ */
89
+ export const OutOfBand = z.enum(['none', 'local-server', 'local-binary', 'language-runtime']);
90
+
91
+ /**
92
+ * The packages an app must install BEYOND `@kitn.ai/ui` to run this
93
+ * integration's route.
94
+ *
95
+ * Derived once, here, from the route's own import statements, so the CLI never
96
+ * has to re-parse route source to find them. Today this fact only exists as prose
97
+ * in `runNote`, which no installer can read.
98
+ *
99
+ * The rule, enforced by `registry.test.ts`: `npm` is exactly the set of
100
+ * bare-module specifiers imported by the TS route sources, normalised to package
101
+ * names (`@langchain/core/tools` counts as `@langchain/core`), minus `node:`
102
+ * builtins and minus `@kitn.ai/ui` itself, which every scaffold already depends
103
+ * on. `pip` is a superset of the python route's imports, because a Python app
104
+ * also needs its ASGI server (`uvicorn`), which nothing imports.
105
+ *
106
+ * Type-only packages (`@types/*`) are not listed: nothing imports them, so the
107
+ * rule cannot see them, and the frameworks that need them already carry them.
108
+ */
109
+ export const DepsSchema = z.object({
110
+ npm: z.array(z.string()).default([]),
111
+ pip: z.array(z.string()).default([]),
112
+ });
113
+
114
+ /**
115
+ * An env var name that holds a secret rather than an address.
116
+ *
117
+ * Anchored at the END, which is the whole precision of it: `CF_API_TOKEN` and
118
+ * `AI_GATEWAY_API_KEY` match, while `CF_ACCOUNT_ID` and `MASTRA_URL` do not.
119
+ * `MASTRA_URL` is the case that stops this being a proxy for "declares any env
120
+ * var at all" — a base URL is not a credential.
121
+ *
122
+ * This is a SAFETY NET over the declaration, never its source. Three integrations
123
+ * (`langgraph`, `vercel-ai-sdk`, `pydantic-ai`) hold a key their route source
124
+ * never names, because the SDK reads the env var itself; their `envVars` is what
125
+ * catches them here, and nothing but the author reading the route would have.
126
+ *
127
+ * Exported because the scaffolder names the secrets back at the developer in its
128
+ * run note ("OPENAI_API_KEY stays on the server"). That sentence and the
129
+ * refinement below have to agree about which env vars are secret, so there is one
130
+ * pattern rather than two free to drift apart.
131
+ */
132
+ export const SECRET_ENV_VAR = /(?:KEY|TOKEN|SECRET|PASSWORD)$/;
133
+
134
+ /**
135
+ * A credential written into a request from route source. The second alternative
136
+ * is Anthropic's spelling, which is not an `Authorization` header at all.
137
+ */
138
+ const AUTH_HEADER = /Authorization\s*:|['"]x-api-key['"]\s*:/i;
139
+
140
+ /**
141
+ * A route that FETCHES a loopback address — so something local has to be
142
+ * listening. `ollama`'s `fetch('http://localhost:11434/v1/chat/completions')` is
143
+ * the case this catches.
144
+ *
145
+ * Anchored at the fetch/URL call, not matched anywhere in the source, and that
146
+ * precision is the whole point. Two other routes mention loopback in prose:
147
+ * mastra's `throw new Error('MASTRA_URL is not set… e.g. http://localhost:4111')`
148
+ * and pi's `console.log('chat api: http://localhost:3001/api/chat')`. A bare
149
+ * /localhost/ would flag both — mastra for the right answer by the wrong
150
+ * evidence, pi for a line about its OWN listening port, which says nothing about
151
+ * what it depends on. A net that is right by accident is the thing this field
152
+ * exists to replace, so it is narrowed until it only fires on a real dependency.
153
+ */
154
+ const LOOPBACK_FETCH = /\b(?:fetch|URL)\s*\(\s*['"`]https?:\/\/(?:localhost|127\.0\.0\.1)/;
155
+
156
+ /** A route that shells out. The program it names must exist on the host. */
157
+ const SPAWNS_PROCESS = /\bfrom\s+['"]node:child_process['"]|\bspawn\s*\(/;
158
+
9
159
  export const IntegrationSchema = z.object({
10
160
  id: z.string(),
11
161
  title: z.string(),
@@ -14,9 +164,219 @@ export const IntegrationSchema = z.object({
14
164
  streamFormat: StreamFormat,
15
165
  envVars: z.array(z.string()).default([]),
16
166
  routeTemplates: z.record(z.string(), z.string()), // keyed by Framework value → code string
167
+ /**
168
+ * The backend as ONE web-standard handler, `(Request) => Response`, written as
169
+ * a complete `async function chatHandler(request: Request)` declaration.
170
+ *
171
+ * WHY THIS EXISTS. `routeTemplates` is keyed by framework, and in practice
172
+ * every TS integration only ever filled in `next`. Everything else fell
173
+ * through to it, so a svelte scaffold emitted a Next.js `export async function
174
+ * POST(req)` — which TYPECHECKS under SvelteKit and then throws
175
+ * `req.json is not a function` on the first submit, because SvelteKit calls
176
+ * `POST(event)`. vue and html got the same snippet with nowhere to put it.
177
+ *
178
+ * The handler BODY is portable; only the few lines that declare the route
179
+ * differ per framework. So integrations write the body once here and the
180
+ * scaffolder wraps it (see `WEB_ROUTE_ADAPTERS` in mcp/tools/scaffold.ts).
181
+ * `routeTemplates` stays for routes that genuinely cannot be expressed this
182
+ * way: a Worker using an `env` binding, an Express `(req, res)` bridge, a
183
+ * FastAPI service.
184
+ *
185
+ * An exact `routeTemplates[framework]` still wins over this.
186
+ */
187
+ webRoute: z.string().optional(),
17
188
  streamMapping: z.string(), // prose: how the stream maps to messages
18
189
  runNote: z.string(),
19
190
  docsSlug: z.string(),
191
+ /**
192
+ * The request-body fields this integration's ROUTE reads off the client and
193
+ * forwards upstream. Anything not listed is owned by the route or by the agent
194
+ * behind it.
195
+ *
196
+ * The scaffolder emits an editable const for a field only when it appears
197
+ * here, and that is the whole point: `model` used to be emitted whenever a
198
+ * route template contained the substring 'model', which is true of any
199
+ * template that so much as writes `model: 'llama3.2'`, so four integrations
200
+ * shipped an editable const their route threw away. The mirror-image bug is a
201
+ * `tools` array that never gets sent, which leaves kai-tool a panel no code
202
+ * path can populate.
203
+ *
204
+ * Empty by default, so a new integration emits nothing until its route really
205
+ * does forward the field.
206
+ */
207
+ forwardsFromClient: z.array(z.enum(['model', 'tools'])).default([]),
208
+ /**
209
+ * The tool-definition envelope this integration's ROUTE expects to find in the
210
+ * `tools` array the client POSTs. Required exactly when `forwardsFromClient`
211
+ * includes `'tools'`, and meaningless otherwise.
212
+ *
213
+ * WHY THIS IS DECLARED AND NOT DERIVED. It used to be looked up from
214
+ * `streamFormat`, and that is a category error: `streamFormat` describes the
215
+ * shape of the RESPONSE stream, while the tool envelope is a REQUEST concern.
216
+ * The two only appeared to agree because every integration that forwarded
217
+ * tools happened to be `openai-sse`. `anthropic` is where the conflation
218
+ * becomes visible — it is `streamFormat: 'native'`, which says nothing about
219
+ * request shape, and the old table mapped `native` to null.
220
+ *
221
+ * And keying on the integration's PROVIDER would be wrong too, which is the
222
+ * part worth reading the route before assuming: `anthropic`'s handler converts
223
+ * the array itself (`toAnthropicTools` reads `raw.function.name` /
224
+ * `.function.parameters`), so it wants `'openai'` here. Handing it Anthropic's
225
+ * own `{ name, input_schema }` shape would yield tools with a blank name. Only
226
+ * the route knows what it accepts, so only the integration can state it — the
227
+ * same reason `forwardsFromClient` lives here rather than being sniffed out of
228
+ * the route source.
229
+ *
230
+ * Optional in the type, mandatory in practice: the refinement below rejects an
231
+ * integration that forwards tools without one. There is deliberately no
232
+ * default — a default is how a tools array with no card in it ships silently.
233
+ */
234
+ clientToolFormat: z.enum(['openai', 'anthropic', 'jsonschema']).optional(),
235
+ /** See {@link DepsSchema}. Empty is a real answer: a fetch-only route needs nothing. */
236
+ deps: DepsSchema.default({ npm: [], pip: [] }),
237
+ /**
238
+ * See {@link KeyExposure}. Optional in the TYPE only so the refinement below
239
+ * owns the error message — Zod skips refinements when the base object already
240
+ * failed, so a plain required field would report "Invalid input" and this is
241
+ * the one field where the reader needs to be told what is at stake.
242
+ */
243
+ keyExposure: KeyExposure.optional(),
244
+ /**
245
+ * See {@link OutOfBand}. Optional in the TYPE only so the refinement below owns
246
+ * the error message — Zod skips refinements when the base object already
247
+ * failed, so a plain required field would report "Invalid input" and this is a
248
+ * field whose reader needs to be told what the four values mean.
249
+ */
250
+ outOfBand: OutOfBand.optional(),
251
+ }).superRefine((integration, ctx) => {
252
+ // Enforced against the real catalog by `registry.test.ts`, which parses every
253
+ // integration through this schema. A new host that forwards tools therefore
254
+ // cannot reach the scaffolder undeclared: it fails at the catalog boundary,
255
+ // before any emit path has to decide what to do about it.
256
+ if (integration.forwardsFromClient.includes('tools') && integration.clientToolFormat === undefined) {
257
+ ctx.addIssue({
258
+ code: z.ZodIssueCode.custom,
259
+ path: ['clientToolFormat'],
260
+ message:
261
+ `integration '${integration.id}' forwards a 'tools' array but declares no clientToolFormat. ` +
262
+ `State the envelope its route expects: 'openai' ({ type: 'function', function: { parameters } }), ` +
263
+ `'anthropic' ({ name, input_schema }), or 'jsonschema' ({ name, description, schema }). ` +
264
+ `Read the route's own handler to decide — a route that CONVERTS the array server-side wants the ` +
265
+ `shape it converts FROM, not its own provider's.`,
266
+ });
267
+ }
268
+
269
+ // ---- keyExposure ----
270
+ //
271
+ // Two checks, and the split matters. The first refuses SILENCE. The second
272
+ // refuses a specific LIE, and only ever in the dangerous direction: it can
273
+ // turn a 'frontend-safe' claim into an error, never the reverse. Declaring
274
+ // 'needs-proxy' where a proxy was not strictly required costs a server hop;
275
+ // declaring 'frontend-safe' where it was required costs the key.
276
+
277
+ if (integration.keyExposure === undefined) {
278
+ ctx.addIssue({
279
+ code: z.ZodIssueCode.custom,
280
+ path: ['keyExposure'],
281
+ message:
282
+ `integration '${integration.id}' declares no keyExposure. State whether its SECRET may reach the ` +
283
+ `browser bundle: 'needs-proxy' (a key, or a server-only capability such as spawning a process, so ` +
284
+ `the CLI must keep it behind a server) or 'frontend-safe' (nothing secret and nothing server-only, ` +
285
+ `so the browser may call the upstream directly). Read the route to decide, not the provider's name: ` +
286
+ `a public CORS-friendly endpoint and one that requires a proxy are indistinguishable from outside. ` +
287
+ `There is no default on purpose — a missing flag read as "safe" is how an API key ships in client code.`,
288
+ });
289
+ }
290
+
291
+ if (integration.keyExposure === 'frontend-safe') {
292
+ const secrets = integration.envVars.filter((name) => SECRET_ENV_VAR.test(name));
293
+ if (secrets.length > 0) {
294
+ ctx.addIssue({
295
+ code: z.ZodIssueCode.custom,
296
+ path: ['keyExposure'],
297
+ message:
298
+ `integration '${integration.id}' claims keyExposure 'frontend-safe' but declares the secret env ` +
299
+ `var(s) ${secrets.join(', ')}. A frontend bundle is public, so that combination puts a key in ` +
300
+ `client code. Use 'needs-proxy'.`,
301
+ });
302
+ }
303
+
304
+ const routeSources = [
305
+ ...Object.values(integration.routeTemplates),
306
+ ...(integration.webRoute ? [integration.webRoute] : []),
307
+ ];
308
+ if (routeSources.some((code) => AUTH_HEADER.test(code))) {
309
+ ctx.addIssue({
310
+ code: z.ZodIssueCode.custom,
311
+ path: ['keyExposure'],
312
+ message:
313
+ `integration '${integration.id}' claims keyExposure 'frontend-safe' but its route sends an ` +
314
+ `authorization header, so it holds a credential a browser bundle must not. Use 'needs-proxy'.`,
315
+ });
316
+ }
317
+ }
318
+
319
+ // ---- outOfBand ----
320
+ //
321
+ // Same two-check shape as keyExposure, and the same asymmetry. The first
322
+ // refuses SILENCE. The second refuses a specific LIE, and only in the direction
323
+ // that costs the developer something: it can turn a `'none'` claim into an
324
+ // error, never the reverse. Over-declaring prints a prerequisite that was not
325
+ // strictly needed; under-declaring ships a scaffold that cannot possibly run
326
+ // and blames the kit.
327
+
328
+ if (integration.outOfBand === undefined) {
329
+ ctx.addIssue({
330
+ code: z.ZodIssueCode.custom,
331
+ path: ['outOfBand'],
332
+ message:
333
+ `integration '${integration.id}' declares no outOfBand. State what the developer must supply ` +
334
+ `BEYOND an install and a key, because that is the group create-kai's gateway prompt puts it in: ` +
335
+ `'none' (a remote endpoint, or the agent runs inside the route), 'local-server' (a process must ` +
336
+ `already be listening, e.g. 'ollama serve'), 'local-binary' (an executable on PATH that the route ` +
337
+ `spawns), or 'language-runtime' (the emitted backend needs a runtime the JS toolchain does not ` +
338
+ `provide, e.g. python + uvicorn). Read the route and the runNote to decide, not the category: ` +
339
+ `'provider' holds both openai and ollama. There is no default on purpose — a missing value read ` +
340
+ `as 'none' is a scaffold that says "npm run dev" to someone who has nothing to connect to.`,
341
+ });
342
+ }
343
+
344
+ if (integration.outOfBand === 'none') {
345
+ const routeSources = [
346
+ ...Object.values(integration.routeTemplates),
347
+ ...(integration.webRoute ? [integration.webRoute] : []),
348
+ ];
349
+ if (integration.language === 'python') {
350
+ ctx.addIssue({
351
+ code: z.ZodIssueCode.custom,
352
+ path: ['outOfBand'],
353
+ message:
354
+ `integration '${integration.id}' claims outOfBand 'none' but its route is python, so a consumer ` +
355
+ `whose whole toolchain is node cannot run it without an interpreter and an ASGI server they ` +
356
+ `start themselves. Use 'language-runtime'.`,
357
+ });
358
+ }
359
+ if (routeSources.some((code) => SPAWNS_PROCESS.test(code))) {
360
+ ctx.addIssue({
361
+ code: z.ZodIssueCode.custom,
362
+ path: ['outOfBand'],
363
+ message:
364
+ `integration '${integration.id}' claims outOfBand 'none' but its route spawns a child process, ` +
365
+ `so the program it spawns has to be installed on the host — nothing in package.json puts it ` +
366
+ `there. Use 'local-binary'.`,
367
+ });
368
+ }
369
+ if (routeSources.some((code) => LOOPBACK_FETCH.test(code))) {
370
+ ctx.addIssue({
371
+ code: z.ZodIssueCode.custom,
372
+ path: ['outOfBand'],
373
+ message:
374
+ `integration '${integration.id}' claims outOfBand 'none' but its route fetches a loopback ` +
375
+ `address, so something local has to be listening before the first message works. ` +
376
+ `Use 'local-server'.`,
377
+ });
378
+ }
379
+ }
20
380
  });
21
381
  export type Integration = z.infer<typeof IntegrationSchema>;
22
382
 
@@ -0,0 +1,120 @@
1
+ // src/components/artifact-card.tsx
2
+ // The `artifact` built-in card: chrome + sizing around <Artifact>, plus the
3
+ // bridge from its observation callbacks onto the frozen Card Contract.
4
+ import { createUniqueId, untrack, Show, type JSX } from 'solid-js';
5
+ import type { CardHost } from '../primitives/card-contract';
6
+ import { Artifact } from './artifact';
7
+
8
+ // `ArtifactCardData` is AUTHORED IN ../primitives/card-data-types.ts, along with
9
+ // `ArtifactCardFile` — the same declaration `FileTree`/`Artifact` use, which is
10
+ // why nothing here restates the file shape. See the note in confirm-card.tsx, or
11
+ // that file's header, for why the card payload types left a `.tsx` and why they
12
+ // are `type` aliases. Re-exported here unchanged.
13
+
14
+ import type { ArtifactCardData } from '../primitives/card-data-types';
15
+
16
+ export type {
17
+ ArtifactCardData,
18
+ ArtifactCardEnvelope,
19
+ ArtifactCardFile,
20
+ ArtifactCardTab,
21
+ } from '../primitives/card-data-types';
22
+
23
+ /** Height the artifact card falls back to. Tall enough that a framed page is
24
+ * actually legible in a thread, short enough to leave the conversation visible. */
25
+ export const DEFAULT_ARTIFACT_CARD_HEIGHT = '420px';
26
+
27
+ function resolveHeight(height: number | string | undefined): string {
28
+ if (typeof height === 'number') return `${height}px`;
29
+ if (typeof height === 'string' && height.trim() !== '') return height;
30
+ return DEFAULT_ARTIFACT_CARD_HEIGHT;
31
+ }
32
+
33
+ export interface ArtifactCardProps {
34
+ data: ArtifactCardData;
35
+ cardId: string;
36
+ heading?: string;
37
+ host?: CardHost;
38
+ }
39
+
40
+ /** Chrome + sizing around `<Artifact>` for the `artifact` card type.
41
+ *
42
+ * WHY A WRAPPER IS REQUIRED, not cosmetic. `<Artifact>`'s root is
43
+ * `flex h-full w-full flex-col` — it is built to FILL a container that already
44
+ * has a height (a resizable panel, a split view). A message thread gives its
45
+ * parts no height at all, so `h-full` resolves against an auto-height parent,
46
+ * the frame computes to ZERO, and the card renders as an invisible nothing.
47
+ * The explicit `height` here is what makes the card visible; `data.height`
48
+ * overrides it.
49
+ *
50
+ * `part`/`data-card-type` are stable handles. `CardRenderer` renders card
51
+ * components bare, and in the web-component path `cardComponentsFromTags` maps a
52
+ * non-overridden built-in straight to its Solid component — so there is no
53
+ * `<kai-artifact>` tag in the DOM to point at. This wrapper is the only stable
54
+ * thing to select, which is what lets a test count rendered artifacts inside
55
+ * `<kai-thread>`'s shadow root.
56
+ *
57
+ * `part="card"` matches the other chromed cards, which get it from `<Card>`;
58
+ * this one hand-rolls its chrome and so states it directly. The artifact-specific
59
+ * handle is `data-card-type`, NOT a second part token: every `::part` name has to
60
+ * be declared in `elements/slots.ts` (the drift guard in `slots.test.ts` enforces
61
+ * it), so adding an `artifact` part is a deliberate public-API decision to make
62
+ * there, not something to smuggle in from a component.
63
+ *
64
+ * `envelope.title` renders as a HEADING above the frame rather than being folded
65
+ * into `displayUrl`: the address field states where the preview is pointing, and
66
+ * overwriting it with a title would make it lie. A heading is also what the four
67
+ * other chromed cards (form/confirm/tasks/choice) already do with `title`.
68
+ *
69
+ * `tab`/`activeFile` are SEEDS, never re-asserted — see their notes on
70
+ * `ArtifactCardData`. A revised envelope must not undo what the user did.
71
+ *
72
+ * The three observation callbacks emit the contract's EXISTING `state` verb —
73
+ * the contract is frozen, and a new kind would force a CARD_CONTRACT_VERSION
74
+ * bump. Each patch key mirrors a `data` field name, so a host can merge the
75
+ * patch straight back into `envelope.data` and re-send it; `addCard` upserts on
76
+ * `envelope.id`, so that round-trip revises the card instead of duplicating it. */
77
+ export function ArtifactCard(props: ArtifactCardProps): JSX.Element {
78
+ const headingId = createUniqueId();
79
+ // Read ONCE, non-reactively: these seed the view and must not be re-asserted
80
+ // when a revision replaces the envelope. See ArtifactCardData.activeFile.
81
+ const seedTab = untrack(() => props.data.tab);
82
+ const seedActiveFile = untrack(() => props.data.activeFile);
83
+ const patch = (p: Record<string, unknown>) =>
84
+ props.host?.emit({ kind: 'state', cardId: props.cardId, patch: p });
85
+
86
+ return (
87
+ <div
88
+ part="card"
89
+ data-card-type="artifact"
90
+ data-card-id={props.cardId}
91
+ role="group"
92
+ aria-labelledby={props.heading ? headingId : undefined}
93
+ aria-label={props.heading ? undefined : 'Artifact'}
94
+ style={{ height: resolveHeight(props.data.height) }}
95
+ class="flex w-full flex-col overflow-hidden rounded-xl border border-border bg-card"
96
+ >
97
+ <Show when={props.heading}>
98
+ <h3
99
+ id={headingId}
100
+ class="shrink-0 truncate border-b border-border px-3 py-2 text-sm font-medium text-foreground"
101
+ >
102
+ {props.heading}
103
+ </h3>
104
+ </Show>
105
+ <div class="min-h-0 flex-1">
106
+ <Artifact
107
+ src={props.data.src}
108
+ files={props.data.files}
109
+ defaultTab={seedTab}
110
+ activeFile={seedActiveFile}
111
+ displayUrl={props.data.displayUrl}
112
+ iframeTitle={props.heading ? `${props.heading} preview` : 'Artifact preview'}
113
+ onNavigate={(url) => patch({ src: url })}
114
+ onTabChange={(tab) => patch({ tab })}
115
+ onFileSelect={(path) => patch({ activeFile: path })}
116
+ />
117
+ </div>
118
+ </div>
119
+ );
120
+ }
@@ -326,6 +326,15 @@ export function AudioVisualizer(props: AudioVisualizerProps): JSX.Element {
326
326
  void load()
327
327
  .then((m) => { if (!cancelled) setShader(() => m.default); })
328
328
  .catch((err) => {
329
+ // Same `cancelled` check as the `.then` above. The two handlers were
330
+ // asymmetric: a rejection arriving after this effect was disposed
331
+ // still warned, even though there is no longer a component to fall
332
+ // back to and nothing the message could usefully tell anyone. Worse,
333
+ // the warning surfaces against whatever is running by the time the
334
+ // rejection lands rather than against the mount that asked for the
335
+ // chunk, so it reads as a fault in unrelated code -- in a test run,
336
+ // in an unrelated test.
337
+ if (cancelled) return;
329
338
  console.warn(
330
339
  `<kai-audio-visualizer variant="${v}">: failed to load the shader chunk, falling back to bars.`,
331
340
  err,