@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
@@ -0,0 +1,171 @@
1
+ import { RawOrigin, ToolPart } from '../components/tool-types.js';
2
+ import { MessagePart, MessageSource } from '../elements/chat-types.js';
3
+ import { ReasoningOpts } from '../state/parts.js';
4
+ /** One fragment of a tool call. */
5
+ export interface ModelToolCallDelta {
6
+ /**
7
+ * The ONLY thing correlating fragments, and its NAMESPACE IS FORMAT-DEFINED.
8
+ * `openaiChatFormat` uses the position in `delta.tool_calls`;
9
+ * `anthropicMessagesFormat` uses the content-block index. Both are correct and
10
+ * both are stable within one stream, but they are not the same number, so a
11
+ * third-party format must pick one and stay consistent with itself.
12
+ */
13
+ index: number;
14
+ id?: string;
15
+ /** Usually whole on the first fragment; a few providers split it. */
16
+ name?: string;
17
+ /** A FRAGMENT of the JSON arguments string, not valid JSON on its own. */
18
+ arguments?: string;
19
+ /** A result the PROVIDER executed (Anthropic web_search_tool_result, an OpenAI
20
+ * built-in). Completes the panel with no host work. */
21
+ output?: Record<string, unknown>;
22
+ /** A provider-executed tool that failed. */
23
+ outputError?: string;
24
+ }
25
+ /** Field names are deliberately provider-neutral. OpenAI says prompt/completion,
26
+ * Anthropic says input/output; input/output is the one that reads correctly for
27
+ * both. */
28
+ export interface ModelUsage {
29
+ inputTokens?: number;
30
+ outputTokens?: number;
31
+ totalTokens?: number;
32
+ /** Non-zero proves the model reasoned even when no reasoning text streamed. */
33
+ reasoningTokens?: number;
34
+ cachedInputTokens?: number;
35
+ costUsd?: number;
36
+ }
37
+ export interface ModelStreamChunk {
38
+ text?: string;
39
+ /**
40
+ * Reasoning delta. `''` is MEANINGFUL, not a no-op: a redacted block has no
41
+ * readable text but still carries a payload that must round-trip, and a format
42
+ * uses an empty delta to OPEN a reasoning part at the right position in the
43
+ * stream so block order survives into `parts`.
44
+ */
45
+ reasoning?: string;
46
+ /** The provider's BLOCK index. Keeps parallel reasoning blocks distinct.
47
+ * Omitted means block 0, the single-block case every provider degrades to. */
48
+ reasoningIndex?: number;
49
+ /**
50
+ * The UNTRANSLATED provider payload for this reasoning block. Valid on a chunk
51
+ * with NO reasoning text at all, which is the whole point: Anthropic returns
52
+ * 400 if a `thinking` block is modified, reordered or RECONSTRUCTED, so an
53
+ * encoder has to echo the original block rather than rebuild one from `text`
54
+ * plus `signature`.
55
+ */
56
+ reasoningRaw?: RawOrigin;
57
+ /** Informational. `reasoningRaw` is the round-trip channel, not this. */
58
+ reasoningSignature?: string;
59
+ toolCalls?: ModelToolCallDelta[];
60
+ /** Citations the model produced. A run of consecutive `source` parts renders
61
+ * as one citation row (`part="citations"`), outside the message bubble. */
62
+ sources?: MessageSource[];
63
+ /** Provider VERBATIM: 'stop' | 'tool_calls' | 'end_turn' | 'max_tokens' | ...
64
+ * Normalizing in place would destroy information consumers branch on. */
65
+ finishReason?: string | null;
66
+ usage?: ModelUsage;
67
+ /** An in-band provider error (the HTTP response was already 200). */
68
+ error?: {
69
+ code?: string | number;
70
+ message: string;
71
+ };
72
+ }
73
+ /** One vocabulary across formats, for code that has to BRANCH. `finishReason`
74
+ * stays beside it, verbatim, for code that has to REPORT. */
75
+ export type StopReason = 'stop' | 'length' | 'tool-calls' | 'content-filter' | 'error' | 'other';
76
+ /** Unknown reasons degrade to 'other' rather than throwing: providers add stop
77
+ * reasons without warning and a new one must not take a turn down. */
78
+ export declare function normalizeStopReason(finishReason: string | null | undefined): StopReason | undefined;
79
+ /**
80
+ * The subset of the kit's `AssistantStream` the adapter drives. Declared
81
+ * STRUCTURALLY so the adapter has no runtime dependency on a stream
82
+ * implementation and can be tested against a recorder. The kit's real
83
+ * `AssistantStream` satisfies it as-is: same method names, same arities, and its
84
+ * `AssistantStream` returns are assignable to `unknown`.
85
+ *
86
+ * `addSource` is optional so a hand-rolled three-method sink still compiles.
87
+ */
88
+ export interface AssistantStreamSink {
89
+ appendText(delta: string): unknown;
90
+ appendReasoning(delta: string, opts?: ReasoningOpts): unknown;
91
+ /** Create-or-merge. There is no separate "announce" call: handing a patch for
92
+ * an unknown `toolCallId` creates the ToolPart, and every later patch merges. */
93
+ upsertTool(toolCallId: string, patch: Partial<ToolPart>): unknown;
94
+ addSource?(source: MessageSource): unknown;
95
+ }
96
+ /** One tool call reassembled out of the stream's fragments. */
97
+ export interface ModelToolCall {
98
+ /** The delta index that correlated this call's fragments. */
99
+ index: number;
100
+ /** Provider call id (synthesised as `call_<index>` if the provider omits it). */
101
+ id: string;
102
+ name: string;
103
+ /** The RAW accumulated argument fragments. Echo THIS back on the next turn,
104
+ * not a re-stringified parse. */
105
+ argumentsText: string;
106
+ /** Parsed arguments: present only when `argumentsText` was a valid JSON object. */
107
+ input?: Record<string, unknown>;
108
+ /** Present only for a call the PROVIDER executed. */
109
+ output?: Record<string, unknown>;
110
+ /** True when the provider ran the tool and returned its result in-stream. The
111
+ * host must NOT execute these. */
112
+ providerExecuted?: boolean;
113
+ /** Why this call is unusable (malformed or truncated args, missing name). */
114
+ error?: string;
115
+ }
116
+ /** Everything one assistant turn produced. */
117
+ export interface ModelTurn {
118
+ /** The turn as ORDERED MESSAGE PARTS, built with the kit's own part builders,
119
+ * so it is exactly what the sink was driven with. Covers this turn only. */
120
+ parts: MessagePart[];
121
+ /** Flat concatenation of the text deltas. The provider wire format is a flat
122
+ * string, so this is kept for encoders. Not the content model. */
123
+ text: string;
124
+ /** Flat concatenation of the reasoning deltas, for the same reason. */
125
+ reasoning: string;
126
+ toolCalls: ModelToolCall[];
127
+ sources: MessageSource[];
128
+ /** The provider's own word for why it stopped. Never normalized. */
129
+ finishReason: string | null;
130
+ /** The same fact in one vocabulary. Branch on this. */
131
+ stopReason?: StopReason;
132
+ error?: {
133
+ code?: string | number;
134
+ message: string;
135
+ };
136
+ usage?: ModelUsage;
137
+ /** How many chunks carried a NON-EMPTY reasoning delta. Zero with a non-zero
138
+ * `usage.reasoningTokens` means the provider hid the thinking text. */
139
+ reasoningChunks: number;
140
+ chunks: number;
141
+ }
142
+ export interface ConsumeOptions {
143
+ /** Label for the reasoning disclosure. Defaults to 'Thinking'. */
144
+ reasoningLabel?: string;
145
+ /** Fires once per tool call the moment its arguments parse cleanly. This is
146
+ * the hook a host's tool loop waits on. There is deliberately no
147
+ * per-fragment callback: `ToolPart.rawInput` is written on every fragment,
148
+ * so the streaming text is already on the part. */
149
+ onToolCallReady?: (call: ModelToolCall) => void;
150
+ }
151
+ /** Per-stream state for one format. */
152
+ export interface WireFormatReader {
153
+ /**
154
+ * Map one decoded frame onto zero or more neutral chunks. Returns an ARRAY
155
+ * because the mapping is not one-to-one: an Anthropic `message_start` yields
156
+ * usage, a `content_block_start` for `tool_use` yields an id-plus-name delta,
157
+ * a `ping` yields nothing.
158
+ *
159
+ * MUST NOT throw on an unrecognized frame. Return `[]` instead: providers add
160
+ * event types without warning.
161
+ */
162
+ push(frame: unknown): ModelStreamChunk[];
163
+ }
164
+ /** A pluggable wire format. Values, not a flag, so a third party can add one
165
+ * without a PR to this repo. */
166
+ export interface WireFormat {
167
+ readonly id: string;
168
+ /** Called once per stream so a format can hold per-stream state. Two calls
169
+ * must share NOTHING. */
170
+ open(): WireFormatReader;
171
+ }
@@ -0,0 +1,26 @@
1
+ import { AssistantStreamSink, ConsumeOptions, ModelStreamChunk, ModelToolCall, ModelToolCallDelta, ModelTurn, StopReason } from './chunk.js';
2
+ /**
3
+ * Correlate tool-call fragments by `index` and drive the ToolPart lifecycle.
4
+ * THE HARD PART: `id`, `name` and each slice of `arguments` arrive across
5
+ * arbitrarily many chunks in provider-dependent order.
6
+ *
7
+ * A ToolPart is pushed (`input-streaming`) the first time a call has BOTH an id
8
+ * and a non-empty name: announcing earlier would create a panel whose `type` is
9
+ * the empty string. Everything before that is buffered and flushed at announce.
10
+ */
11
+ export declare function createToolCallAccumulator(sink: AssistantStreamSink, opts?: ConsumeOptions): {
12
+ apply: (raw: ModelToolCallDelta) => void;
13
+ settle: (stopReason: StopReason | undefined, streamError?: string) => ModelToolCall[];
14
+ };
15
+ /**
16
+ * Read one turn's worth of `ModelStreamChunk`s and drive `sink` with them.
17
+ *
18
+ * The sink is expected to be the kit's `AssistantStream`, which produces a NEW
19
+ * message object (and a new `parts` array) on every real mutation: that is what
20
+ * makes `<kai-thread>` re-render. This adapter calls the sink once per delta and
21
+ * never batches; batching is a host concern.
22
+ *
23
+ * This is also the escape hatch for a consumer who already has neutral chunks
24
+ * from somewhere else and does not need a WireFormat at all.
25
+ */
26
+ export declare function consumeModelStream(chunks: AsyncIterable<ModelStreamChunk>, sink: AssistantStreamSink, opts?: ConsumeOptions): Promise<ModelTurn>;
@@ -0,0 +1,221 @@
1
+ import { ChatMessage } from '../elements/chat-types.js';
2
+ import { MediaTypeFilter } from './media-types.js';
3
+ export interface OpenAIToolCall {
4
+ id: string;
5
+ type: 'function';
6
+ function: {
7
+ name: string;
8
+ arguments: string;
9
+ };
10
+ }
11
+ /** One `reasoning_details` entry. Provider-owned open shape, kept as a record
12
+ * for the same reason `AnthropicContentBlock` is: an opaque entry has to pass
13
+ * through UNTOUCHED, and a closed type would be a list of the fields we happen
14
+ * to have seen. */
15
+ export type OpenAIReasoningDetail = Record<string, unknown>;
16
+ /** A multimodal user message's content entries. `image_url` takes an https URL
17
+ * or a `data:` URI in the same field; `file` takes `file_data`, which is a DATA
18
+ * URI on this wire (`data:application/pdf;base64,...`) and not bare base64. */
19
+ export type OpenAIContentPart = {
20
+ type: 'text';
21
+ text: string;
22
+ } | {
23
+ type: 'image_url';
24
+ image_url: {
25
+ url: string;
26
+ };
27
+ } | {
28
+ type: 'file';
29
+ file: {
30
+ filename?: string;
31
+ file_data: string;
32
+ };
33
+ };
34
+ export interface OpenAIWireMessage {
35
+ role: 'system' | 'user' | 'assistant' | 'tool';
36
+ /** An ARRAY only when the turn carries an encodable `file` part. A text-only
37
+ * turn stays a plain string, so adding attachment support changed nothing
38
+ * about what an existing thread puts on the wire. */
39
+ content: string | OpenAIContentPart[] | null;
40
+ tool_calls?: OpenAIToolCall[];
41
+ tool_call_id?: string;
42
+ name?: string;
43
+ /** Only ever present when `toOpenAIMessages` was asked for it. See
44
+ * `OpenAIEncodeOptions.reasoning`. */
45
+ reasoning_details?: OpenAIReasoningDetail[];
46
+ }
47
+ /** EXTENDS rather than restates the file options: `onUnencodableFile` and
48
+ * `accept` mean the same thing on both wires, and a second declaration of them
49
+ * here is a second place to forget to update. */
50
+ export interface OpenAIEncodeOptions extends FileEncodeOptions {
51
+ /**
52
+ * Whether to send the assistant's own reasoning back with the thread.
53
+ *
54
+ * DEFAULT `'omit'`, and that default is a measurement, not caution. Omitting
55
+ * reasoning is accepted by every configuration tested -- five live omission
56
+ * trials plus 28 recorded live requests per configuration across the spike's
57
+ * conformance sweep, zero 400s -- so the path that ships today demonstrably
58
+ * works, while including reasoning cost about 25% more prompt tokens per round
59
+ * when measured (665 -> 834 on a two-round loop). A library does not get to
60
+ * raise every consumer's bill and add a new provider-validation surface as a
61
+ * side effect of a bug fix.
62
+ *
63
+ * `'include'` is for a multi-round TOOL loop, which is where OpenRouter says it
64
+ * pays: "when you post tool results, including the original reasoning ensures
65
+ * the model can continue its reasoning from where it left off". Measured
66
+ * accepted (HTTP 200) for a signed Anthropic block and for an OpenAI encrypted
67
+ * block, over the OpenAI-compatible wire.
68
+ *
69
+ * The Anthropic wire has no such knob because it has no such choice: a filtered
70
+ * or rebuilt thinking block there is a hard 400.
71
+ */
72
+ reasoning?: 'omit' | 'include';
73
+ }
74
+ /**
75
+ * What to do with a `file` part this wire cannot carry.
76
+ *
77
+ * DEFAULT `'throw'`, and the default is the whole point. Skipping is how
78
+ * attachments came to render perfectly in the thread and reach the model as
79
+ * nothing: the developer wires up upload, watches it work, and ships a model
80
+ * that cannot see the file. A throw here names the message, the part and the
81
+ * reason, which is strictly more than a 400 at request time would tell you.
82
+ *
83
+ * `'skip'` restores the lenient behaviour for a host that would rather send a
84
+ * degraded turn than fail one. It is silent, but it is silence the developer
85
+ * asked for by name, which is the difference that matters.
86
+ */
87
+ export type UnencodableFilePolicy = 'throw' | 'skip';
88
+ export interface FileEncodeOptions {
89
+ onUnencodableFile?: UnencodableFilePolicy;
90
+ /**
91
+ * Narrow which attachment media types reach the wire, as HTML `accept` syntax
92
+ * (`'image/*,application/pdf'`) or an array of the same.
93
+ *
94
+ * THE SAME STRING the composer takes as `<kai-chat accept="...">`, resolved by
95
+ * the same function against the same declaration -- so a developer writes the
96
+ * set once as a constant and hands it to both ends. Omitted means the kit's
97
+ * full capability set, which is `encodableMediaTypes()`.
98
+ *
99
+ * It can only NARROW. Naming a type the encoders cannot represent does not
100
+ * enable it; that would just move the failure to a provider 400.
101
+ */
102
+ accept?: MediaTypeFilter;
103
+ }
104
+ export type AnthropicEncodeOptions = FileEncodeOptions;
105
+ /** Anthropic content blocks are an open, provider-owned union. Keeping them as
106
+ * records is what lets a verbatim `thinking` payload pass through UNTOUCHED,
107
+ * which is the entire point of this encoder. */
108
+ export type AnthropicContentBlock = Record<string, unknown>;
109
+ export interface AnthropicWireMessage {
110
+ role: 'user' | 'assistant';
111
+ content: AnthropicContentBlock[];
112
+ }
113
+ /** A message cannot be encoded without losing something the provider will reject.
114
+ * Thrown at encode time, on purpose: a throw here beats a 400 at request time,
115
+ * because here you still know which message and which part caused it. */
116
+ export declare class WireEncodeError extends Error {
117
+ readonly messageId: string;
118
+ readonly partIndex: number;
119
+ constructor(message: string, messageId: string, partIndex: number);
120
+ }
121
+ /**
122
+ * ChatMessage[] to an OpenAI chat-completions `messages` array.
123
+ *
124
+ * ONE ChatMessage CAN BECOME SEVERAL WIRE MESSAGES. The kit streams a whole
125
+ * assistant turn into a single message, so text, a tool call and the model's
126
+ * answer to that call all live in one `parts` array. The OpenAI wire has no such
127
+ * shape: a `role:'tool'` result must sit between the assistant message that
128
+ * announced the call and whatever the model said afterwards. So the turn is
129
+ * SPLIT at each tool boundary, into
130
+ *
131
+ * assistant(pre-tool text + tool_calls) -> tool(result)... -> assistant(answer)
132
+ *
133
+ * Flattening instead would put the model's answer BEFORE the result it was based
134
+ * on. No endpoint rejects that, which is exactly why it is worth spelling out:
135
+ * it quietly degrades every later round of a tool loop.
136
+ *
137
+ * Consecutive tool parts stay in ONE assistant message, because parallel calls
138
+ * are announced together and their results follow together.
139
+ *
140
+ * A turn that encodes to nothing is SKIPPED, never sent as `{ content: null }`
141
+ * with no `tool_calls`: OpenAI treats `content` as required unless `tool_calls`
142
+ * is present, and strict-compatible endpoints reject it.
143
+ *
144
+ * REASONING IS OPT-IN, and off by default. OpenRouter's OpenAI-compatible
145
+ * endpoint does have a channel on the way back in -- `reasoning_details` on the
146
+ * assistant message -- and `{ reasoning: 'include' }` uses it, one entry per
147
+ * reasoning part, in part order, reassembled by `reasoningDetailOf` rather than
148
+ * echoed out of `part.raw`. Read that function for which blocks make it and why.
149
+ * The default omits, because omitting is measured-accepted everywhere and costs
150
+ * about 25% fewer prompt tokens per round; see `OpenAIEncodeOptions.reasoning`.
151
+ *
152
+ * Reasoning alone still encodes to NOTHING. A block is content the model already
153
+ * produced, not a reason to send a turn, so a message carrying reasoning and no
154
+ * text and no settled tool is skipped exactly as before, rather than becoming
155
+ * `{ content: null }` with no `tool_calls`.
156
+ *
157
+ * `card` and `source` parts are never encoded; they are kit-side.
158
+ *
159
+ * `file` parts ARE encoded, on a USER turn, and a turn carrying nothing but an
160
+ * attachment is now a real message rather than nothing. Images become
161
+ * `image_url` (https URL or `data:` URI alike); a base64 PDF becomes a `file`
162
+ * part whose `file_data` is the data URI. Two cases have no form here and THROW
163
+ * by default: a remote PDF, because this wire's `file` part has no URL variant,
164
+ * and anything that is neither -- see `UnencodableFilePolicy` for why the
165
+ * default is a throw and not a skip.
166
+ *
167
+ * A `file` part on an ASSISTANT turn is still dropped. Neither API accepts image
168
+ * or document content in an assistant message, so there is nothing to encode it
169
+ * to; attachments belong to the user turn that sent them.
170
+ */
171
+ export declare function toOpenAIMessages(messages: ChatMessage[], options?: OpenAIEncodeOptions): OpenAIWireMessage[];
172
+ /**
173
+ * ChatMessage[] to an Anthropic Messages `messages` array. THE ROUND-TRIP
174
+ * ENCODER.
175
+ *
176
+ * A reasoning block is emitted as `part.raw.payload` verbatim and is NEVER
177
+ * rebuilt from `text` plus `signature`: Anthropic returns 400 if a thinking
178
+ * block in the most recent assistant message is modified, reordered, filtered or
179
+ * reconstructed. A reasoning part with no `raw`, or with a `raw` captured from
180
+ * some other format, therefore THROWS rather than silently producing a request
181
+ * that will fail.
182
+ *
183
+ * Block order follows part order, which follows stream order, with no filtering,
184
+ * because the API validates order too. An empty-text reasoning part (an omitted
185
+ * or redacted block) is still emitted: the docs require sending back every block
186
+ * "including any blocks with empty thinking fields".
187
+ *
188
+ * ONE ChatMessage CAN BECOME SEVERAL WIRE MESSAGES, for the same reason as
189
+ * `toOpenAIMessages`: the kit streams a whole assistant turn into one message, so
190
+ * the tool call and the model's answer to it share a `parts` array, but Anthropic
191
+ * carries the result in a SEPARATE user message that has to sit between them. So
192
+ * the turn is SPLIT at each tool boundary, into
193
+ *
194
+ * assistant(pre-tool blocks + tool_use) -> user(tool_result)... -> assistant(answer)
195
+ *
196
+ * Flattening instead puts the model's answer BEFORE the result it was based on,
197
+ * and strands every later round's thinking block in the first assistant message.
198
+ * Consecutive tool parts stay in ONE assistant message, because parallel calls are
199
+ * announced together and their results come back together.
200
+ *
201
+ * Adjacent user messages are MERGED. The API combines consecutive same-role turns
202
+ * itself rather than rejecting them, so this is not what stands between you and a
203
+ * 400; it is emitted anyway because the tool-result turn and a following user turn
204
+ * are one turn, several OpenAI-compatible Anthropic proxies do enforce strict
205
+ * alternation, and the merged form is what the models are trained on. Ordering is
206
+ * safe by construction: `results` is only non-empty when `blocks` is, so a
207
+ * tool_result message always follows its assistant message and can never be
208
+ * appended after a plain user turn.
209
+ *
210
+ * `file` parts on a USER turn become `image` and `document` blocks, in part
211
+ * order. Both take `source: {type:'base64'}` and `source: {type:'url'}`, so this
212
+ * wire can carry a remote PDF that `toOpenAIMessages` has to refuse. Anything
213
+ * neither API accepts as message content THROWS by default; see
214
+ * `UnencodableFilePolicy`. A `file` part on an ASSISTANT turn is dropped, because
215
+ * an assistant message here carries only text, thinking and tool_use.
216
+ *
217
+ * Asymmetry worth knowing: `tool_use.input` is a parsed OBJECT on this wire, not
218
+ * a string, so it uses `input` and not `rawInput`. Only thinking blocks carry a
219
+ * verbatim requirement.
220
+ */
221
+ export declare function toAnthropicMessages(messages: ChatMessage[], options?: AnthropicEncodeOptions): AnthropicWireMessage[];
@@ -0,0 +1,116 @@
1
+ import { AttachmentData } from '../components/attachment-types.js';
2
+ import { MediaPolicy } from './media-types.js';
3
+ /** Where the bytes live. `base64` carries them inline; `remote` is an address
4
+ * the PROVIDER dereferences, never us. */
5
+ export type FileSource = {
6
+ type: 'base64';
7
+ mediaType: string;
8
+ data: string;
9
+ dataUri: string;
10
+ } | {
11
+ type: 'remote';
12
+ url: string;
13
+ };
14
+ /** Bytes already in hand, shaped for the provider. A union rather than an
15
+ * optional `text` field so neither encoder can reach for text that is not
16
+ * there, and so adding a kind is a compile error at both wires rather than a
17
+ * silently unhandled branch. */
18
+ export type ClassifiedFile =
19
+ /** Named for the Anthropic blocks they become. `document` is PDF-only. */
20
+ {
21
+ kind: 'image';
22
+ mediaType: string;
23
+ source: FileSource;
24
+ filename?: string;
25
+ } | {
26
+ kind: 'document';
27
+ mediaType: string;
28
+ source: FileSource;
29
+ filename?: string;
30
+ }
31
+ /** The bytes, decoded. A text file rides as TEXT CONTENT on both wires --
32
+ * neither API has an arbitrary-file block, so this is the only representation
33
+ * the wire can express, not a preference. `source` is narrowed to `base64`
34
+ * because the text has to be in hand to inline it, and fetching a remote one
35
+ * would put I/O in the encoder. */
36
+ | {
37
+ kind: 'text';
38
+ mediaType: string;
39
+ source: Extract<FileSource, {
40
+ type: 'base64';
41
+ }>;
42
+ filename?: string;
43
+ text: string;
44
+ };
45
+ export type FileClassification =
46
+ /** Ready for either wire to shape. A wire may still refuse it -- see
47
+ * OpenAI and remote PDFs -- but the attachment itself is sound. */
48
+ {
49
+ status: 'encodable';
50
+ file: ClassifiedFile;
51
+ }
52
+ /** Not an upload at all. A `source-document` is the citation chip an app
53
+ * renders next to a RAG answer, not something the user staged to send, and
54
+ * its content is already in the prompt that produced the answer. Encoding it
55
+ * would send the same text twice. */
56
+ | {
57
+ status: 'kit-side';
58
+ }
59
+ /** Cannot reach a model. `reason` completes the sentence "Cannot encode file
60
+ * part N of message X: ...", so it explains AND says what to do. */
61
+ | {
62
+ status: 'unencodable';
63
+ reason: string;
64
+ };
65
+ /**
66
+ * The text content a text attachment contributes to the prompt.
67
+ *
68
+ * ★ THE SWAP POINT for how a text file appears in a message, and the shape is
69
+ * SETTLED: `<file name="..." type="...">…</file>`. Two alternatives were weighed
70
+ * and rejected. A bare `filename:\n` prefix marks where the file BEGINS and not
71
+ * where it ends, so the next part of the turn reads as more file. An Anthropic
72
+ * `document` block would buy citations, but it is Anthropic-specific -- the
73
+ * OpenAI wire has no equivalent, so the two wires would disagree about one
74
+ * attachment -- and it needs a Files API upload round trip, which is I/O, in a
75
+ * layer that by design has none. Changing the envelope is still a change to this
76
+ * function and nothing else; it just is not an open question.
77
+ *
78
+ * ★ WHY THE BODY IS BARELY TOUCHED. Both attributes are escaped in full, as
79
+ * attributes always are. The body is not, and that is deliberate: these are
80
+ * source files, a reader will diff what they attached against what arrived, and
81
+ * XML-escaping every `<` in a TSX file would mangle the exact thing this feature
82
+ * exists to send and pay tokens to do it. So the body transform is the smallest
83
+ * one that makes the delimiter unforgeable -- the end tag, and nothing else.
84
+ *
85
+ * Left alone, that end tag is a way out of the block. A file containing `</file>`
86
+ * closes it early, and everything after that point reads to the model as the turn
87
+ * AROUND the file rather than as file content: user-supplied bytes in instruction
88
+ * position, reachable by anyone who can get a file in front of the composer.
89
+ * Escaped, it stays where it belongs. `&lt;/file&gt;` ends nothing, and it is
90
+ * visible in the output and reversible by eye, which a deletion or a silent
91
+ * substitution would not be -- a reader who spots it can say exactly what the
92
+ * original byte was. The OPENING tag is left untouched on purpose: it cannot end
93
+ * the block, and escaping it would corrupt every HTML file anyone ever attaches.
94
+ */
95
+ export declare function textFileContent(file: Extract<ClassifiedFile, {
96
+ kind: 'text';
97
+ }>): string;
98
+ /**
99
+ * One attachment to the provider-neutral facts both encoders need.
100
+ *
101
+ * A `data:` URI's OWN media type wins over `attachment.mediaType` when they
102
+ * disagree: the URI describes the bytes actually present, while the field is a
103
+ * label the host set, and it is the bytes the provider will decode. The one
104
+ * exception is a URI whose media type names nothing, where there is no answer to
105
+ * prefer -- see below.
106
+ *
107
+ * When NOTHING names the file, it is settled by DECODING it rather than by
108
+ * reading its filename. That path can only ever produce text, and only when the
109
+ * policy still allows text, so it cannot be used to get around `accept`.
110
+ *
111
+ * `policy` narrows what counts as encodable. It defaults to the kit's full
112
+ * capability set, so an omitted policy behaves exactly as before for images and
113
+ * PDFs. It is the SAME object the composer resolves for its picker -- see
114
+ * `media-types.ts` for why that sharing is the point rather than a convenience.
115
+ */
116
+ export declare function classifyAttachment(attachment: AttachmentData, policy?: MediaPolicy): FileClassification;
@@ -0,0 +1,2 @@
1
+ import { WireFormat } from '../chunk.js';
2
+ export declare const anthropicMessagesFormat: WireFormat;
@@ -0,0 +1,5 @@
1
+ import { WireFormat } from '../chunk.js';
2
+ /** Stateless: every frame is self-describing, so `open()` returns a reader with
3
+ * no closure state. The interface still calls it per stream, which is what lets
4
+ * the stateful Anthropic format use the same seam. */
5
+ export declare const openaiChatFormat: WireFormat;
@@ -0,0 +1,16 @@
1
+ export { readModelStream, readOpenAIStream, readAnthropicStream, WireError } from './read.js';
2
+ export type { StreamSource, ReadOptions } from './read.js';
3
+ export { consumeModelStream, createToolCallAccumulator } from './consume.js';
4
+ export { applyToolOutput, applyToolFailure, bufferText } from './sink-helpers.js';
5
+ export { toOpenAIMessages, toAnthropicMessages, WireEncodeError } from './encode.js';
6
+ export type { AnthropicContentBlock, AnthropicEncodeOptions, AnthropicWireMessage, FileEncodeOptions, OpenAIContentPart, OpenAIEncodeOptions, OpenAIReasoningDetail, OpenAIToolCall, OpenAIWireMessage, UnencodableFilePolicy, } from './encode.js';
7
+ export { encodableMediaTypes, resolveMediaPolicy } from './media-types.js';
8
+ export type { EncodableKind, MediaDecision, MediaPolicy, MediaPolicyOptions, MediaTypeFilter, } from './media-types.js';
9
+ export { openaiChatFormat } from './formats/openai.js';
10
+ export { anthropicMessagesFormat } from './formats/anthropic.js';
11
+ export { sseDataFrames, sseJson, readableToAsyncIterable } from './sse.js';
12
+ export type { ByteSource } from './sse.js';
13
+ export { normalizeStopReason } from './chunk.js';
14
+ export type { AssistantStreamSink, ConsumeOptions, ModelStreamChunk, ModelToolCall, ModelToolCallDelta, ModelTurn, ModelUsage, StopReason, WireFormat, WireFormatReader, } from './chunk.js';
15
+ export type { ChatMessage, MessagePart, MessageSource, RawOrigin } from '../elements/chat-types.js';
16
+ export type { ToolPart } from '../components/tool-types.js';
@@ -0,0 +1,106 @@
1
+ /** What a media type BECOMES on the wire. Named for the Anthropic block set,
2
+ * which is the narrower of the two: `text` / `image` / `document` and nothing
3
+ * else. There is no arbitrary-file block on either API, which is why a text
4
+ * file has to ride as text content and a `.zip` has no representation at all. */
5
+ export type EncodableKind = 'image' | 'document' | 'text';
6
+ /**
7
+ * The media type an unnamed file gets once its BYTES have proven to be UTF-8
8
+ * text, and the type whose presence in the effective policy is what permits that
9
+ * proof to be attempted at all.
10
+ *
11
+ * `text/plain` is not a guess dressed up as a fact. It is the media type for
12
+ * "text, no further structure claimed", which is exactly what a successful
13
+ * decode establishes and the most any decode could ever establish. A `.rs` file
14
+ * arriving as `text/plain` is true; arriving as `text/x-rust` would be the
15
+ * filename talking.
16
+ */
17
+ export declare const UNNAMED_TEXT_MEDIA_TYPE = "text/plain";
18
+ /** A developer's narrowing filter. A comma-separated string (so it works as an
19
+ * HTML attribute under the `kai-` contract) or an array (so it composes in JS).
20
+ * Both spell the same thing; the string form is what `<kai-chat accept="...">`
21
+ * takes and what the `kai` MCP scaffolder can emit as data. */
22
+ export type MediaTypeFilter = string | readonly string[];
23
+ /** One media type, decided against the effective set.
24
+ *
25
+ * `unsupported` and `filtered` are split because the developer needs different
26
+ * things from them: `unsupported` means fix your expectations (no API takes
27
+ * this), `filtered` means fix your `accept` (the kit could have sent it). */
28
+ export type MediaDecision = {
29
+ status: 'allowed';
30
+ kind: EncodableKind;
31
+ } | {
32
+ status: 'unsupported';
33
+ } | {
34
+ status: 'filtered';
35
+ }
36
+ /**
37
+ * Nobody named this file, so its media type cannot decide it. LOOK AT THE
38
+ * BYTES: decode them as UTF-8 (`classifyAttachment` does), and it is `text`
39
+ * if they decode and unencodable if they do not. Do not look at the filename.
40
+ *
41
+ * ★ THIS VARIANT IS WHERE THE DEVELOPER'S FILTER IS ENFORCED, so the caller
42
+ * cannot get it wrong by forgetting to check. It is returned ONLY when the
43
+ * effective policy still admits `text/plain` -- the one thing a decode can
44
+ * establish. Narrow `accept` to `image/png` and an unnamed file comes back
45
+ * `unsupported` instead, so the decode path is unreachable and a typeless
46
+ * `.rs` cannot slip past an images-only filter. That is the whole reason the
47
+ * check lives here rather than at each call site: there is one place to get
48
+ * right, and the callers physically cannot reach the bytes without being told
49
+ * to.
50
+ */
51
+ | {
52
+ status: 'undetermined';
53
+ };
54
+ export interface MediaPolicy {
55
+ /** The effective patterns: the kit's capability set narrowed by the
56
+ * developer's filter. Never wider than `encodableMediaTypes()`. */
57
+ readonly types: readonly string[];
58
+ /** The same set as an HTML `accept` attribute value, ready to put on an
59
+ * `<input type="file">`. This is what makes the picker and the encoder
60
+ * provably one thing rather than two lists that agree today. */
61
+ readonly accept: string;
62
+ /**
63
+ * What this policy makes of one media type, including "I cannot tell from
64
+ * this, go and read the bytes" -- see `undetermined`.
65
+ *
66
+ * The primitive behind "expose information, do not make decisions": it answers
67
+ * a question and returns a fact, so a consumer can build their own picker,
68
+ * their own validation and their own error copy on top of it without the kit
69
+ * deciding anything on their behalf.
70
+ */
71
+ decide(mediaType: string | undefined): MediaDecision;
72
+ }
73
+ export interface MediaPolicyOptions {
74
+ /** Narrow the kit's capability set. Omitted means the full set. Anything here
75
+ * that the kit cannot encode is dropped rather than honoured, because
76
+ * allowing it would only relocate the failure to the provider. */
77
+ accept?: MediaTypeFilter;
78
+ }
79
+ /** Does this media type say anything at all about the bytes it labels? Exported
80
+ * so `files.ts` decides "nameless" by the same rule `decide()` does, rather
81
+ * than growing a second opinion about which spellings mean "I don't know". */
82
+ export declare const namesNothing: (mediaType: string | undefined) => boolean;
83
+ /**
84
+ * Every media type this kit's encoders can represent, as HTML `accept` patterns.
85
+ *
86
+ * PUBLIC ON PURPOSE, and not merely for introspection: a consumer who wants
87
+ * their own picker, their own validation and their own error copy can build all
88
+ * three against this without touching `<kai-chat>` at all. That demotes the
89
+ * `accept` prop from "the only door" to a convenience over a published fact,
90
+ * which is the composition-first shape this project already committed to.
91
+ */
92
+ export declare function encodableMediaTypes(): readonly string[];
93
+ /**
94
+ * The effective policy: the kit's capability set narrowed by the developer's
95
+ * filter, plus the text ceiling.
96
+ *
97
+ * BOTH LAYERS CALL THIS. The composer calls it to build its picker `accept`
98
+ * attribute and to filter what actually gets staged; the encoders call it to
99
+ * decide what reaches the wire. That shared call is the whole design -- it is
100
+ * why changing `ENCODABLE` above moves the picker and the encoder together
101
+ * rather than moving one and leaving the other to be noticed in production.
102
+ */
103
+ export declare function resolveMediaPolicy(options?: MediaPolicyOptions): MediaPolicy;
104
+ /** The policy every caller gets when nobody narrowed anything: the kit's full
105
+ * capability set. Built once -- it has no inputs. */
106
+ export declare const DEFAULT_MEDIA_POLICY: MediaPolicy;