@kitn.ai/ui 0.20.1 → 0.21.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 (500) 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 +68 -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-D3Y5qiij.js +338 -0
  50. package/dist/create-tween-DGKY1FDY.js +341 -0
  51. package/dist/create-tween-paho5Rh-.js +7 -0
  52. package/dist/custom-elements.json +1681 -454
  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-C-2LvGDG.js} +1 -1
  70. package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-CaYoImEk.js} +1 -1
  71. package/dist/elements/chunks/arrow-left-Bb46H7w9.js +1 -0
  72. package/dist/elements/chunks/artifact-BBIscOxJ.js +1 -0
  73. package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-BB56zoji.js} +1 -1
  74. package/dist/elements/chunks/audio-visualizer-BxOx4THz.js +1 -0
  75. package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-SxLSZ19R.js} +1 -1
  76. package/dist/elements/chunks/{button-ZWNif3--.js → button-CmkUkz6c.js} +1 -1
  77. package/dist/elements/chunks/card-renderer-Db4ffkWv.js +1 -0
  78. package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
  79. package/dist/elements/chunks/chat-thread-B3Ks-cKr.js +1 -0
  80. package/dist/elements/chunks/check-C8desc_h.js +1 -0
  81. package/dist/elements/chunks/chevron-down-DKtc2HNB.js +1 -0
  82. package/dist/elements/chunks/chevron-right-Dw4GPhwL.js +1 -0
  83. package/dist/elements/chunks/choice-card-Q9cYYDyM.js +1 -0
  84. package/dist/elements/chunks/circle-BeokBsvB.js +1 -0
  85. package/dist/elements/chunks/circle-check-wJSqt859.js +1 -0
  86. package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-D0MEfxOM.js} +1 -1
  87. package/dist/elements/chunks/code-block-C8VzAraE.js +1 -0
  88. package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-Cvj61obE.js} +1 -1
  89. package/dist/elements/chunks/{composer-BguS0QL_.js → composer-D86ztyL0.js} +2 -2
  90. package/dist/elements/chunks/confirm-card-BdyDAGLw.js +1 -0
  91. package/dist/elements/chunks/context-WHDl-xSx.js +1 -0
  92. package/dist/elements/chunks/conversation-list-CdR14_Y4.js +1 -0
  93. package/dist/elements/chunks/create-tween-C_A_B638.js +7 -0
  94. package/dist/elements/chunks/{default-input-Cqqilg9t.js → default-input-CSZqUM81.js} +1 -1
  95. package/dist/elements/chunks/define-BzPnNsXg.js +1 -0
  96. package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DVKsoc1F.js} +1 -1
  97. package/dist/elements/chunks/{download-Dsbg3ste.js → download-BjA54IMJ.js} +1 -1
  98. package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-BjVVHWXH.js} +1 -1
  99. package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BNedmqfi.js} +1 -1
  100. package/dist/elements/chunks/embed-DQsl4XEq.js +1 -0
  101. package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-Di-dw2CU.js} +1 -1
  102. package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-B3sAODCV.js} +1 -1
  103. package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-Dgto-bMn.js} +1 -1
  104. package/dist/elements/chunks/{folder-glP5rha4.js → folder-D6rMadFV.js} +1 -1
  105. package/dist/elements/chunks/form-CILxvhQ7.js +1 -0
  106. package/dist/elements/chunks/hover-card-BtiF4XiU.js +1 -0
  107. package/dist/elements/chunks/{icon-BLb8beoi.js → icon-DKkmze3y.js} +1 -1
  108. package/dist/elements/chunks/{info-CIsv92JK.js → info-CWRjZkuy.js} +1 -1
  109. package/dist/elements/chunks/{input-Dds1kFyt.js → input--QJBK6BA.js} +1 -1
  110. package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-C3zuKh8R.js} +1 -1
  111. package/dist/elements/chunks/{link-i4r_k7z4.js → link-BL5JA7Q0.js} +1 -1
  112. package/dist/elements/chunks/link-preview-CU37bbXh.js +1 -0
  113. package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-XmpyxyRH.js} +1 -1
  114. package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-3Gv5UZ_o.js} +1 -1
  115. package/dist/elements/chunks/message-CnBA2OUt.js +1 -0
  116. package/dist/elements/chunks/message-X5NZbq-W.js +1 -0
  117. package/dist/elements/chunks/message-square-CnpAm_P0.js +1 -0
  118. package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-DwyrUTcM.js} +1 -1
  119. package/dist/elements/chunks/{model-switcher-B94YAKsM.js → model-switcher-CclaJEHt.js} +1 -1
  120. package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-Cepd-KcS.js} +1 -1
  121. package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CdwKjrlu.js} +1 -1
  122. package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-DMVXBD3b.js} +1 -1
  123. package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-Di_WZE_5.js} +1 -1
  124. package/dist/elements/chunks/reasoning-D0jMch5u.js +1 -0
  125. package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-1znbL1Gv.js} +1 -1
  126. package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-DVhhgx8n.js} +1 -1
  127. package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-Bs4bFS1P.js} +1 -1
  128. package/dist/elements/chunks/scroll-button-Bet5NLc4.js +1 -0
  129. package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-C5Gh8qGC.js} +1 -1
  130. package/dist/elements/chunks/{settings-B8lmec4D.js → settings-5vmEFg0K.js} +1 -1
  131. package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-BWLB38kz.js} +1 -1
  132. package/dist/elements/chunks/{share-C3lTiYGt.js → share-BZ3G_DaB.js} +1 -1
  133. package/dist/elements/chunks/skeleton-DafPJQTp.js +1 -0
  134. package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
  135. package/dist/elements/chunks/source-D_qj_6uJ.js +1 -0
  136. package/dist/elements/chunks/{star-CSJtGxgv.js → star-Cuv7j2IE.js} +1 -1
  137. package/dist/elements/chunks/{store-CHyW95TP.js → store-C1StPHfW.js} +1 -1
  138. package/dist/elements/chunks/tasks-card-EyoBZfpA.js +1 -0
  139. package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D9gRSh34.js} +1 -1
  140. package/dist/elements/chunks/textarea-DuhtHfcm.js +1 -0
  141. package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-B9hwv43w.js} +1 -1
  142. package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-Bm3DUEDe.js} +1 -1
  143. package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-CDtW7L0z.js} +1 -1
  144. package/dist/elements/chunks/tooltip-eB226mGK.js +1 -0
  145. package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C1SNzTqK.js} +1 -1
  146. package/dist/elements/chunks/use-card-resolution-YZh2MvI5.js +1 -0
  147. package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Cj1F7D0l.js} +2 -2
  148. package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-T9gpt7QE.js} +1 -1
  149. package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-CxU9z-TE.js} +2 -2
  150. package/dist/elements/chunks/{video-B7vmenoC.js → video-CK4R7Rus.js} +1 -1
  151. package/dist/elements/chunks/x-D1qx0aLd.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 +7 -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 +2 -2
  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/slots.d.ts +16 -0
  208. package/dist/elements/source.js +1 -1
  209. package/dist/elements/status.js +1 -1
  210. package/dist/elements/switch.js +1 -1
  211. package/dist/elements/tabs.js +1 -1
  212. package/dist/elements/tasks.js +1 -1
  213. package/dist/elements/text-shimmer.js +1 -1
  214. package/dist/elements/thinking-bar.js +1 -1
  215. package/dist/elements/thread.js +1 -1
  216. package/dist/elements/toast.js +1 -1
  217. package/dist/elements/tool.js +1 -1
  218. package/dist/elements/tooltip.js +1 -1
  219. package/dist/elements/validate-messages.d.ts +25 -0
  220. package/dist/elements/voice-input.js +1 -1
  221. package/dist/elements/voice-output.js +1 -1
  222. package/dist/elements.d.ts +2725 -214
  223. package/dist/index.d.ts +163 -125
  224. package/dist/index.js +6336 -5802
  225. package/dist/index.server.d.ts +5 -0
  226. package/dist/index.server.js +5446 -4937
  227. package/dist/kai-provider.es.d.ts +5 -0
  228. package/dist/kai-provider.es.js +79 -77
  229. package/dist/kai.es.d.ts +5 -0
  230. package/dist/kai.es.js +1 -1
  231. package/dist/llms/llms-full.txt +762 -148
  232. package/dist/llms/llms.txt +57 -5
  233. package/dist/mcp.es.js +4010 -770
  234. package/dist/primitives/card-component-types.d.ts +11 -0
  235. package/dist/primitives/card-data-types.d.ts +196 -0
  236. package/dist/primitives/card-host.d.ts +1 -1
  237. package/dist/primitives/card-recovery.d.ts +3 -3
  238. package/dist/primitives/card-registry.d.ts +4 -14
  239. package/dist/primitives/card-resolution.d.ts +1 -1
  240. package/dist/primitives/card-routing.d.ts +1 -1
  241. package/dist/primitives/card-tags.d.ts +11 -0
  242. package/dist/primitives/card-validate-cards.d.ts +57 -0
  243. package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
  244. package/dist/primitives/card-validate-schemas.d.ts +17 -0
  245. package/dist/primitives/card-validate.d.ts +24 -0
  246. package/dist/primitives/create-kai-chat.d.ts +3 -3
  247. package/dist/primitives/embed-providers.d.ts +1 -1
  248. package/dist/primitives/link-preview.d.ts +1 -1
  249. package/dist/primitives/message-feedback.d.ts +2 -2
  250. package/dist/primitives/toast-store.d.ts +1 -1
  251. package/dist/react/index.d.ts +717 -299
  252. package/dist/react/use-kai-chat.d.ts +8 -4
  253. package/dist/react.d.ts +5 -0
  254. package/dist/react.js +417 -316
  255. package/dist/register-impl-bzrZ44ft.js +145 -0
  256. package/dist/remote/host-embed.d.ts +1 -1
  257. package/dist/remote/index.d.ts +2 -2
  258. package/dist/remote/provider-runtime.d.ts +2 -2
  259. package/dist/remote/provider.d.ts +2 -2
  260. package/dist/remote/validate.d.ts +1 -1
  261. package/dist/remote/wire.d.ts +1 -1
  262. package/dist/schemas/artifact.schema.json +92 -0
  263. package/dist/schemas/embed.schema.json +0 -2
  264. package/dist/schemas/from-tool-call.d.ts +48 -0
  265. package/dist/schemas/index.d.ts +48 -0
  266. package/dist/schemas/link.schema.json +0 -2
  267. package/dist/schemas/provider-subsets.d.ts +136 -0
  268. package/dist/schemas/registry.d.ts +140 -0
  269. package/dist/schemas/tool-defs.d.ts +121 -0
  270. package/dist/schemas.d.ts +5 -0
  271. package/dist/schemas.js +717 -0
  272. package/dist/solid-BCJUQqwS.js +22750 -0
  273. package/dist/solid-BdENBcEq.js +20108 -0
  274. package/dist/solid.d.ts +66 -0
  275. package/dist/solid.js +261 -0
  276. package/dist/solid.server.d.ts +5 -0
  277. package/dist/solid.server.js +261 -0
  278. package/dist/state/index.d.ts +14 -4
  279. package/dist/state/messages.d.ts +8 -3
  280. package/dist/state/mock.d.ts +46 -0
  281. package/dist/state/parts.d.ts +85 -0
  282. package/dist/state/stream.d.ts +15 -9
  283. package/dist/state.d.ts +5 -0
  284. package/dist/state.js +253 -84
  285. package/dist/ui/action-icons.d.ts +1 -1
  286. package/dist/ui/collapsible.d.ts +11 -6
  287. package/dist/ui/dropdown.d.ts +47 -42
  288. package/dist/ui/pane-group.d.ts +1 -1
  289. package/dist/variant-aurora-1wMcXRUS.js +381 -0
  290. package/dist/variant-aurora-BKHHiOgL.js +391 -0
  291. package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-DOb_o4pC.js} +1 -1
  292. package/dist/{variant-custom-Dif-IV4u.js → variant-custom-CJGB0Kbw.js} +1 -1
  293. package/dist/variant-custom-Co0CkXJF.js +200 -0
  294. package/dist/variant-custom-DWSSgmd2.js +170 -0
  295. package/dist/variant-wave-C3-45cL6.js +218 -0
  296. package/dist/{variant-wave-DbfNdvSi.js → variant-wave-CEODq-9q.js} +1 -1
  297. package/dist/variant-wave-jdXBnCUZ.js +208 -0
  298. package/dist/wire/chunk.d.ts +171 -0
  299. package/dist/wire/consume.d.ts +26 -0
  300. package/dist/wire/encode.d.ts +148 -0
  301. package/dist/wire/formats/anthropic.d.ts +2 -0
  302. package/dist/wire/formats/openai.d.ts +5 -0
  303. package/dist/wire/index.d.ts +14 -0
  304. package/dist/wire/read.d.ts +26 -0
  305. package/dist/wire/sink-helpers.d.ts +21 -0
  306. package/dist/wire/sse.d.ts +33 -0
  307. package/dist/wire.d.ts +5 -53
  308. package/dist/wire.js +898 -0
  309. package/frameworks/react/index.tsx +183 -154
  310. package/frameworks/react/runtime.tsx +21 -1
  311. package/frameworks/react/use-kai-chat.tsx +11 -1
  312. package/llms-full.txt +762 -148
  313. package/llms.txt +57 -5
  314. package/package.json +61 -8
  315. package/src/agent-tooling/archetypes.ts +96 -0
  316. package/src/agent-tooling/integrations/anthropic.ts +412 -0
  317. package/src/agent-tooling/integrations/cloudflare.ts +136 -52
  318. package/src/agent-tooling/integrations/langgraph.ts +67 -13
  319. package/src/agent-tooling/integrations/mastra.ts +120 -12
  320. package/src/agent-tooling/integrations/mock.ts +43 -8
  321. package/src/agent-tooling/integrations/ollama.ts +61 -24
  322. package/src/agent-tooling/integrations/openai.ts +87 -0
  323. package/src/agent-tooling/integrations/openrouter.ts +56 -8
  324. package/src/agent-tooling/integrations/pi.ts +79 -23
  325. package/src/agent-tooling/integrations/pydantic-ai.ts +24 -2
  326. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +84 -13
  327. package/src/agent-tooling/mcp/manifest.ts +206 -25
  328. package/src/agent-tooling/mcp/tools/debug.ts +13 -7
  329. package/src/agent-tooling/mcp/tools/reference.ts +285 -6
  330. package/src/agent-tooling/mcp/tools/scaffold.ts +3345 -675
  331. package/src/agent-tooling/registry.ts +17 -0
  332. package/src/agent-tooling/types.ts +229 -1
  333. package/src/components/artifact-card.tsx +120 -0
  334. package/src/components/audio-visualizer/index.tsx +9 -0
  335. package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
  336. package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
  337. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
  338. package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
  339. package/src/components/card-fallback.tsx +42 -10
  340. package/src/components/card-renderer.tsx +146 -9
  341. package/src/components/chat-container.tsx +4 -0
  342. package/src/components/chat-thread.tsx +118 -51
  343. package/src/components/choice-card.tsx +17 -29
  344. package/src/components/composer.tsx +12 -2
  345. package/src/components/confirm-card.tsx +24 -20
  346. package/src/components/context.tsx +12 -4
  347. package/src/components/conversation-list.tsx +18 -2
  348. package/src/components/file-tree.tsx +11 -22
  349. package/src/components/file-upload.tsx +14 -8
  350. package/src/components/form.tsx +14 -47
  351. package/src/components/loader.tsx +39 -12
  352. package/src/components/message-skills.tsx +4 -0
  353. package/src/components/message.tsx +294 -46
  354. package/src/components/reasoning.tsx +92 -5
  355. package/src/components/response-compare-types.ts +25 -0
  356. package/src/components/response-compare.tsx +4 -9
  357. package/src/components/source.tsx +50 -24
  358. package/src/components/tasks-card.tsx +10 -33
  359. package/src/components/thread.tsx +84 -42
  360. package/src/components/toast.tsx +11 -5
  361. package/src/components/tool-classify.ts +26 -0
  362. package/src/components/tool-types.ts +31 -1
  363. package/src/elements/agent-card.tsx +11 -11
  364. package/src/elements/artifact.tsx +15 -7
  365. package/src/elements/attachments.tsx +6 -4
  366. package/src/elements/avatar.tsx +1 -1
  367. package/src/elements/button.tsx +3 -3
  368. package/src/elements/card.tsx +2 -2
  369. package/src/elements/cards.tsx +109 -14
  370. package/src/elements/chain-of-thought.tsx +14 -10
  371. package/src/elements/chat-scope-picker.tsx +9 -7
  372. package/src/elements/chat-types.ts +59 -6
  373. package/src/elements/chat-workspace.tsx +50 -9
  374. package/src/elements/chat.tsx +64 -3
  375. package/src/elements/choice.tsx +8 -8
  376. package/src/elements/coachmark.tsx +1 -1
  377. package/src/elements/command.tsx +8 -23
  378. package/src/elements/compare.tsx +7 -6
  379. package/src/elements/compiled.css +1 -1
  380. package/src/elements/composer.tsx +8 -8
  381. package/src/elements/confirm-card.tsx +9 -9
  382. package/src/elements/context-meter.tsx +4 -18
  383. package/src/elements/conversation-list.tsx +14 -9
  384. package/src/elements/default-input.tsx +3 -3
  385. package/src/elements/define.tsx +178 -43
  386. package/src/elements/editable-label.tsx +17 -2
  387. package/src/elements/element-data-types.ts +112 -0
  388. package/src/elements/element-meta.json +1596 -304
  389. package/src/elements/element-types.d.ts +2636 -211
  390. package/src/elements/feedback-bar.tsx +1 -1
  391. package/src/elements/file-tree.tsx +1 -1
  392. package/src/elements/file-upload.tsx +1 -1
  393. package/src/elements/form.tsx +14 -6
  394. package/src/elements/input.tsx +1 -1
  395. package/src/elements/kbd.tsx +1 -1
  396. package/src/elements/menu.tsx +10 -29
  397. package/src/elements/message-skills.tsx +7 -9
  398. package/src/elements/message.tsx +200 -32
  399. package/src/elements/model-switcher.tsx +5 -3
  400. package/src/elements/pane.tsx +1 -1
  401. package/src/elements/prompt-dock.tsx +8 -8
  402. package/src/elements/prompt-input.tsx +10 -10
  403. package/src/elements/prompt-suggestions.tsx +7 -4
  404. package/src/elements/reasoning.tsx +1 -1
  405. package/src/elements/register.ts +9 -0
  406. package/src/elements/resizable.globals.d.ts +36 -0
  407. package/src/elements/resizable.tsx +24 -13
  408. package/src/elements/response-stream.tsx +1 -1
  409. package/src/elements/scroll-button.tsx +1 -1
  410. package/src/elements/search.tsx +6 -1
  411. package/src/elements/segmented.tsx +5 -11
  412. package/src/elements/separator.tsx +1 -1
  413. package/src/elements/slots.ts +57 -24
  414. package/src/elements/source.tsx +21 -22
  415. package/src/elements/switch.tsx +3 -3
  416. package/src/elements/tasks.tsx +5 -4
  417. package/src/elements/thread.tsx +36 -4
  418. package/src/elements/toast.tsx +3 -2
  419. package/src/elements/tool.tsx +1 -1
  420. package/src/elements/validate-messages.ts +76 -0
  421. package/src/elements/voice-input.tsx +7 -7
  422. package/src/elements/voice-output.tsx +4 -4
  423. package/src/index.ts +141 -6
  424. package/src/primitives/card-component-types.ts +63 -0
  425. package/src/primitives/card-data-types.ts +312 -0
  426. package/src/primitives/card-recovery.ts +13 -2
  427. package/src/primitives/card-registry.tsx +34 -23
  428. package/src/primitives/card-schemas/artifact.schema.json +92 -0
  429. package/src/primitives/card-schemas/embed.schema.json +0 -2
  430. package/src/primitives/card-schemas/link.schema.json +0 -2
  431. package/src/primitives/card-tags.ts +61 -0
  432. package/src/primitives/card-validate-cards.ts +255 -0
  433. package/src/primitives/card-validate-generator.testlib.ts +38 -0
  434. package/src/primitives/card-validate-schemas.ts +58 -0
  435. package/src/primitives/card-validate.ts +48 -20
  436. package/src/primitives/create-tween.ts +54 -2
  437. package/src/primitives/message-feedback.ts +3 -2
  438. package/src/primitives/use-audio-analysis.ts +20 -1
  439. package/src/primitives/use-sequencer.ts +20 -1
  440. package/src/schemas/from-tool-call.ts +151 -0
  441. package/src/schemas/index.ts +340 -0
  442. package/src/schemas/provider-subsets.ts +538 -0
  443. package/src/schemas/registry.ts +355 -0
  444. package/src/schemas/tool-defs.ts +492 -0
  445. package/src/solid.ts +150 -0
  446. package/src/state/index.ts +27 -1
  447. package/src/state/messages.ts +21 -4
  448. package/src/state/mock.ts +211 -0
  449. package/src/state/parts.ts +295 -0
  450. package/src/state/stream.ts +56 -58
  451. package/src/ui/collapsible.tsx +17 -5
  452. package/src/ui/dropdown.tsx +46 -12
  453. package/src/ui/overlay.tsx +10 -4
  454. package/src/wire/chunk.ts +201 -0
  455. package/src/wire/consume.ts +440 -0
  456. package/src/wire/encode.ts +474 -0
  457. package/src/wire/formats/anthropic.ts +267 -0
  458. package/src/wire/formats/openai.ts +187 -0
  459. package/src/wire/index.ts +52 -0
  460. package/src/wire/read.ts +152 -0
  461. package/src/wire/sink-helpers.ts +50 -0
  462. package/src/wire/sse.ts +140 -0
  463. package/dist/create-tween-hvpmSuwW.js +0 -7
  464. package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
  465. package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
  466. package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
  467. package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
  468. package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
  469. package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
  470. package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
  471. package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
  472. package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
  473. package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
  474. package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
  475. package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
  476. package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
  477. package/dist/elements/chunks/define-D1din7Ld.js +0 -1
  478. package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
  479. package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
  480. package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
  481. package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
  482. package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
  483. package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
  484. package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
  485. package/dist/elements/chunks/slots--V19HwUb.js +0 -1
  486. package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
  487. package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
  488. package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
  489. package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
  490. package/dist/host-embed.d.ts +0 -33
  491. package/dist/kai-provider.d.ts +0 -2
  492. package/dist/origin.d.ts +0 -5
  493. package/dist/provider-runtime.d.ts +0 -27
  494. package/dist/register-impl-DQyejdfb.js +0 -145
  495. package/dist/validate.d.ts +0 -4
  496. package/dist/version.d.ts +0 -4
  497. package/src/components/component-meta.json +0 -4550
  498. package/src/elements/card-media.jpg +0 -0
  499. package/src/elements/resizable.d.ts +0 -27
  500. package/src/elements/video-poster.jpg +0 -0
