@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
@@ -3,7 +3,7 @@ import { FeedbackBar, type FeedbackValue, type FeedbackDetail } from '../compone
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
5
  /** The banner label (e.g. "Was this helpful?"). Attribute: `bar-title`
6
- * (`title` is avoided it's a global HTML attribute). */
6
+ * (`title` is avoided because it is a global HTML attribute). */
7
7
  barTitle?: string;
8
8
  /** When set, a not-helpful vote opens an optional detail form before the
9
9
  * thank-you confirmation. Attribute: `collect-detail`. */
@@ -4,7 +4,7 @@ import { FileTree, type FileTreeFile } from '../components/file-tree';
4
4
  interface Props extends Record<string, unknown> {
5
5
  /** The files to render. Set as a JS property (array of `{ path, url?, code?, language?, type?, additions?, deletions?, status? }`). */
6
6
  files: FileTreeFile[];
7
- /** Selected file path highlighted in the tree. */
7
+ /** Selected file path, highlighted in the tree. */
8
8
  activeFile?: string;
9
9
  /** Folder paths expanded initially. Omit to start with all folders open. */
10
10
  defaultExpanded?: string[];
@@ -7,7 +7,7 @@ interface Props extends Record<string, unknown> {
7
7
  multiple?: boolean;
8
8
  /** `accept` attribute for the file picker (e.g. `image/*`). */
9
9
  accept?: string;
10
- /** Disable the dropzone no clicking, no drag-and-drop. */
10
+ /** Disable the dropzone: no clicking, no drag-and-drop. */
11
11
  disabled?: boolean;
12
12
  /** Default dropzone label (overridable via the default slot). */
13
13
  label?: string;
@@ -3,11 +3,18 @@ import { Form, type FormController, type FormDefinition } from '../components/fo
3
3
  import type { CardResolution } from '../primitives/card-contract';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
6
- /** The form definition a JSON Schema (`type:'object'`) + `x-kai-*` UI hints
6
+ /** The form definition: a JSON Schema (`type:'object'`) + `x-kai-*` UI hints
7
7
  * (the CardEnvelope.data). Set as a JS PROPERTY: `el.data = { type:'object',
8
8
  * properties:{…} }`. Import the `FormDefinition` type from `@kitn.ai/ui` for
9
- * the full shape (it is self-referential, so the element types it loosely). */
10
- data?: Record<string, unknown>;
9
+ * the full shape.
10
+ *
11
+ * It IS self-referential (`FormField.properties` is another `FormField` map),
12
+ * and the generated `element-types.d.ts` inlines every named type, so the
13
+ * shipped declaration bottoms out in a `Record<string, unknown>` placeholder
14
+ * one level down rather than carrying the recursion. That is why
15
+ * `FormDefinition` is a `type` alias: an interface gets no implicit index
16
+ * signature, so it would not be assignable to that placeholder. */
17
+ data?: FormDefinition;
11
18
  /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */
12
19
  cardId?: string;
13
20
  /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
@@ -27,7 +34,8 @@ interface Props extends Record<string, unknown> {
27
34
  * contract event — `kai-values-change` is the live change signal, distinct from the
28
35
  * terminal submit.) */
29
36
  interface Events {
30
- /** The form's values changed on input current coerced values + validity. */
37
+ /** The form's values changed on input. Carries the current coerced values +
38
+ * validity. */
31
39
  'kai-values-change': { values: Record<string, unknown>; valid: boolean };
32
40
  }
33
41
 
@@ -56,7 +64,7 @@ defineWebComponent<Props, Events>('kai-form', {
56
64
  expose({
57
65
  /** Focus the first control, or the first INVALID control after a failed validation. */
58
66
  focus: (options?: FocusOptions) => controller?.focus(options),
59
- /** Validate + submit programmatically focus the first invalid field on failure,
67
+ /** Validate + submit programmatically: focus the first invalid field on failure,
60
68
  * else emit the `submit` CardEvent and resolve. Named `send`, not `submit`. */
61
69
  send: () => controller?.send(),
62
70
  /** Run client-side validation now and return `{ valid, errors? }` WITHOUT submitting. */
@@ -71,7 +79,7 @@ defineWebComponent<Props, Events>('kai-form', {
71
79
 
72
80
  return (
73
81
  <Form
74
- data={props.data as FormDefinition | undefined}
82
+ data={props.data}
75
83
  cardId={props.cardId ?? (element.id || 'kai-form')}
76
84
  heading={props.heading}
77
85
  resolution={props.resolution as CardResolution | undefined}
@@ -6,7 +6,7 @@ interface Props extends Record<string, unknown> {
6
6
  /** Native input type: `text` (default) · `email` · `url` · `search` · `tel` ·
7
7
  * `password` · `number`. Single-line only. */
8
8
  type?: string;
9
- /** Controlled value settable and reflected to the `value` attribute. `el.value
9
+ /** Controlled value. Settable and reflected to the `value` attribute. `el.value
10
10
  * = 'hi'` drives it (no event); typing updates it and fires `kai-input`. Read
11
11
  * `el.value` for live state. */
12
12
  value?: string;
@@ -2,7 +2,7 @@ import { defineWebComponent } from './define';
2
2
  import { Kbd, type KbdPlatform } from '../ui/kbd';
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
- /** Shortcut spec tokens joined by `+` (e.g. `Mod+Shift+K`). Omit it to show
5
+ /** Shortcut spec: tokens joined by `+` (e.g. `Mod+Shift+K`). Omit it to show
6
6
  * default-slot content instead. Display only; the element does not bind keys. */
7
7
  keys?: string;
8
8
  /** `mac` uses ⌘/⌥, `other` uses Ctrl. `auto` (default) sniffs the OS. */
@@ -11,47 +11,45 @@ import { Kbd } from '../ui/kbd';
11
11
  import { cn } from '../utils/cn';
12
12
  import { defineWebComponent } from './define';
13
13
  import { wireDisclosure } from './disclosure';
14
+ import type { KaiMenuItem } from './element-data-types';
14
15
 
15
- export interface KaiMenuItem {
16
- /** Emitted in `kai-select` for actionable items. */
17
- id?: string;
18
- label?: string;
19
- /** Named icon (e.g. "paperclip"), image URL / data-URI, or plain text. */
20
- icon?: string;
21
- /** e.g. '⌘U' — shown right-aligned, muted. */
22
- shortcut?: string;
23
- /** Presence ⇒ a checkbox item (role=menuitemcheckbox). With `radioGroup` set,
24
- * marks the SELECTED radio item in that group instead. */
25
- checked?: boolean;
26
- /** Membership in a single-select group (role=menuitemradio). Items sharing a
27
- * `radioGroup` are mutually exclusive — the one with `checked: true` shows the
28
- * checkmark; selecting one emits `{ id, radioGroup }` so the consumer moves
29
- * the checkmark (the consumer owns state, like checkbox items). */
30
- radioGroup?: string;
31
- disabled?: boolean;
32
- /** A divider (ignores other fields). */
33
- separator?: boolean;
34
- /** A non-interactive section label (uses `label`). */
35
- heading?: boolean;
36
- /** ⇒ a submenu. */
37
- items?: KaiMenuItem[];
38
- }
16
+ // The item shape lives in ./element-data-types so the ROOT entry can re-export it
17
+ // (a per-element module's shipped .d.ts is `export {};`). Re-exported here so
18
+ // `import type { KaiMenuItem } from './menu'` keeps working.
19
+ export type { KaiMenuItem } from './element-data-types';
39
20
 
40
21
  interface Props extends Record<string, unknown> {
41
- /** Tree of menu items. Set as a JS property not an HTML attribute. */
22
+ /** Tree of menu items. Set as a JS property, not an HTML attribute. */
42
23
  items?: KaiMenuItem[];
43
24
  /** Optional placement hint (unused by the underlying Dropdown which always
44
25
  * positions bottom-start, kept for future extension). */
45
26
  placement?: string;
46
27
  /** Built-in trigger: leading icon (a named icon like `"plus"`, an image
47
28
  * URL/data-URI, or text). Use this instead of slotting `slot="trigger"` for
48
- * the common case a slotted trigger overrides it. */
29
+ * the common case; a slotted trigger overrides it. */
49
30
  triggerIcon?: string;
50
- /** Built-in trigger: a text label (e.g. `"High"`). */
31
+ /** Built-in trigger: a text label (e.g. `"High"`). This is the trigger's
32
+ * VISIBLE text, so it is also its accessible name, and `label` does not
33
+ * override it: an accessible name that does not contain the visible text is
34
+ * unreachable by speech input, which is what WCAG 2.5.3 (Label in Name)
35
+ * exists for. A slotted `slot="trigger"` replaces this built-in trigger
36
+ * entirely and is named differently; see `label`. */
51
37
  triggerLabel?: string;
52
38
  /** Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). */
53
39
  triggerIconTrailing?: string;
54
- /** Accessible name for an icon-only trigger (no visible label). */
40
+ /** Accessible name for a trigger with no visible label. Ignored when
41
+ * `triggerLabel` is set, which is already the visible name.
42
+ *
43
+ * It DOES name a slotted `slot="trigger"`, and that is a difference in what
44
+ * the two slots MEAN, not a limitation. `<kai-button>`'s slot IS the button's
45
+ * label, so text slotted there is the name and `label` steps aside. This slot
46
+ * is VISUAL content, a `+` or an `<svg>`, with the name supplied separately:
47
+ * decoration beside a name, never a second name competing with one. So
48
+ * `label` names the trigger here by design.
49
+ *
50
+ * Slotting a real WORD rather than a glyph makes that word a visible label,
51
+ * and an accessible name has to contain the visible text. Then either drop
52
+ * `label` or make it contain the word you slotted. */
55
53
  label?: string;
56
54
  /** Drive/observe open state (Shoelace-style: settable + reflected to the `open`
57
55
  * attribute, the menu still self-manages on click/keyboard). Set `el.open = true`,
@@ -59,7 +57,7 @@ interface Props extends Record<string, unknown> {
59
57
  open?: boolean;
60
58
  /** Initial open state on mount (uncontrolled seed). */
61
59
  defaultOpen?: boolean;
62
- /** Disable the trigger click/keyboard and `show()` no longer open the menu. */
60
+ /** Disable the trigger: click/keyboard and `show()` no longer open the menu. */
63
61
  disabled?: boolean;
64
62
  }
65
63
 
@@ -68,8 +66,8 @@ interface Events {
68
66
  * Fired when the user selects a leaf item.
69
67
  * - Plain items: `{ id }`.
70
68
  * - Checkbox items: `{ id, checked }` where `checked` is the NEW state.
71
- * - Radio items: `{ id, radioGroup }` the consumer marks `id` as the selected
72
- * one in `radioGroup` and clears the others.
69
+ * - Radio items: `{ id, radioGroup }`, where the consumer marks `id` as the
70
+ * selected one in `radioGroup` and clears the others.
73
71
  */
74
72
  'kai-select': { id: string; checked?: boolean; radioGroup?: string };
75
73
  /** The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). */
@@ -201,7 +199,17 @@ defineWebComponent<Props, Events>('kai-menu', {
201
199
  ? 'gap-1.5 px-2 py-1.5 text-sm font-medium text-muted-foreground hover:bg-accent hover:text-foreground'
202
200
  : 'justify-center p-1.5 text-foreground hover:bg-muted',
203
201
  )}
204
- aria-label={props.label ?? (props.triggerLabel ? undefined : 'Open menu')}
202
+ // A visible `triggerLabel` IS the name (name-from-contents reaches the
203
+ // slotted/shadow text), so `label` must not be layered over it: aria-label
204
+ // REPLACES the computed name, and a trigger reading "High" that answers to
205
+ // "Reasoning effort" locks speech-input users out (WCAG 2.5.3). Same rule
206
+ // kai-checkpoint and kai-button follow.
207
+ //
208
+ // A SLOTTED trigger keeps `label`, and that is the contract rather than a
209
+ // gap: kai-button's slot IS the label, so text there is the name; this
210
+ // slot is visual content with the name supplied separately. Two slots,
211
+ // two meanings, so the same rule should not apply to both. See `label`.
212
+ aria-label={props.triggerLabel ? undefined : (props.label ?? 'Open menu')}
205
213
  >
206
214
  {/* Slotted trigger wins; otherwise build one from the trigger* props;
207
215
  otherwise fall back to a "more" glyph. */}
@@ -1,17 +1,15 @@
1
1
  import { createSignal, onCleanup, onMount } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
- import { MessageSkills } from '../components/message-skills';
3
+ // The badge shape is the Solid component's own `Skill` — one declaration, so the
4
+ // element and `<MessageSkills>` cannot drift, and the ROOT entry re-exports it.
5
+ import { MessageSkills, type Skill } from '../components/message-skills';
4
6
 
5
- interface Skill {
6
- /** Stable identifier for the skill. */
7
- id: string;
8
- /** Human-readable skill name shown on the badge. */
9
- name: string;
10
- }
11
7
 
12
8
  interface Props extends Record<string, unknown> {
13
- /** The active skills to badge. Set as a JS property. */
14
- skills: Skill[];
9
+ /** The active skills to badge. Set as a JS property. Omit to supply them as
10
+ * `<kai-skill>` light-DOM children instead; when both are present the
11
+ * property's skills come first. Nothing renders when there are none. */
12
+ skills?: Skill[];
15
13
  }
16
14
 
17
15
  /**
@@ -1,18 +1,76 @@
1
- import { Show, createSignal, onMount, onCleanup } from 'solid-js';
1
+ import { Show, createSignal, createEffect, onMount, onCleanup, type JSX } from 'solid-js';
2
+ import { Dynamic } from 'solid-js/web';
2
3
  import { defineWebComponent } from './define';
3
4
  import { readSlots, MESSAGE_SLOTS } from './slots';
4
5
  import { ChatConfig, useChatConfig, type ProseSize } from '../primitives/chat-config';
5
6
  import { Message, MessageAvatar, MessageBody } from '../components/message';
6
7
  import { createMessageFeedback } from '../primitives/message-feedback';
8
+ import {
9
+ mergeCardTags,
10
+ BUILTIN_CARD_TAGS,
11
+ BUILTIN_CARD_COMPONENTS,
12
+ type CardTagMap,
13
+ type CardComponentMap,
14
+ } from '../primitives/card-registry';
15
+ import type { CardEnvelope } from '../primitives/card-contract';
16
+ import { hasParts } from './validate-messages';
7
17
  import type { ChatMessage } from './chat-types';
8
18
 
19
+ /**
20
+ * Bridges the web-component-facing `cardTypes` (envelope type -> custom-element
21
+ * TAG name, e.g. `{ 'my-widget': 'my-widget-el' }`) into the `CardComponentMap`
22
+ * that `MessageBody`/`Thread` expect. A type the consumer did NOT override keeps
23
+ * rendering its built-in Solid component directly (no extra custom-element
24
+ * indirection); an overridden built-in or a brand-new consumer type renders as a
25
+ * dynamically-created custom element instead, mirroring `<kai-cards>`'s
26
+ * `CardSlot`. A type with no tag at all (unregistered) simply gets no entry, so
27
+ * `CardRenderer`'s own fallback (`CardFallback`) takes over.
28
+ */
29
+ export function cardComponentsFromTags(types?: CardTagMap, theme = 'auto'): CardComponentMap {
30
+ const tags = mergeCardTags(types);
31
+ const map: CardComponentMap = {};
32
+ for (const type of Object.keys(tags)) {
33
+ const tag = tags[type];
34
+ map[type] = tag === BUILTIN_CARD_TAGS[type] && BUILTIN_CARD_COMPONENTS[type]
35
+ ? BUILTIN_CARD_COMPONENTS[type]
36
+ : (p) => <CardTagSlot tag={tag} envelope={p.envelope} theme={theme} />;
37
+ }
38
+ return map;
39
+ }
40
+
41
+ /** Renders one envelope as a dynamically-created custom element, setting the
42
+ * envelope's data/id/title/resolution as DOM properties (reactive) plus the
43
+ * `theme` + `data-card-id` chrome, mirroring `<kai-cards>`'s `CardSlot` so a
44
+ * custom card behaves identically whether it arrives via `<kai-cards>` or a
45
+ * `card` message part here. */
46
+ function CardTagSlot(props: { tag: string; envelope: CardEnvelope; theme: string }): JSX.Element {
47
+ let ref: HTMLElement | undefined;
48
+ createEffect(() => {
49
+ if (!ref) return;
50
+ (ref as unknown as { data: unknown }).data = props.envelope.data;
51
+ (ref as unknown as { cardId: string }).cardId = props.envelope.id;
52
+ if (props.envelope.title != null) (ref as unknown as { heading: string }).heading = props.envelope.title;
53
+ (ref as unknown as { resolution: unknown }).resolution = props.envelope.resolution;
54
+ ref.setAttribute('theme', props.theme);
55
+ ref.setAttribute('data-card-id', props.envelope.id);
56
+ });
57
+ return <Dynamic component={props.tag} ref={ref} />;
58
+ }
59
+
9
60
  interface Props extends Record<string, unknown> {
10
61
  /** The full message object. Set as a JS property. */
11
62
  message?: ChatMessage;
12
- /** Convenience for simple cases when not passing a `message` object. */
63
+ /** Who is speaking: `'user'` or `'assistant'`. Convenience for simple cases when
64
+ * not passing a `message` object.
65
+ *
66
+ * This is the SEMANTIC role of the message, not an ARIA role. The name collides
67
+ * with the global ARIA `role` attribute, which is why the facade lifts it off
68
+ * the host (see `liftRoleOffHost`). Neither speaker is a valid ARIA role,
69
+ * so a `role="user"` left on `<kai-message>` is a CRITICAL axe `aria-roles`
70
+ * violation. The accessible role lives on the row inside the shadow root
71
+ * instead: `role="article"` plus an `aria-label` naming the speaker, matching
72
+ * the SolidJS `<Message>` component. */
13
73
  role?: 'user' | 'assistant';
14
- /** Convenience content (used when `message` is not set). */
15
- content?: string;
16
74
  /** Force markdown on/off. Defaults to on for assistant, off for user. */
17
75
  markdown?: boolean;
18
76
  /** Text/markdown sizing for the message body. */
@@ -33,6 +91,65 @@ interface Props extends Record<string, unknown> {
33
91
  * value keeps the default behaviour: the built-in avatar when one resolves, or
34
92
  * your `slot="avatar"` content when projected (which REPLACES the built-in). */
35
93
  avatar?: 'none' | string;
94
+ /** Optional card type -> custom-element tag overrides/additions for `card`
95
+ * parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a
96
+ * plain string map (not the `CardTagMap` alias) so the generated React
97
+ * wrapper inlines it instead of emitting an unresolved named type. */
98
+ cardTypes?: Record<string, string>;
99
+ /** JSON Schemas for the card types this app renders, keyed by envelope type. The
100
+ * companion of `cardTypes`, which says what DRAWS a card while this says what a
101
+ * VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas
102
+ * = { 'pricing-table': pricingSchema }`, never an attribute.
103
+ * `createCardRegistry(...).validationSchemas` is exactly this shape.
104
+ *
105
+ * Without it the kit validates its own seven built-ins and leaves your own card
106
+ * type, the one your app actually cares about, as the only unchecked thing on
107
+ * screen. A schema here WINS over a built-in of the same name.
108
+ *
109
+ * Typed `Record<string, object>` rather than `Record<string, JsonSchema>`
110
+ * deliberately: an imported `.json` schema widens `"type"` to `string`, and an
111
+ * authored one carries `$schema`/`title`/`description`/`additionalProperties`,
112
+ * so the tighter type would reject both of the normal ways to supply one. */
113
+ cardSchemas?: Record<string, object>;
114
+ }
115
+
116
+ /**
117
+ * Move a `role` the consumer put on the host into the element's own prop store,
118
+ * and off the DOM.
119
+ *
120
+ * `role` names the SPEAKER here (`'user'` / `'assistant'`) — the correct domain
121
+ * word, and the documented attribute — but it is also the global ARIA `role`
122
+ * attribute, and neither speaker is a valid ARIA role. Measured in a real chromium:
123
+ * a host left carrying `role="user"` is a CRITICAL axe `aria-roles` violation
124
+ * ("Role must be one of the valid ARIA roles: user"), and chromium discards the
125
+ * unknown token and computes `generic`, so the row is left with no accessible role
126
+ * and no accessible name rather than a mis-announced one.
127
+ *
128
+ * Capture the value, remove the attribute, then write it back as a PROPERTY.
129
+ * component-register's prop accessors do not reflect, so the write cannot put it
130
+ * back on the DOM, and it feeds the same reactive prop the facade already reads.
131
+ *
132
+ * The ORDER is load-bearing: `removeAttribute` fires component-register's
133
+ * `attributeChangedCallback` with `null`, which sets the property to `null`. The
134
+ * write-back has to come after that, or the scrub destroys the speaker it was
135
+ * meant to preserve.
136
+ *
137
+ * NOTE — this covers every path where the attribute is still on the host by the
138
+ * time the facade runs (`setAttribute` before or after connection, and any later
139
+ * change, via the observer below). It does NOT cover an element authored in HTML
140
+ * and upgraded at registration time: `defineWebComponent` installs its
141
+ * non-reflecting `role` accessor AFTER `customElements.define()`, so for elements
142
+ * already in the document the native ARIAMixin setter runs first in the constructor
143
+ * (`this[prop] = undefined` → `role` is a nullable reflected IDL attribute →
144
+ * `removeAttribute`) and the value is gone before any of this code executes. That
145
+ * is a separate defect in `src/elements/define.tsx`, not something the facade can
146
+ * reach; this function composes correctly with the fix once it lands.
147
+ */
148
+ function liftRoleOffHost(element: HTMLElement): void {
149
+ const attr = element.getAttribute('role');
150
+ if (attr === null) return;
151
+ element.removeAttribute('role');
152
+ (element as unknown as { role?: string }).role = attr;
36
153
  }
37
154
 
38
155
  /** Events fired by `<kai-message>`. */
@@ -52,7 +169,6 @@ interface Events {
52
169
  defineWebComponent<Props, Events>('kai-message', {
53
170
  message: undefined,
54
171
  role: 'assistant',
55
- content: undefined,
56
172
  markdown: undefined,
57
173
  proseSize: 'sm',
58
174
  codeTheme: 'github-dark-dimmed',
@@ -61,10 +177,39 @@ defineWebComponent<Props, Events>('kai-message', {
61
177
  avatarSrc: undefined,
62
178
  avatarFallback: undefined,
63
179
  avatar: undefined,
180
+ cardTypes: undefined,
181
+ cardSchemas: undefined,
64
182
  }, (props, { dispatch, flag, element, expose }) => {
65
183
  const outer = useChatConfig();
184
+ // Do this FIRST, before anything reads `props.role`: it rewrites that prop as a
185
+ // side effect of taking the invalid ARIA role off the host.
186
+ liftRoleOffHost(element);
66
187
  const msg = (): ChatMessage =>
67
- props.message ?? { id: 'message', role: props.role ?? 'assistant', content: props.content ?? '' };
188
+ props.message ?? {
189
+ id: 'message',
190
+ role: props.role ?? 'assistant',
191
+ parts: [],
192
+ };
193
+ // `message` is an untyped boundary: a consumer can hand it anything at
194
+ // runtime (a pre-0.20.0 `{ id, role, content }` object, in particular).
195
+ // `parts` is a REQUIRED field, so validate it here rather than let
196
+ // `MessageBody`/`groupMessageParts` throw deep inside a Solid render pass;
197
+ // an uncaught exception there blanks the whole element instead of just this
198
+ // one message. Warn once per bad message (not on every unrelated re-render)
199
+ // and render nothing for it, matching the old pre-parts fallback behavior
200
+ // (an unusable message rendered an empty body, not a crash).
201
+ let lastWarnedMessage: unknown;
202
+ const hasValidParts = (): boolean => {
203
+ const m = msg();
204
+ if (hasParts(m)) return true;
205
+ if (m !== lastWarnedMessage) {
206
+ lastWarnedMessage = m;
207
+ console.error(
208
+ "<kai-message>: 'message' must have a 'parts' array. The 'content' string field was removed in 0.20.0.",
209
+ );
210
+ }
211
+ return false;
212
+ };
68
213
  // Copy + vote state lives here (above the rendered body) so it survives a
69
214
  // re-render when the host swaps in a fresh `message` object during streaming.
70
215
  const feedback = createMessageFeedback({
@@ -82,7 +227,7 @@ defineWebComponent<Props, Events>('kai-message', {
82
227
  // `kai-message-action{action:'copy'}`.
83
228
  expose({
84
229
  /** Copy the message content to the clipboard and show the copied check. */
85
- copy: () => feedback.handleAction(msg(), 'copy'),
230
+ copy: () => { if (hasValidParts()) feedback.handleAction(msg(), 'copy'); },
86
231
  });
87
232
 
88
233
  // Read declarative <kai-action> children from light DOM.
@@ -106,6 +251,16 @@ defineWebComponent<Props, Events>('kai-message', {
106
251
  observer.observe(element, { childList: true, attributes: true, subtree: true });
107
252
  onCleanup(() => observer.disconnect());
108
253
  });
254
+ // A consumer can set `role` at any point after the element is live
255
+ // (`el.setAttribute('role', 'user')`), which puts the invalid ARIA role back on
256
+ // the host. Keep lifting it off. Scoped to the one attribute so this cannot be
257
+ // mistaken for general attribute handling; no loop, because the write-back is a
258
+ // property and the removal leaves nothing for the next callback to find.
259
+ onMount(() => {
260
+ const roleObserver = new MutationObserver(() => liftRoleOffHost(element));
261
+ roleObserver.observe(element, { attributes: true, attributeFilter: ['role'] });
262
+ onCleanup(() => roleObserver.disconnect());
263
+ });
109
264
  const isUser = () => msg().role === 'user';
110
265
  const avatar = () =>
111
266
  msg().avatar ??
@@ -127,10 +282,9 @@ defineWebComponent<Props, Events>('kai-message', {
127
282
  const mergedActions = () => [...(msg().actions ?? []), ...slottedActions()];
128
283
  const body = () => (
129
284
  <MessageBody
130
- content={msg().content}
131
- reasoning={msg().reasoning}
132
- tools={msg().tools}
133
- attachments={msg().attachments}
285
+ parts={msg().parts}
286
+ cardTypes={cardComponentsFromTags(props.cardTypes, (props as { theme?: string }).theme)}
287
+ cardSchemas={props.cardSchemas}
134
288
  isUser={isUser()}
135
289
  markdown={useMarkdown()}
136
290
  actions={mergedActions()}
@@ -165,27 +319,41 @@ defineWebComponent<Props, Events>('kai-message', {
165
319
  );
166
320
 
167
321
  return (
168
- <ChatConfig
169
- proseSize={props.proseSize}
170
- codeTheme={props.codeTheme}
171
- codeHighlight={flag('codeHighlight')}
172
- portalMount={outer.portalMount()}
173
- >
174
- <Show
175
- when={showRail()}
176
- fallback={
177
- <Message class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}>
178
- {body()}
179
- </Message>
180
- }
322
+ // No fallback: an invalid `message` (missing `parts`) renders nothing for
323
+ // this element rather than crashing. `hasValidParts()` already logged why.
324
+ <Show when={hasValidParts()}>
325
+ <ChatConfig
326
+ proseSize={props.proseSize}
327
+ codeTheme={props.codeTheme}
328
+ codeHighlight={flag('codeHighlight')}
329
+ portalMount={outer.portalMount()}
181
330
  >
182
- <Message class={rowGroup()}>
183
- {avatarRail()}
184
- <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
185
- {body()}
186
- </div>
187
- </Message>
188
- </Show>
189
- </ChatConfig>
331
+ <Show
332
+ when={showRail()}
333
+ fallback={
334
+ // `role` here is `<Message>`'s SPEAKER prop, not an ARIA role: the
335
+ // component turns it into `role="article"` + an `aria-label` naming the
336
+ // speaker, so the row an assistive technology sees has a valid role and
337
+ // a name. This is the same treatment the SolidJS `<Message>` gets when
338
+ // used directly — the facade just always knows its speaker, so unlike
339
+ // the bare component (where `role` is optional and usually omitted) the
340
+ // row is never left unlabelled.
341
+ <Message
342
+ role={msg().role}
343
+ class={`${rowGroup()}${isUser() ? 'flex-col items-end' : 'flex-col items-start'}`}
344
+ >
345
+ {body()}
346
+ </Message>
347
+ }
348
+ >
349
+ <Message role={msg().role} class={rowGroup()}>
350
+ {avatarRail()}
351
+ <div class={`flex min-w-0 flex-1 flex-col ${isUser() ? 'items-end' : 'items-start'}`}>
352
+ {body()}
353
+ </div>
354
+ </Message>
355
+ </Show>
356
+ </ChatConfig>
357
+ </Show>
190
358
  );
191
359
  });
@@ -6,8 +6,10 @@ import type { DropdownController } from '../ui/dropdown';
6
6
  import type { ModelOption } from '../types';
7
7
 
8
8
  interface Props extends Record<string, unknown> {
9
- /** The selectable models. Set as a JS property (array). */
10
- models: ModelOption[];
9
+ /** The selectable models. Set as a JS property (array). Omit to supply them as
10
+ * `<kai-model>` light-DOM children instead; when both are present the
11
+ * property's models come first. */
12
+ models?: ModelOption[];
11
13
  /** The currently-selected model id. Defaults to the first model. */
12
14
  currentModel?: string;
13
15
  /** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
@@ -16,7 +18,7 @@ interface Props extends Record<string, unknown> {
16
18
  open?: boolean;
17
19
  /** Initial open state on mount (uncontrolled seed). */
18
20
  defaultOpen?: boolean;
19
- /** Disable the trigger click/keyboard and `show()` no longer open the dropdown. */
21
+ /** Disable the trigger: click/keyboard and `show()` no longer open the dropdown. */
20
22
  disabled?: boolean;
21
23
  }
22
24
 
@@ -31,7 +31,7 @@ interface Props extends Record<string, unknown> {
31
31
  /** Events fired by `<kai-pane>`. All non-bubbling — listen on the element. */
32
32
  interface Events {
33
33
  /** The maximize/restore control was clicked. `detail.maximized` is the
34
- * intended NEXT state drive the `maximized` prop yourself from it. */
34
+ * intended NEXT state. Drive the `maximized` prop yourself from it. */
35
35
  'kai-maximize': { maximized: boolean };
36
36
  /** The close (×) control was clicked. */
37
37
  'kai-close': void;
@@ -3,15 +3,15 @@ import { defineWebComponent } from './define';
3
3
  import { PromptDock, type PromptDockAppearance, type PromptDockFrame } from '../ui/prompt-dock';
4
4
 
5
5
  interface Props extends Record<string, unknown> {
6
- /** How the tray frames the input the SPATIAL inset axis: `inset` (default,
7
- * the classic recessed frame on every side) | `edge` (top/bottom inset only;
8
- * the input sits flush left/right so the lips span the full width) | `none`
9
- * (no inset; the lips attach directly as a plain stack). Attribute: `frame`. */
6
+ /** How the tray frames the input, the SPATIAL inset axis: `inset` (default, the
7
+ * classic recessed frame on every side) | `edge` (top/bottom inset only; the
8
+ * input sits flush left/right so the lips span the full width) | `none` (no
9
+ * inset; the lips attach directly as a plain stack). Attribute: `frame`. */
10
10
  frame?: PromptDockFrame;
11
- /** How the tray surface looks the VISUAL axis, orthogonal to `frame`:
12
- * `soft` (default, sunken surface + border + radius) | `outlined`
13
- * (transparent + border + radius) | `filled` (sunken, no border, + radius) |
14
- * `plain` (bare). Attribute: `appearance`. */
11
+ /** How the tray surface looks, the VISUAL axis orthogonal to `frame`: `soft`
12
+ * (default, sunken surface + border + radius) | `outlined` (transparent +
13
+ * border + radius) | `filled` (sunken, no border, + radius) | `plain`
14
+ * (bare). Attribute: `appearance`. */
15
15
  appearance?: PromptDockAppearance;
16
16
  }
17
17
 
@@ -37,9 +37,9 @@ interface Props extends Record<string, unknown> {
37
37
  * button (square icon, "Stop" aria-label). Clicking it fires `kai-stop`. */
38
38
  stoppable?: boolean;
39
39
  /** Send-button visibility. `'always'` (default) always shows it; `'auto'` shows
40
- * it only when there's text/attachments (an empty composer hides it — Enter
41
- * still submits). To hide it entirely (Enter-only), it's pure CSS:
42
- * `::part(send){display:none}` no prop needed. Restyle via `::part(send)`.
40
+ * it only when there's text/attachments (an empty composer hides it, though
41
+ * Enter still submits). To hide it entirely (Enter-only), it's pure CSS:
42
+ * `::part(send){display:none}`, no prop needed. Restyle via `::part(send)`.
43
43
  * The Stop button (`stoppable` + `loading`) is unaffected. */
44
44
  submit?: 'always' | 'auto';
45
45
  /** When `false`, hides the built-in paperclip attach button even though the
@@ -51,9 +51,9 @@ interface Props extends Record<string, unknown> {
51
51
  * files without an upload). Set as a JS property; the element then manages its
52
52
  * own attachment state from there (add via the paperclip, remove per chip). */
53
53
  attachments?: AttachmentData[];
54
- /** Rich entity triggers each `{ char, kind, items }` opens a caret-anchored
55
- * menu that inserts an atomic pill. Convention: `/` → skills, `@` → agents
56
- * (plugins are the grouping/provenance of those items). Set as a JS property. */
54
+ /** Rich entity triggers. Each `{ char, kind, items }` opens a caret-anchored menu
55
+ * that inserts an atomic pill. Convention: `/` → skills, `@` → agents (plugins
56
+ * are the grouping/provenance of those items). Set as a JS property. */
57
57
  triggers?: TriggerDef[];
58
58
  /** Default icon per entity kind (kind → image URL/data-URI) for pills/menu items
59
59
  * without their own `icon`. Overrides the built-in agent/plugin glyphs. JS property. */
@@ -69,7 +69,7 @@ interface Events {
69
69
  /** The input changed (fires on every edit). Carries the flattened `value`
70
70
  * plus the structured `doc` + `entities`. */
71
71
  'kai-value-change': { value: string; doc: ComposerDoc; entities: EntityRef[] };
72
- /** The staged attachments changed a file was added (via the paperclip) or
72
+ /** The staged attachments changed: a file was added (via the paperclip) or
73
73
  * removed (per-chip ×). Carries the full current list so a consumer can react
74
74
  * in real time (validate, show upload progress, toggle the send button). */
75
75
  'kai-attachments-change': { attachments: AttachmentData[] };
@@ -198,9 +198,9 @@ defineWebComponent<Props, Events>('kai-prompt-input', {
198
198
  handleChange('');
199
199
  if (attachments().length) { setAttachments([]); dispatch('kai-attachments-change', { attachments: [] }); }
200
200
  },
201
- /** Send the current value programmatically same path as Enter / the send
202
- * button (fires kai-submit, then clears staged attachments). Named `send`,
203
- * not `submit`, to avoid colliding with the `submit` prop. */
201
+ /** Send the current value programmatically, on the same path as Enter / the
202
+ * send button (fires kai-submit, then clears staged attachments). Named
203
+ * `send`, not `submit`, to avoid colliding with the `submit` prop. */
204
204
  send: () => handleSubmit(),
205
205
  });
206
206