@@ -0,0 +1,267 @@
1
+ // Anthropic Messages SSE.
2
+ //
3
+ // This format is STATEFUL. `content_block_delta` names the delta kind
4
+ // (`thinking_delta`, `input_json_delta`, ...) but not which block kind the
5
+ // fragment belongs to, so the block map is populated at `content_block_start`
6
+ // and read on every later event for that index.
7
+ //
8
+ // It is also the only format in the kit carrying a VERBATIM requirement:
9
+ // Anthropic returns 400 if a `thinking` block is modified, reordered or
10
+ // reconstructed on the way back in. The block emitted at `content_block_stop`
11
+ // is ASSEMBLED, not invented: `thinking` is the concatenation of the provider's
12
+ // own thinking_delta payloads and `signature` is the provider's signature_delta,
13
+ // so every byte came off the wire. Nothing is derived from the reasoning PART's
14
+ // text, which a consumer can edit.
15
+ //
16
+ // Three of the chunks below carry NO reasoning text (the block start, every
17
+ // signature_delta, the block stop). They depend on consume.ts gating reasoning
18
+ // on `reasoning !== undefined || reasoningRaw || reasoningSignature` rather than
19
+ // on truthiness. Under the old guard all three vanish.
20
+ import type { MessageSource } from '../../elements/chat-types';
21
+ import type { ModelStreamChunk, ModelUsage, WireFormat, WireFormatReader } from '../chunk';
22
+
23
+ function isRecord(v: unknown): v is Record<string, unknown> {
24
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
25
+ }
26
+
27
+ function str(v: unknown): string | undefined {
28
+ return typeof v === 'string' ? v : undefined;
29
+ }
30
+
31
+ function num(v: unknown): number | undefined {
32
+ return typeof v === 'number' ? v : undefined;
33
+ }
34
+
35
+ type BlockKind = 'text' | 'thinking' | 'redacted_thinking' | 'tool_use' | 'other';
36
+
37
+ interface BlockState {
38
+ kind: BlockKind;
39
+ /** Accumulated thinking_delta payloads, for the verbatim block at stop. */
40
+ thinking: string;
41
+ /** Accumulated signature_delta payloads. */
42
+ signature?: string;
43
+ }
44
+
45
+ function usageOf(raw: unknown): ModelUsage | undefined {
46
+ if (!isRecord(raw)) return undefined;
47
+ const out: ModelUsage = {};
48
+ const input = num(raw.input_tokens);
49
+ if (input !== undefined) out.inputTokens = input;
50
+ const output = num(raw.output_tokens);
51
+ if (output !== undefined) out.outputTokens = output;
52
+ const cached = num(raw.cache_read_input_tokens);
53
+ if (cached !== undefined) out.cachedInputTokens = cached;
54
+ return Object.keys(out).length > 0 ? out : undefined;
55
+ }
56
+
57
+ function blockStart(
58
+ frame: Record<string, unknown>,
59
+ blocks: Map<number, BlockState>,
60
+ toolIndexById: Map<string, number>,
61
+ ): ModelStreamChunk[] {
62
+ const index = num(frame.index) ?? 0;
63
+ const block = frame.content_block;
64
+ if (!isRecord(block)) return [];
65
+
66
+ switch (str(block.type)) {
67
+ case 'text': {
68
+ blocks.set(index, { kind: 'text', thinking: '' });
69
+ const text = str(block.text);
70
+ return text ? [{ text }] : [];
71
+ }
72
+ case 'thinking': {
73
+ const seed = str(block.thinking) ?? '';
74
+ blocks.set(index, { kind: 'thinking', thinking: seed });
75
+ // An EMPTY reasoning delta on purpose: it opens the reasoning part at the
76
+ // point in the stream where the block started, so block order in `parts`
77
+ // matches block order on the wire. The encoder round-trips that order.
78
+ return [{ reasoning: seed, reasoningIndex: index }];
79
+ }
80
+ case 'redacted_thinking': {
81
+ blocks.set(index, { kind: 'redacted_thinking', thinking: '' });
82
+ // The WHOLE block arrives here; there are no deltas and there is no
83
+ // readable text. It must still round-trip: the docs require sending back
84
+ // every block "including any blocks with empty thinking fields".
85
+ return [
86
+ {
87
+ reasoning: '',
88
+ reasoningIndex: index,
89
+ reasoningRaw: { source: 'anthropic.content_block', payload: block },
90
+ },
91
+ ];
92
+ }
93
+ case 'tool_use':
94
+ case 'server_tool_use': {
95
+ const id = str(block.id);
96
+ const name = str(block.name);
97
+ blocks.set(index, { kind: 'tool_use', thinking: '' });
98
+ if (id) toolIndexById.set(id, index);
99
+ return [{ toolCalls: [{ index, ...(id ? { id } : {}), ...(name ? { name } : {}) }] }];
100
+ }
101
+ case 'web_search_tool_result': {
102
+ // A result the PROVIDER executed. It correlates by `tool_use_id`, NOT by
103
+ // its own block index, so it is routed back to the index of the
104
+ // server_tool_use block that opened the call. With no such block the
105
+ // result has nothing to complete and is dropped rather than inventing a
106
+ // panel.
107
+ blocks.set(index, { kind: 'other', thinking: '' });
108
+ const toolUseId = str(block.tool_use_id);
109
+ const target = toolUseId !== undefined ? toolIndexById.get(toolUseId) : undefined;
110
+ if (target === undefined) return [];
111
+ const content = block.content;
112
+ if (isRecord(content) && (str(content.type) ?? '').endsWith('_error')) {
113
+ return [
114
+ {
115
+ toolCalls: [
116
+ {
117
+ index: target,
118
+ ...(toolUseId ? { id: toolUseId } : {}),
119
+ outputError: str(content.error_code) ?? 'web_search_tool_result_error',
120
+ },
121
+ ],
122
+ },
123
+ ];
124
+ }
125
+ return [
126
+ {
127
+ toolCalls: [
128
+ { index: target, ...(toolUseId ? { id: toolUseId } : {}), output: { content } },
129
+ ],
130
+ },
131
+ ];
132
+ }
133
+ default:
134
+ blocks.set(index, { kind: 'other', thinking: '' });
135
+ return [];
136
+ }
137
+ }
138
+
139
+ function blockDelta(
140
+ frame: Record<string, unknown>,
141
+ blocks: Map<number, BlockState>,
142
+ ): ModelStreamChunk[] {
143
+ const index = num(frame.index) ?? 0;
144
+ const delta = frame.delta;
145
+ if (!isRecord(delta)) return [];
146
+
147
+ switch (str(delta.type)) {
148
+ case 'text_delta': {
149
+ const text = str(delta.text);
150
+ return text ? [{ text }] : [];
151
+ }
152
+ case 'thinking_delta': {
153
+ const text = str(delta.thinking) ?? '';
154
+ const state = blocks.get(index);
155
+ if (state) state.thinking += text;
156
+ return [{ reasoning: text, reasoningIndex: index }];
157
+ }
158
+ case 'signature_delta': {
159
+ const signature = str(delta.signature) ?? '';
160
+ const state = blocks.get(index);
161
+ // Concatenated rather than assigned: a split signature must reassemble.
162
+ if (state) state.signature = (state.signature ?? '') + signature;
163
+ // No text. Carried so the part's informational `signature` is populated;
164
+ // the round-trip payload lands at content_block_stop.
165
+ return [{ reasoning: '', reasoningIndex: index, reasoningSignature: signature }];
166
+ }
167
+ case 'input_json_delta': {
168
+ return [{ toolCalls: [{ index, arguments: str(delta.partial_json) ?? '' }] }];
169
+ }
170
+ case 'citations_delta': {
171
+ const citation = delta.citation;
172
+ if (!isRecord(citation)) return [];
173
+ const source: MessageSource = {};
174
+ const url = str(citation.url);
175
+ if (url) source.url = url;
176
+ const title = str(citation.title);
177
+ if (title) source.title = title;
178
+ const snippet = str(citation.cited_text);
179
+ if (snippet) source.snippet = snippet;
180
+ return Object.keys(source).length > 0 ? [{ sources: [source] }] : [];
181
+ }
182
+ default:
183
+ return [];
184
+ }
185
+ }
186
+
187
+ function blockStop(
188
+ frame: Record<string, unknown>,
189
+ blocks: Map<number, BlockState>,
190
+ ): ModelStreamChunk[] {
191
+ const index = num(frame.index) ?? 0;
192
+ const state = blocks.get(index);
193
+ // Only a streamed `thinking` block needs assembling. `redacted_thinking`
194
+ // already emitted its whole payload at start, and text and tool blocks have
195
+ // no verbatim requirement.
196
+ if (!state || state.kind !== 'thinking') return [];
197
+ const payload: Record<string, unknown> = { type: 'thinking', thinking: state.thinking };
198
+ if (state.signature !== undefined) payload.signature = state.signature;
199
+ return [
200
+ {
201
+ reasoning: '',
202
+ reasoningIndex: index,
203
+ reasoningRaw: { source: 'anthropic.content_block', payload },
204
+ },
205
+ ];
206
+ }
207
+
208
+ function messageDelta(frame: Record<string, unknown>): ModelStreamChunk[] {
209
+ const out: ModelStreamChunk = {};
210
+ const delta = frame.delta;
211
+ if (isRecord(delta)) {
212
+ const stop = str(delta.stop_reason);
213
+ if (stop) out.finishReason = stop;
214
+ }
215
+ const usage = usageOf(frame.usage);
216
+ if (usage) out.usage = usage;
217
+ return Object.keys(out).length > 0 ? [out] : [];
218
+ }
219
+
220
+ function errorFrame(frame: Record<string, unknown>): ModelStreamChunk[] {
221
+ const err = frame.error;
222
+ const message = isRecord(err) ? str(err.message) : undefined;
223
+ const code = isRecord(err) ? str(err.type) : undefined;
224
+ return [
225
+ {
226
+ error: {
227
+ message: message ?? 'The provider sent an error frame with no message.',
228
+ ...(code ? { code } : {}),
229
+ },
230
+ },
231
+ ];
232
+ }
233
+
234
+ export const anthropicMessagesFormat: WireFormat = {
235
+ id: 'anthropic.messages',
236
+ open(): WireFormatReader {
237
+ // Per-stream state, created HERE so two open() calls share nothing.
238
+ const blocks = new Map<number, BlockState>();
239
+ const toolIndexById = new Map<string, number>();
240
+ return {
241
+ push(frame: unknown): ModelStreamChunk[] {
242
+ if (!isRecord(frame)) return [];
243
+ switch (str(frame.type)) {
244
+ case 'message_start': {
245
+ const message = frame.message;
246
+ if (!isRecord(message)) return [];
247
+ const usage = usageOf(message.usage);
248
+ return usage ? [{ usage }] : [];
249
+ }
250
+ case 'content_block_start':
251
+ return blockStart(frame, blocks, toolIndexById);
252
+ case 'content_block_delta':
253
+ return blockDelta(frame, blocks);
254
+ case 'content_block_stop':
255
+ return blockStop(frame, blocks);
256
+ case 'message_delta':
257
+ return messageDelta(frame);
258
+ case 'error':
259
+ return errorFrame(frame);
260
+ default:
261
+ // ping, message_stop, and anything Anthropic adds later.
262
+ return [];
263
+ }
264
+ },
265
+ };
266
+ },
267
+ };
@@ -0,0 +1,187 @@
1
+ // OpenAI chat-completions SSE. Also the shape every non-mock integration in the
2
+ // kit's catalog re-frames to server-side, so this one decoder covers all nine.
3
+ //
4
+ // Input is an ALREADY DECODED JSON frame typed `unknown`. Nothing here imports a
5
+ // provider SDK, and nothing here throws: a frame this format does not recognise
6
+ // yields [] so a provider adding a field cannot take a turn down.
7
+ import type { MessageSource } from '../../elements/chat-types';
8
+ import type {
9
+ ModelStreamChunk,
10
+ ModelToolCallDelta,
11
+ ModelUsage,
12
+ WireFormat,
13
+ WireFormatReader,
14
+ } from '../chunk';
15
+
16
+ function isRecord(v: unknown): v is Record<string, unknown> {
17
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
18
+ }
19
+
20
+ function str(v: unknown): string | undefined {
21
+ return typeof v === 'string' ? v : undefined;
22
+ }
23
+
24
+ function num(v: unknown): number | undefined {
25
+ return typeof v === 'number' ? v : undefined;
26
+ }
27
+
28
+ function usageOf(raw: unknown): ModelUsage | undefined {
29
+ if (!isRecord(raw)) return undefined;
30
+ const out: ModelUsage = {};
31
+ const input = num(raw.prompt_tokens);
32
+ if (input !== undefined) out.inputTokens = input;
33
+ const output = num(raw.completion_tokens);
34
+ if (output !== undefined) out.outputTokens = output;
35
+ const total = num(raw.total_tokens);
36
+ if (total !== undefined) out.totalTokens = total;
37
+ const details = raw.completion_tokens_details;
38
+ if (isRecord(details)) {
39
+ // The one number that proves reasoning happened even when no reasoning text
40
+ // was streamed back.
41
+ const reasoning = num(details.reasoning_tokens);
42
+ if (reasoning !== undefined) out.reasoningTokens = reasoning;
43
+ }
44
+ const promptDetails = raw.prompt_tokens_details;
45
+ if (isRecord(promptDetails)) {
46
+ const cached = num(promptDetails.cached_tokens);
47
+ if (cached !== undefined) out.cachedInputTokens = cached;
48
+ }
49
+ const cost = num(raw.cost);
50
+ if (cost !== undefined) out.costUsd = cost;
51
+ return Object.keys(out).length > 0 ? out : undefined;
52
+ }
53
+
54
+ function toolCallDelta(raw: unknown, position: number): ModelToolCallDelta | undefined {
55
+ if (!isRecord(raw)) return undefined;
56
+ const fn = isRecord(raw.function) ? raw.function : undefined;
57
+ const out: ModelToolCallDelta = { index: num(raw.index) ?? position };
58
+ const id = str(raw.id);
59
+ if (id) out.id = id;
60
+ const name = str(fn?.name);
61
+ if (name) out.name = name;
62
+ const args = str(fn?.arguments);
63
+ if (args !== undefined) out.arguments = args;
64
+ return out;
65
+ }
66
+
67
+ /** Sum the READABLE text across reasoning_details entries. Entries with no
68
+ * readable text (`reasoning.encrypted`, opaque signed blobs) contribute nothing
69
+ * here; they still ride along whole in `reasoningRaw`. */
70
+ function detailText(details: unknown[]): string {
71
+ let out = '';
72
+ for (const d of details) {
73
+ if (!isRecord(d)) continue;
74
+ const text = str(d.text) ?? str(d.summary);
75
+ if (text) out += text;
76
+ }
77
+ return out;
78
+ }
79
+
80
+ function detailField(details: unknown[], key: 'index' | 'signature'): unknown {
81
+ for (const d of details) {
82
+ if (isRecord(d) && d[key] !== undefined) return d[key];
83
+ }
84
+ return undefined;
85
+ }
86
+
87
+ /**
88
+ * FINDINGS: OpenRouter frequently puts the SAME text in `reasoning` AND in
89
+ * `reasoning_details` on the same delta. Concatenating both doubles every
90
+ * reasoning token, so `reasoning` wins and details are only a text FALLBACK.
91
+ *
92
+ * `reasoning_details` is still read in BOTH cases, for `reasoningRaw`, the block
93
+ * index and the signature. It is the provider's own block list, and dropping it
94
+ * is exactly the Anthropic 400 this entry exists to avoid.
95
+ */
96
+ function applyReasoning(delta: Record<string, unknown>, out: ModelStreamChunk): void {
97
+ const details = Array.isArray(delta.reasoning_details) ? delta.reasoning_details : undefined;
98
+ const primaryRaw = str(delta.reasoning);
99
+ const primary = primaryRaw !== undefined && primaryRaw !== '' ? primaryRaw : undefined;
100
+ const fallback = details ? detailText(details) : undefined;
101
+ const hasDetails = details !== undefined && details.length > 0;
102
+ const text = primary ?? fallback;
103
+ if (text === undefined && !hasDetails) return;
104
+
105
+ // '' is deliberate and meaningful: an encrypted-only detail entry has no
106
+ // readable text but must still produce a reasoning part carrying its payload.
107
+ out.reasoning = text ?? '';
108
+ if (!hasDetails) return;
109
+
110
+ out.reasoningRaw = { source: 'openai.reasoning_details', payload: details };
111
+ const index = num(detailField(details, 'index'));
112
+ if (index !== undefined) out.reasoningIndex = index;
113
+ const signature = str(detailField(details, 'signature'));
114
+ if (signature !== undefined) out.reasoningSignature = signature;
115
+ }
116
+
117
+ function sourcesOf(delta: Record<string, unknown>): MessageSource[] {
118
+ if (!Array.isArray(delta.annotations)) return [];
119
+ const out: MessageSource[] = [];
120
+ for (const a of delta.annotations) {
121
+ if (!isRecord(a)) continue;
122
+ const citation = isRecord(a.url_citation) ? a.url_citation : undefined;
123
+ const url = str(citation?.url);
124
+ if (!url) continue;
125
+ const source: MessageSource = { url };
126
+ const title = str(citation?.title);
127
+ if (title) source.title = title;
128
+ const snippet = str(citation?.content);
129
+ if (snippet) source.snippet = snippet;
130
+ out.push(source);
131
+ }
132
+ return out;
133
+ }
134
+
135
+ function pushOpenAI(frame: unknown): ModelStreamChunk[] {
136
+ if (!isRecord(frame)) return [];
137
+ const out: ModelStreamChunk = {};
138
+
139
+ const err = frame.error;
140
+ if (isRecord(err)) {
141
+ const message = str(err.message);
142
+ if (message) {
143
+ out.error = { message };
144
+ const code = err.code;
145
+ if (typeof code === 'string' || typeof code === 'number') out.error.code = code;
146
+ }
147
+ }
148
+
149
+ const usage = usageOf(frame.usage);
150
+ if (usage) out.usage = usage;
151
+
152
+ const choices = Array.isArray(frame.choices) ? frame.choices : [];
153
+ const choice = isRecord(choices[0]) ? choices[0] : undefined;
154
+ if (choice) {
155
+ const delta = isRecord(choice.delta) ? choice.delta : undefined;
156
+ if (delta) {
157
+ const content = str(delta.content);
158
+ if (content) out.text = content;
159
+
160
+ applyReasoning(delta, out);
161
+
162
+ if (Array.isArray(delta.tool_calls) && delta.tool_calls.length > 0) {
163
+ const calls = delta.tool_calls
164
+ .map((raw, i) => toolCallDelta(raw, i))
165
+ .filter((c): c is ModelToolCallDelta => c !== undefined);
166
+ if (calls.length > 0) out.toolCalls = calls;
167
+ }
168
+
169
+ const sources = sourcesOf(delta);
170
+ if (sources.length > 0) out.sources = sources;
171
+ }
172
+ const finish = str(choice.finish_reason);
173
+ if (finish) out.finishReason = finish;
174
+ }
175
+
176
+ return Object.keys(out).length > 0 ? [out] : [];
177
+ }
178
+
179
+ /** Stateless: every frame is self-describing, so `open()` returns a reader with
180
+ * no closure state. The interface still calls it per stream, which is what lets
181
+ * the stateful Anthropic format use the same seam. */
182
+ export const openaiChatFormat: WireFormat = {
183
+ id: 'openai.chat-completions',
184
+ open(): WireFormatReader {
185
+ return { push: pushOpenAI };
186
+ },
187
+ };
@@ -0,0 +1,52 @@
1
+ // @kitn.ai/ui/wire: the model-stream adapter.
2
+ //
3
+ // Separate from ./state on purpose. `state` is I/O-free pure functions over
4
+ // ChatMessage[]; `wire` touches Response, TextDecoder and byte streams. Keeping
5
+ // them apart leaves the bring-your-own-transport consumer at zero cost, and
6
+ // gives a future AG-UI format an obvious home. The cost is that importing both
7
+ // entries ships state/parts.ts twice, about 2 KB.
8
+ //
9
+ // The kit PARSES. The consumer FETCHES. There is no client, no key handling and
10
+ // no provider SDK anywhere below this file.
11
+
12
+ export { readModelStream, readOpenAIStream, readAnthropicStream, WireError } from './read';
13
+ export type { StreamSource, ReadOptions } from './read';
14
+
15
+ export { consumeModelStream, createToolCallAccumulator } from './consume';
16
+ export { applyToolOutput, applyToolFailure, bufferText } from './sink-helpers';
17
+
18
+ export { toOpenAIMessages, toAnthropicMessages, WireEncodeError } from './encode';
19
+ export type {
20
+ AnthropicContentBlock,
21
+ AnthropicWireMessage,
22
+ OpenAIEncodeOptions,
23
+ OpenAIReasoningDetail,
24
+ OpenAIToolCall,
25
+ OpenAIWireMessage,
26
+ } from './encode';
27
+
28
+ export { openaiChatFormat } from './formats/openai';
29
+ export { anthropicMessagesFormat } from './formats/anthropic';
30
+
31
+ export { sseDataFrames, sseJson, readableToAsyncIterable } from './sse';
32
+ export type { ByteSource } from './sse';
33
+
34
+ export { normalizeStopReason } from './chunk';
35
+ export type {
36
+ AssistantStreamSink,
37
+ ConsumeOptions,
38
+ ModelStreamChunk,
39
+ ModelToolCall,
40
+ ModelToolCallDelta,
41
+ ModelTurn,
42
+ ModelUsage,
43
+ StopReason,
44
+ WireFormat,
45
+ WireFormatReader,
46
+ } from './chunk';
47
+
48
+ // The content-model types every signature above mentions, re-exported so a
49
+ // consumer importing only from '@kitn.ai/ui/wire' can annotate the values these
50
+ // functions take and return without a second import.
51
+ export type { ChatMessage, MessagePart, MessageSource, RawOrigin } from '../elements/chat-types';
52
+ export type { ToolPart } from '../components/tool-types';
@@ -0,0 +1,152 @@
1
+ // The transport seam. The kit PARSES the stream; the consumer OWNS the
2
+ // transport. Auth, proxies, retries, aborts and rate limits are app decisions,
3
+ // so `StreamSource` is the entire surface: hand over a Response, a
4
+ // ReadableStream, or any async iterable of bytes or strings.
5
+ //
6
+ // Deliberately absent: retries, reconnect, Last-Event-ID, backoff, an
7
+ // AbortSignal parameter (abort the fetch), a URL-taking client, and key
8
+ // handling. Untested retry logic is worse than none.
9
+ //
10
+ // SSR: nothing here references Response or ReadableStream at module scope. A
11
+ // Response is detected by duck-typing, not `instanceof`, so this module imports
12
+ // cleanly in a runtime where the global does not exist.
13
+ import { sseJson, type ByteSource } from './sse';
14
+ import { consumeModelStream } from './consume';
15
+ import type {
16
+ AssistantStreamSink,
17
+ ConsumeOptions,
18
+ ModelStreamChunk,
19
+ ModelTurn,
20
+ WireFormat,
21
+ } from './chunk';
22
+ import { openaiChatFormat } from './formats/openai';
23
+ import { anthropicMessagesFormat } from './formats/anthropic';
24
+
25
+ export type StreamSource =
26
+ | Response
27
+ | ReadableStream<Uint8Array>
28
+ | AsyncIterable<Uint8Array | string>;
29
+
30
+ export interface ReadOptions extends ConsumeOptions {
31
+ format: WireFormat;
32
+ }
33
+
34
+ /** A non-ok HTTP response from the model endpoint, with the provider's own error
35
+ * body attached when there is one. Thrown before a single chunk is read, so a
36
+ * caller can distinguish "the request failed" from "the stream carried an
37
+ * error", which is `ModelTurn.error`. */
38
+ export class WireError extends Error {
39
+ readonly status: number;
40
+ readonly statusText: string;
41
+ /** The response body parsed as JSON, or undefined when it was not JSON (an
42
+ * HTML error page from a proxy, most often). */
43
+ readonly body: unknown;
44
+ /** The raw response body, always. */
45
+ readonly bodyText: string;
46
+
47
+ constructor(status: number, statusText: string, bodyText: string, body: unknown) {
48
+ super(buildMessage(status, statusText, bodyText, body));
49
+ // Restores the prototype chain when this class is DOWNLEVELLED to ES5 by a
50
+ // consumer's build. Without it `err instanceof WireError` is false there,
51
+ // and the documented way to tell a transport failure from an in-band error
52
+ // stops working. A no-op in the shipped ES2020+ output.
53
+ Object.setPrototypeOf(this, WireError.prototype);
54
+ this.name = 'WireError';
55
+ this.status = status;
56
+ this.statusText = statusText;
57
+ this.bodyText = bodyText;
58
+ this.body = body;
59
+ }
60
+ }
61
+
62
+ function providerMessage(body: unknown): string | undefined {
63
+ if (typeof body !== 'object' || body === null) return undefined;
64
+ const error = (body as { error?: unknown }).error;
65
+ if (typeof error === 'string') return error;
66
+ if (typeof error === 'object' && error !== null) {
67
+ const message = (error as { message?: unknown }).message;
68
+ if (typeof message === 'string') return message;
69
+ }
70
+ const top = (body as { message?: unknown }).message;
71
+ return typeof top === 'string' ? top : undefined;
72
+ }
73
+
74
+ function buildMessage(status: number, statusText: string, bodyText: string, body: unknown): string {
75
+ const head = `Model request failed: HTTP ${status}${statusText ? ` ${statusText}` : ''}`;
76
+ const provider = providerMessage(body);
77
+ if (provider) return `${head}: ${provider}`;
78
+ const snippet = bodyText.trim().slice(0, 200);
79
+ return snippet ? `${head}: ${snippet}` : head;
80
+ }
81
+
82
+ /** Duck-typed, because `Response` may not be a global in every runtime the kit
83
+ * is imported into. A ReadableStream has no `ok`, and an async iterable that
84
+ * happens to have all three of these is not a shape any transport produces. */
85
+ function isResponse(source: StreamSource): source is Response {
86
+ return (
87
+ typeof source === 'object' &&
88
+ source !== null &&
89
+ 'ok' in source &&
90
+ 'status' in source &&
91
+ 'body' in source
92
+ );
93
+ }
94
+
95
+ async function wireErrorFrom(res: Response): Promise<WireError> {
96
+ const bodyText = await res.text().catch(() => '');
97
+ let body: unknown;
98
+ try {
99
+ body = bodyText ? JSON.parse(bodyText) : undefined;
100
+ } catch {
101
+ body = undefined; // an HTML error page, or anything else non-JSON
102
+ }
103
+ return new WireError(res.status, res.statusText, bodyText, body);
104
+ }
105
+
106
+ async function toByteSource(source: StreamSource): Promise<ByteSource> {
107
+ if (!isResponse(source)) return source;
108
+ if (!source.ok) throw await wireErrorFrom(source);
109
+ if (!source.body) {
110
+ throw new Error(
111
+ 'The model response has no body to stream. Check that the request set stream: true and that nothing between you and the provider buffered it.',
112
+ );
113
+ }
114
+ return source.body;
115
+ }
116
+
117
+ /** Read one turn off the wire in `opts.format` and drive `sink` with it. */
118
+ export async function readModelStream(
119
+ source: StreamSource,
120
+ sink: AssistantStreamSink,
121
+ opts: ReadOptions,
122
+ ): Promise<ModelTurn> {
123
+ const bytes = await toByteSource(source);
124
+ // Opened ONCE per stream, which is the whole point of the open()/push() shape:
125
+ // a stateful format (Anthropic) gets a fresh block map per call.
126
+ const reader = opts.format.open();
127
+ async function* chunks(): AsyncGenerator<ModelStreamChunk> {
128
+ for await (const frame of sseJson<unknown>(bytes)) {
129
+ for (const chunk of reader.push(frame)) yield chunk;
130
+ }
131
+ }
132
+ return consumeModelStream(chunks(), sink, opts);
133
+ }
134
+
135
+ /** OpenAI chat-completions SSE. Also what all nine catalog integrations except
136
+ * `mock` re-frame to server-side, so this is the common path. */
137
+ export function readOpenAIStream(
138
+ source: StreamSource,
139
+ sink: AssistantStreamSink,
140
+ opts: ConsumeOptions = {},
141
+ ): Promise<ModelTurn> {
142
+ return readModelStream(source, sink, { ...opts, format: openaiChatFormat });
143
+ }
144
+
145
+ /** Anthropic Messages SSE. */
146
+ export function readAnthropicStream(
147
+ source: StreamSource,
148
+ sink: AssistantStreamSink,
149
+ opts: ConsumeOptions = {},
150
+ ): Promise<ModelTurn> {
151
+ return readModelStream(source, sink, { ...opts, format: anthropicMessagesFormat });
152
+ }