@kitn.ai/ui 0.20.0 → 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 +16913 -0
  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 +65 -7
  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
@@ -4,12 +4,15 @@
4
4
  // `kai-card` events through an optional `policy`. The raw events keep bubbling past
5
5
  // <kai-cards> (composed) so document-level listeners still work. Unknown types render
6
6
  // the Solid CardFallback inline and emit a contract `error`.
7
- import { For, Show, createEffect, createSignal, on, onCleanup, onMount, type JSX } from 'solid-js';
7
+ import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount, type JSX } from 'solid-js';
8
8
  import { Dynamic } from 'solid-js/web';
9
9
  import { defineWebComponent } from './define';
10
10
  import type { CardEnvelope, CardEvent, CardPolicy, CardResolution } from '../primitives/card-contract';
11
11
  import { CARD_EVENT_NAME, emitCardEvent, routeCardEvent } from '../primitives/card-routing';
12
- import { mergeCardTags } from '../primitives/card-registry';
12
+ import { BUILTIN_CARD_TAGS, mergeCardTags } from '../primitives/card-registry';
13
+ import type { JsonSchema } from '../primitives/card-validate';
14
+ import { cardValidationMessage, validateCardData, type CardValidationReport } from '../primitives/card-validate-cards';
15
+ import { hasConsumerSchema } from '../components/card-renderer';
13
16
  import { CardFallback } from '../components/card-fallback';
14
17
  // Register the built-in child card elements so that importing <kai-cards> is self-contained.
15
18
  import './form';
@@ -26,18 +29,45 @@ interface Props extends Record<string, unknown> {
26
29
  * Typed as a plain string map (not the `CardTagMap` alias) so the generated React
27
30
  * wrapper inlines it instead of emitting an unresolved named type. */
28
31
  types?: Record<string, string>;
32
+ /** JSON Schemas for the card types this app renders, keyed by envelope type. The
33
+ * companion of `types`, which says what DRAWS a card while this says what a
34
+ * VALID one looks like. An OBJECT, so it is a JS property only: `el.schemas = {
35
+ * 'pricing-table': pricingSchema }`, never an attribute.
36
+ * `createCardRegistry(...).validationSchemas` is exactly this shape.
37
+ *
38
+ * Without it the kit validates its own seven built-ins and leaves your own card
39
+ * type, the one your app actually cares about, as the only unchecked thing on
40
+ * screen. A schema here WINS over a built-in of the same name, matching
41
+ * `mergeCardTags`, where your entry is spread over ours.
42
+ *
43
+ * Typed `Record<string, object>` rather than `Record<string, JsonSchema>`
44
+ * deliberately: an imported `.json` schema widens `"type"` to `string`, and an
45
+ * authored one carries `$schema`/`title`/`description`/`additionalProperties`,
46
+ * so the tighter type would reject both of the normal ways to supply one. See
47
+ * `CardSchemaMap` in components/card-renderer.tsx. */
48
+ schemas?: Record<string, object>;
29
49
  /** Optional CardPolicy handling child events. Property: `el.policy`. */
30
50
  policy?: CardPolicy;
51
+ /** Validate each envelope's `data` against the schema for its type before
52
+ * rendering it, using a built-in's own schema or yours from `schemas`. Default
53
+ * `true`; set `validate-cards="false"` (or `el.validateCards = false`) to opt
54
+ * out. A hard failure (wrong type, a missing required field) renders a
55
+ * diagnostic naming the field instead of the card; a soft failure (bounds)
56
+ * renders the card unchanged. Both emit a contract `error` event. On in
57
+ * production too: a model emitting a bad shape is a production failure mode,
58
+ * so stripping the check there would hide it from exactly the person who needs
59
+ * to see it. */
60
+ validateCards?: boolean;
31
61
  }
32
62
 
33
63
  /** Events fired by `<kai-cards>`. */
34
64
  interface Events {
35
- /** A child card transitioned to a resolved/deferred state (an action was chosen,
36
- * a form/tasks submission landed, or it was dismissed) — re-emitted off the host
37
- * as a non-bubbling convenience event so a consumer can observe resolution
38
- * centrally without diffing the cards array. `detail` = `{ cardId, resolution }`.
39
- * (A `reopen` un-resolves a card and has no `CardResolution`, so it does NOT fire
40
- * this observe reopen via the underlying bubbling `kai-card` event.) */
65
+ /** A child card transitioned to a resolved/deferred state (an action was chosen, a
66
+ * form/tasks submission landed, or it was dismissed). Re-emitted off the host as
67
+ * a non-bubbling convenience event so a consumer can observe resolution centrally
68
+ * without diffing the cards array. `detail` = `{ cardId, resolution }`. (A
69
+ * `reopen` un-resolves a card and has no `CardResolution`, so it does NOT fire
70
+ * this; observe reopen via the underlying bubbling `kai-card` event.) */
41
71
  'kai-card-resolved': { cardId: string; resolution: CardResolution };
42
72
  }
43
73
 
@@ -57,9 +87,47 @@ function resolutionFromEvent(e: CardEvent): CardResolution | undefined {
57
87
  }
58
88
  }
59
89
 
60
- /** A single resolved child: a known kai-* tag (props set imperatively) or the fallback. */
61
- function CardSlot(props: { envelope: CardEnvelope; tag?: string; theme: string; emit: (e: CardEvent) => void }): JSX.Element {
90
+ /** A single resolved child: a known kai-* tag (props set imperatively), a diagnostic
91
+ * for data that cannot render, or the unknown-type fallback. */
92
+ function CardSlot(props: {
93
+ envelope: CardEnvelope;
94
+ tag?: string;
95
+ theme: string;
96
+ validate: boolean;
97
+ schemas?: Record<string, object>;
98
+ emit: (e: CardEvent) => void;
99
+ }): JSX.Element {
62
100
  let ref: HTMLElement | undefined;
101
+
102
+ // MIRRORS src/remote/provider-runtime.ts:139-147, the same way
103
+ // components/card-renderer.tsx does. The remote (iframe) transport has validated
104
+ // every incoming envelope since the contract landed and this native one did not,
105
+ // so the same bad payload was caught in one transport and rendered silently in the
106
+ // other. Two tiers: `hard` (nothing to render) replaces the card with a diagnostic
107
+ // naming the field, `soft` (bounds) renders the card untouched. Both emit `error`.
108
+ //
109
+ // OUR schema applies only to OUR element: `types` lets a consumer point a built-in
110
+ // card type at their own element (`el.types = { confirm: 'my-confirm-el' }`), and
111
+ // our schema describes our element's data, not theirs.
112
+ //
113
+ // A schema the CONSUMER registered through `el.schemas` runs the other way: they
114
+ // wrote it about their own card, and it is the shape their model was told to
115
+ // emit, so it applies whichever element draws the type. That is what validates a
116
+ // `pricing-table` — nobody's built-in, and until this prop existed the one card in
117
+ // the app that nothing checked. Same rule as components/card-renderer.tsx, which
118
+ // compares component identity where this compares tag identity; `hasConsumerSchema`
119
+ // is shared with it so the gate is spelled once.
120
+ const report = createMemo<CardValidationReport | null>(() => {
121
+ if (!props.validate) return null;
122
+ if (!hasConsumerSchema(props.schemas, props.envelope.type) && props.tag !== BUILTIN_CARD_TAGS[props.envelope.type]) {
123
+ return null;
124
+ }
125
+ // `schemas` is passed even when the gate opened on tag identity, so a consumer
126
+ // schema for a built-in type wins over ours — `schemaFor`'s rule.
127
+ return validateCardData(props.envelope.type, props.envelope.data, props.schemas as Record<string, JsonSchema> | undefined);
128
+ });
129
+ const invalid = () => report()?.tier === 'hard';
130
+
63
131
  // Set object/string props as DOM properties on the custom element (reactive).
64
132
  createEffect(() => {
65
133
  if (!ref) return;
@@ -79,19 +147,44 @@ function CardSlot(props: { envelope: CardEnvelope; tag?: string; theme: string;
79
147
  props.emit({ kind: 'error', cardId: props.envelope.id, message: `Unsupported card type: ${props.envelope.type}` });
80
148
  }
81
149
  });
150
+ // One `error` per distinct problem, both tiers. Keyed on the message, not on
151
+ // mount: a consumer re-assigning `el.cards` per stream chunk hands this a new
152
+ // envelope object each time, so an identity-triggered emit would fire per chunk.
153
+ let lastEmitted: string | null = null;
154
+ createEffect(() => {
155
+ const r = report();
156
+ if (!props.tag) return; // an unknown TYPE already reported itself in onMount
157
+ if (!r || r.ok) {
158
+ lastEmitted = null;
159
+ return;
160
+ }
161
+ const message = cardValidationMessage(r);
162
+ if (message === lastEmitted) return;
163
+ lastEmitted = message;
164
+ props.emit({ kind: 'error', cardId: props.envelope.id, message });
165
+ });
166
+
82
167
  return (
83
168
  <Show
84
169
  when={props.tag}
85
170
  fallback={<CardFallback type={props.envelope.type} cardId={props.envelope.id} />}
86
171
  >
87
- {(tag) => <Dynamic component={tag()} ref={ref} />}
172
+ {(tag) => (
173
+ <Show
174
+ when={invalid()}
175
+ // SOFT and valid both take this branch: the card renders as it does today.
176
+ fallback={<Dynamic component={tag()} ref={ref} />}
177
+ >
178
+ <CardFallback type={props.envelope.type} cardId={props.envelope.id} reason={report()!.summary} />
179
+ </Show>
180
+ )}
88
181
  </Show>
89
182
  );
90
183
  }
91
184
 
92
185
  defineWebComponent<Props, Events>(
93
186
  'kai-cards',
94
- { cards: undefined, types: undefined, policy: undefined },
187
+ { cards: undefined, types: undefined, schemas: undefined, policy: undefined, validateCards: true },
95
188
  (props, { element, dispatch, expose }) => {
96
189
  // Local working copy of the card list. The `cards` PROP still drives rendering
97
190
  // (a new prop array re-seeds this), but holding a settable copy lets the
@@ -134,11 +227,11 @@ defineWebComponent<Props, Events>(
134
227
  );
135
228
  expose({
136
229
  /** Programmatically resolve a child card by id: set that envelope's
137
- * `resolution` so the child re-renders into its read-only/resolved view — the
230
+ * `resolution` so the child re-renders into its read-only/resolved view. The
138
231
  * imperative twin of the consumer mutating the cards array. No-op for an
139
232
  * unknown id. */
140
233
  resolve: (cardId: string, resolution: CardResolution) => resolveCard(cardId, resolution),
141
- /** Collapse a card to its re-openable stub from the host side convenience for
234
+ /** Collapse a card to its re-openable stub from the host side. Convenience for
142
235
  * `resolve(cardId, { kind: 'dismissed' })`. */
143
236
  dismiss: (cardId: string) => resolveCard(cardId, { kind: 'dismissed' }),
144
237
  /** Return the live child element node for a card id (or null) so consumers can
@@ -161,6 +254,8 @@ defineWebComponent<Props, Events>(
161
254
  envelope={env}
162
255
  tag={tags()[env.type]}
163
256
  theme={theme()}
257
+ validate={props.validateCards !== false}
258
+ schemas={props.schemas}
164
259
  emit={(e) => emitCardEvent(element, e)}
165
260
  />
166
261
  )}
@@ -19,23 +19,25 @@ type Step = ChainOfThoughtStepData;
19
19
 
20
20
  interface Props extends Record<string, unknown> {
21
21
  /** The reasoning steps. Set as a JS property. Compound sub-parts collapse to
22
- * this one data model (Route 1). Each `{ label, content?, id? }`. */
23
- steps: Step[];
24
- /** Open mode: `'multiple'` (default — any number of steps open at once) or
22
+ * this one data model (Route 1). Each `{ label, content?, id? }`. Omit to
23
+ * supply the steps as `<kai-step>` light-DOM children instead; when both are
24
+ * present the property's steps come first. */
25
+ steps?: Step[];
26
+ /** Open mode: `'multiple'` (default, any number of steps open at once) or
25
27
  * `'single'` (at most one open; opening a step closes the others). */
26
28
  type?: ChainOfThoughtType;
27
29
  /** Controlled open step key(s). When set, it WINS over user interaction (the
28
30
  * consumer owns the open set). String in `single` mode, string[] in
29
31
  * `multiple` mode. Set as a JS property. */
30
32
  value?: string | string[];
31
- /** Uncontrolled INITIAL open step key(s) seeds which steps render expanded.
32
- * Ignored once `value` is provided. Set as a JS property. */
33
+ /** Uncontrolled INITIAL open step key(s), seeding which steps render
34
+ * expanded. Ignored once `value` is provided. Set as a JS property. */
33
35
  defaultValue?: string | string[];
34
36
  }
35
37
 
36
38
  /** Events fired by `<kai-chain-of-thought>`. */
37
39
  interface Events {
38
- /** The open set changed by user click OR an expand()/collapse()/toggle()
40
+ /** The open set changed, by user click OR an expand()/collapse()/toggle()
39
41
  * call. `value` is a string in `single` mode, a string[] in `multiple` mode.
40
42
  * (Maps Radix Accordion's onValueChange.) */
41
43
  'kai-value-change': { value: string | string[] };
@@ -99,7 +101,7 @@ defineWebComponent<Props, Events>('kai-chain-of-thought', {
99
101
  });
100
102
 
101
103
  // Prop steps first; declarative children appended after.
102
- const allSteps = () => [...props.steps, ...slottedSteps()];
104
+ const allSteps = () => [...(props.steps ?? []), ...slottedSteps()];
103
105
 
104
106
  // ── Imperative API (instance methods on the host) ──────────────────────────
105
107
  // Pattern C: the Accordion component owns the open-set; the facade captures its
@@ -109,10 +111,12 @@ defineWebComponent<Props, Events>('kai-chain-of-thought', {
109
111
  // the only props are steps/type/value/defaultValue.
110
112
  let controller: ChainOfThoughtController | undefined;
111
113
  expose({
112
- /** Open one step's detail by index, or with no arg — ALL steps. In `single`
113
- * mode opening one step closes the others (expand-all keeps the last). */
114
+ /** Open one step's detail by index, or ALL steps when called with no arg. In
115
+ * `single` mode opening one step closes the others (expand-all keeps the
116
+ * last). */
114
117
  expand: (index?: number) => controller?.expand(index),
115
- /** Close one step's detail by index, or with no arg ALL steps. */
118
+ /** Close one step's detail by index, or ALL steps when called with no
119
+ * arg. */
116
120
  collapse: (index?: number) => controller?.collapse(index),
117
121
  /** Flip one step's open state by index. */
118
122
  toggle: (index?: number) => controller?.toggle(index),
@@ -5,10 +5,12 @@ import type { DropdownController } from '../ui/dropdown';
5
5
  import type { SearchFilters } from '../types';
6
6
 
7
7
  interface Props extends Record<string, unknown> {
8
- /** Authors to offer as scope filters. Set as a JS property. */
9
- availableAuthors: string[];
10
- /** Tags to offer as scope filters. Set as a JS property. */
11
- availableTags: string[];
8
+ /** Authors to offer as scope filters. Omit to drop the Authors section (for a
9
+ * tag-only picker). Set as a JS property. */
10
+ availableAuthors?: string[];
11
+ /** Tags to offer as scope filters. Omit to drop the Tags section (for an
12
+ * author-only picker). Set as a JS property. */
13
+ availableTags?: string[];
12
14
  /** The label shown on the trigger for the active scope. */
13
15
  currentLabel?: string;
14
16
  /** Drive/observe the dropdown's open state (Shoelace-style: settable + reflected
@@ -17,7 +19,7 @@ interface Props extends Record<string, unknown> {
17
19
  open?: boolean;
18
20
  /** Initial open state on mount (uncontrolled seed). */
19
21
  defaultOpen?: boolean;
20
- /** Disable the trigger click/keyboard and `show()` no longer open the dropdown. */
22
+ /** Disable the trigger: click/keyboard and `show()` no longer open the dropdown. */
21
23
  disabled?: boolean;
22
24
  }
23
25
 
@@ -52,8 +54,8 @@ defineWebComponent<Props, Events>('kai-scope-picker', {
52
54
  return (
53
55
  <ChatScopePicker
54
56
  currentLabel={props.currentLabel ?? 'All Content'}
55
- availableAuthors={props.availableAuthors}
56
- availableTags={props.availableTags}
57
+ availableAuthors={props.availableAuthors ?? []}
58
+ availableTags={props.availableTags ?? []}
57
59
  onScopeChange={(filters) => dispatch('kai-scope-change', { filters })}
58
60
  defaultOpen={flag('defaultOpen')}
59
61
  disabled={flag('disabled')}
@@ -1,5 +1,11 @@
1
- import type { ToolPart } from '../components/tool-types';
1
+ import type { ToolPart, RawOrigin } from '../components/tool-types';
2
2
  import type { AttachmentData } from '../components/attachment-types';
3
+ import type { CardEnvelope } from '../primitives/card-contract';
4
+
5
+ /** Re-exported so consumers of chat-types (and MessagePart) can keep using
6
+ * RawOrigin unqualified. It is defined in components/tool-types.ts, not here,
7
+ * to keep the components -> elements import direction one-way. */
8
+ export type { RawOrigin };
3
9
 
4
10
  /** The five built-in action buttons (each carries its own curated icon + label). */
5
11
  export type ChatMessageAction = 'copy' | 'like' | 'dislike' | 'regenerate' | 'edit';
@@ -31,14 +37,61 @@ export interface AvatarData {
31
37
  alt?: string;
32
38
  }
33
39
 
40
+ /** A citation the model produced. */
41
+ export interface Source {
42
+ id?: string;
43
+ url?: string;
44
+ title?: string;
45
+ snippet?: string;
46
+ /** Citation marker number, when the model numbers its citations. */
47
+ index?: number;
48
+ }
49
+
50
+ /** The public name for the citation carried by a `source` part, and the argument
51
+ * type of `AssistantStream.addSource`. The bare `Source` name is already taken
52
+ * on the public entry by the citation-chip COMPONENT (`./components/source`),
53
+ * so exporting this interface unaliased would be a duplicate identifier and the
54
+ * type would be unnameable from `@kitn.ai/ui`. */
55
+ export type MessageSource = Source;
56
+
57
+ /** One ordered piece of message content. Closed union: extension happens at the CARD
58
+ * layer via the card registry, not by adding variants here. */
59
+ export type MessagePart =
60
+ | { type: 'text'; text: string; raw?: RawOrigin }
61
+ | {
62
+ type: 'reasoning';
63
+ text: string;
64
+ label?: string;
65
+ /** Provider block index. Keeps parallel reasoning blocks distinct. */
66
+ index?: number;
67
+ /** Which provider RESPONSE STREAM `index` was counted in. Anthropic restarts
68
+ * content-block indices at 0 for every message, and a multi-round tool loop
69
+ * folds several of those messages into ONE assistant turn, so `index` alone
70
+ * is not unique within `parts`. Set by the wire adapter, one value per
71
+ * `consumeModelStream` call. See `appendReasoningPart`. */
72
+ streamId?: string;
73
+ /** Load-bearing on the OpenAI wire, informational on the Anthropic one.
74
+ * `toOpenAIMessages({ reasoning: 'include' })` REBUILDS a signed
75
+ * `reasoning_details` entry from `text` plus this, because `raw` after a
76
+ * streamed turn is a textless fragment: only the final frame carries the
77
+ * signature and it has no text, and `appendReasoningPart` resolves `raw`
78
+ * last-write-wins. `toAnthropicMessages` ignores this field and echoes
79
+ * `raw.payload` verbatim — a thinking block rebuilt from text plus
80
+ * signature is a hard 400. */
81
+ signature?: string;
82
+ raw?: RawOrigin;
83
+ }
84
+ | { type: 'tool'; tool: ToolPart; raw?: RawOrigin }
85
+ | { type: 'card'; envelope: CardEnvelope; raw?: RawOrigin }
86
+ | { type: 'source'; source: Source; raw?: RawOrigin }
87
+ | { type: 'file'; attachment: AttachmentData; raw?: RawOrigin };
88
+
34
89
  export interface ChatMessage {
35
90
  id: string;
36
91
  role: 'user' | 'assistant';
37
- content: string;
38
- reasoning?: { text: string; label?: string };
39
- tools?: ToolPart[];
40
- attachments?: AttachmentData[];
41
- /** Action buttons under the message — built-in names and/or custom descriptors. */
92
+ /** The ONLY content channel. Ordered. */
93
+ parts: MessagePart[];
94
+ /** Action buttons under the message. Chrome, not content. */
42
95
  actions?: (ChatMessageAction | CustomAction)[];
43
96
  /** Optional speaker avatar shown to the left of the message column. */
44
97
  avatar?: AvatarData;
@@ -5,6 +5,8 @@ import { readSlots, WORKSPACE_SLOTS } from './slots';
5
5
  import { ChatThread, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
6
6
  import { ConversationList, CollapsedRail } from '../components/conversation-list';
7
7
  import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '../ui/resizable';
8
+ import { cardComponentsFromTags } from './message';
9
+ import { createMessagesGuard } from './validate-messages';
8
10
  import type { AttachmentData } from '../components/attachments';
9
11
  import type { TriggerDef } from '../components/composer';
10
12
  import type { ChatMessage } from './chat-types';
@@ -12,14 +14,25 @@ import type { ProseSize } from '../primitives/chat-config';
12
14
  import type { ModelOption, ConversationGroup, ConversationSummary } from '../types';
13
15
 
14
16
  interface Props extends Record<string, unknown> {
15
- /** Pre-bucketed conversation groups for the sidebar. Set as a JS property. */
16
- groups: ConversationGroup[];
17
- /** Flat conversation list (auto-bucketed if `groups` is empty). Set as a JS property. */
18
- conversations: ConversationSummary[];
17
+ /** The sidebar's section headers, rendered in array order. A group carries no
18
+ * conversations of its own; it is matched against `conversations` by id, so
19
+ * the two props are complementary rather than alternatives. Omit for an
20
+ * ungrouped sidebar. Set as a JS property. */
21
+ groups?: ConversationGroup[];
22
+ /** Every conversation in the sidebar, flat. Each one is filed under the group
23
+ * whose `id` equals its `groupId`; one with no `groupId`, or with a `groupId`
24
+ * matching no entry in `groups`, falls into a trailing ungrouped section
25
+ * (headerless when `compact`), so nothing you pass in is ever dropped. There is
26
+ * no recency bucketing. Set as a JS property. Omit for an empty sidebar, or
27
+ * when `no-conversations` replaces the built-in list with your own
28
+ * `sidebar-header` content. */
29
+ conversations?: ConversationSummary[];
19
30
  /** Id of the open conversation, highlighted in the sidebar. */
20
31
  activeId?: string;
21
- /** The active conversation's message thread, newest last. Set as a JS property. */
22
- messages: ChatMessage[];
32
+ /** The active conversation's message thread, newest last. Set as a JS property
33
+ * (`el.messages = [...]`); a NEW array reference per streaming chunk
34
+ * re-renders (mutating in place does not). Omit for an empty thread. */
35
+ messages?: ChatMessage[];
23
36
  value?: string;
24
37
  placeholder?: string;
25
38
  loading?: boolean;
@@ -63,6 +76,26 @@ interface Props extends Record<string, unknown> {
63
76
  * whole rail flex region (for apps that supply their own rail nav). Default
64
77
  * false. Attribute: `no-conversations`. */
65
78
  noConversations?: boolean;
79
+ /** Optional card type -> custom-element tag overrides/additions for `card`
80
+ * parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a
81
+ * plain string map (not the `CardTagMap` alias) so the generated React
82
+ * wrapper inlines it instead of emitting an unresolved named type. */
83
+ cardTypes?: Record<string, string>;
84
+ /** JSON Schemas for the card types this app renders, keyed by envelope type. The
85
+ * companion of `cardTypes`, which says what DRAWS a card while this says what a
86
+ * VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas
87
+ * = { 'pricing-table': pricingSchema }`, never an attribute.
88
+ * `createCardRegistry(...).validationSchemas` is exactly this shape.
89
+ *
90
+ * Without it the kit validates its own seven built-ins and leaves your own card
91
+ * type, the one your app actually cares about, as the only unchecked thing on
92
+ * screen. A schema here WINS over a built-in of the same name.
93
+ *
94
+ * Typed `Record<string, object>` rather than `Record<string, JsonSchema>`
95
+ * deliberately: an imported `.json` schema widens `"type"` to `string`, and an
96
+ * authored one carries `$schema`/`title`/`description`/`additionalProperties`,
97
+ * so the tighter type would reject both of the normal ways to supply one. */
98
+ cardSchemas?: Record<string, object>;
66
99
  }
67
100
 
68
101
  interface Events {
@@ -99,8 +132,14 @@ defineWebComponent<Props, Events>('kai-workspace', {
99
132
  search: false, voice: false, triggers: undefined, kindIcons: undefined,
100
133
  sidebarWidth: 26, sidebarMinWidth: 240, sidebarMaxWidth: 420,
101
134
  sidebarCollapsed: undefined, defaultSidebarCollapsed: undefined, collapseBelow: undefined, compact: undefined,
102
- noConversations: undefined,
135
+ noConversations: undefined, cardTypes: undefined, cardSchemas: undefined,
103
136
  }, (props, { dispatch, flag, expose, element }) => {
137
+ // `messages` is an untyped boundary: a consumer can hand it anything at
138
+ // runtime (a pre-0.20.0 `{ id, role, content }` array, in particular). Skip
139
+ // the invalid entries rather than let `groupMessageParts` throw deep inside a
140
+ // render pass, which would blank the whole workspace instead of one message.
141
+ const validMessages = createMessagesGuard('kai-workspace');
142
+
104
143
  // Which injection slots the consumer has filled. A bare <slot> is always a
105
144
  // truthy JSX node, so we render each region wrapper ONLY when readSlots reports
106
145
  // projected light-DOM content (re-read on childList mutation).
@@ -180,7 +219,7 @@ defineWebComponent<Props, Events>('kai-workspace', {
180
219
  // own state (e.g. an uncontrolled draft) survives the collapse/expand.
181
220
  const threadEl = (
182
221
  <ChatThread
183
- messages={props.messages} value={props.value as string | undefined} placeholder={props.placeholder as string}
222
+ messages={validMessages(props.messages)} value={props.value as string | undefined} placeholder={props.placeholder as string}
184
223
  loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
185
224
  suggestionMode={props.suggestionMode as 'submit' | 'fill'} proseSize={props.proseSize as ProseSize}
186
225
  codeTheme={props.codeTheme as string} codeHighlight={flag('codeHighlight')}
@@ -189,6 +228,8 @@ defineWebComponent<Props, Events>('kai-workspace', {
189
228
  scrollButton={props.scrollButton !== false} search={flag('search')} voice={flag('voice')}
190
229
  triggers={props.triggers as TriggerDef[] | undefined}
191
230
  kindIcons={props.kindIcons as Record<string, string> | undefined}
231
+ cardTypes={cardComponentsFromTags(props.cardTypes as Record<string, string> | undefined, (props as { theme?: string }).theme)}
232
+ cardSchemas={props.cardSchemas as Record<string, object> | undefined}
192
233
  onValueChange={(value) => dispatch('kai-value-change', { value })}
193
234
  onSubmit={(detail) => dispatch('kai-submit', detail)}
194
235
  onSuggestionClick={(value) => dispatch('kai-suggestion-click', { value })}
@@ -253,7 +294,7 @@ defineWebComponent<Props, Events>('kai-workspace', {
253
294
  <div class="min-h-0 flex-1">
254
295
  <ConversationList
255
296
  class="bg-transparent"
256
- groups={props.groups} conversations={props.conversations} activeId={props.activeId as string | undefined}
297
+ groups={props.groups ?? []} conversations={props.conversations ?? []} activeId={props.activeId as string | undefined}
257
298
  compact={flag('compact')}
258
299
  onSelect={(id) => dispatch('kai-conversation-select', { id })}
259
300
  onNewChat={() => dispatch('kai-new-chat', {})}
@@ -2,7 +2,10 @@ import { createEffect, createSignal, onCleanup, onMount } from 'solid-js';
2
2
  import { defineWebComponent } from './define';
3
3
  import { CHAT_SLOTS, readSlots } from './slots';
4
4
  import { ChatThread, type ChatThreadProps, type ChatThreadContextUsage, type ChatThreadController } from '../components/chat-thread';
5
+ import { cardComponentsFromTags } from './message';
6
+ import { createMessagesGuard } from './validate-messages';
5
7
  import type { AttachmentData } from '../components/attachments';
8
+ import type { ChatMessage } from './chat-types';
6
9
  import type { TriggerDef } from '../components/composer';
7
10
  import type { ComposerDoc } from '../primitives/composer-model';
8
11
  import type { ProseSize } from '../primitives/chat-config';
@@ -10,7 +13,38 @@ import type { ModelOption } from '../types';
10
13
 
11
14
  type Props = Omit<ChatThreadProps,
12
15
  'class' | 'onValueChange' | 'onSubmit' | 'onAttachmentsChange' | 'onSuggestionClick' | 'onModelChange'
13
- | 'onMessageAction' | 'onSearch' | 'onVoice' | 'controllerRef'> & Record<string, unknown>;
16
+ | 'onMessageAction' | 'onSearch' | 'onVoice' | 'controllerRef' | 'cardTypes' | 'cardSchemas' | 'messages'> & Record<string, unknown> & {
17
+ /** The full message thread to render, newest last. Each entry carries its
18
+ * role, ordered `parts`, and optional actions/avatar/feedback. Set as a JS
19
+ * property (`el.messages = [...]`); a NEW array reference per streaming
20
+ * chunk re-renders (mutating in place does not). Omit for an empty thread.
21
+ *
22
+ * Re-declared here (rather than inherited from `ChatThreadProps`) because
23
+ * the ELEMENT registers a `[]` default and renders the empty state without
24
+ * it, while the SolidJS `<ChatThread>` component still requires it. The
25
+ * facade hands it a validated array either way. Matches `<kai-thread>`. */
26
+ messages?: ChatMessage[];
27
+ /** Optional card type -> custom-element tag overrides/additions for `card`
28
+ * parts (merged over the built-ins). Property: `el.cardTypes`. Typed as a
29
+ * plain string map (not the `CardTagMap` alias) so the generated React
30
+ * wrapper inlines it instead of emitting an unresolved named type. */
31
+ cardTypes?: Record<string, string>;
32
+ /** JSON Schemas for the card types this app renders, keyed by envelope type. The
33
+ * companion of `cardTypes`, which says what DRAWS a card while this says what a
34
+ * VALID one looks like. An OBJECT, so it is a JS property only: `el.cardSchemas
35
+ * = { 'pricing-table': pricingSchema }`, never an attribute.
36
+ * `createCardRegistry(...).validationSchemas` is exactly this shape.
37
+ *
38
+ * Without it the kit validates its own seven built-ins and leaves your own card
39
+ * type, the one your app actually cares about, as the only unchecked thing on
40
+ * screen. A schema here WINS over a built-in of the same name.
41
+ *
42
+ * Typed `Record<string, object>` rather than `Record<string, JsonSchema>`
43
+ * deliberately: an imported `.json` schema widens `"type"` to `string`, and an
44
+ * authored one carries `$schema`/`title`/`description`/`additionalProperties`,
45
+ * so the tighter type would reject both of the normal ways to supply one. */
46
+ cardSchemas?: Record<string, object>;
47
+ };
14
48
 
15
49
  interface Events {
16
50
  /** User submitted a message. */
@@ -40,8 +74,14 @@ defineWebComponent<Props, Events>('kai-chat', {
40
74
  codeTheme: 'github-dark-dimmed', codeHighlight: true, chatTitle: undefined,
41
75
  models: undefined, currentModel: undefined, context: undefined, scrollButton: true,
42
76
  search: false, voice: false, triggers: undefined, kindIcons: undefined,
43
- actionsReveal: 'always',
77
+ actionsReveal: 'always', cardTypes: undefined, cardSchemas: undefined,
44
78
  }, (props, { dispatch, flag, element, expose }) => {
79
+ // `messages` is an untyped boundary: a consumer can hand it anything at
80
+ // runtime (a pre-0.20.0 `{ id, role, content }` array, in particular). Skip
81
+ // the invalid entries rather than let `groupMessageParts` throw deep inside a
82
+ // render pass, which would blank the whole chat instead of one message.
83
+ const validMessages = createMessagesGuard('kai-chat');
84
+
45
85
  // Slot detection is driven by the CHAT_SLOTS registry (single source of truth)
46
86
  // so slot names never drift between the view, the facade, and the docs.
47
87
  const [slots, setSlots] = createSignal<Record<string, boolean>>({});
@@ -62,16 +102,35 @@ defineWebComponent<Props, Events>('kai-chat', {
62
102
  // (focus the composer, clear it, send programmatically, scroll the thread).
63
103
  let controller: ChatThreadController | undefined;
64
104
  expose({
105
+ /** Focus the composer, meaning the contenteditable (or textarea) inside the
106
+ * shadow root. A native `focus()` on the host lands on the host itself and
107
+ * never reaches it, so this is the only way to focus the input
108
+ * programmatically. */
65
109
  focus: (options?: FocusOptions) => controller?.focus(options),
110
+ /** Blur whatever currently holds focus inside the shadow root. The companion
111
+ * to `focus()`, for the same reason: a native `blur()` on the host misses
112
+ * the real focus target. */
66
113
  blur: () => (element.shadowRoot?.activeElement as HTMLElement | null)?.blur(),
114
+ /** Empty the COMPOSER: drops the draft text and every staged attachment, then
115
+ * fires `kai-value-change` with `''`. It does NOT touch the thread. `messages`
116
+ * is the consumer's own state, so clearing history stays the consumer's call. */
67
117
  clear: () => controller?.clear(),
118
+ /** Submit whatever the composer currently holds, on the same path as Enter or
119
+ * the send button: fires `kai-submit` with that value plus the staged
120
+ * attachments, then drops the attachments. It takes no argument, so to send
121
+ * text the user never typed, set `el.value` first. There is no empty-check,
122
+ * so an empty composer still fires. The draft is cleared afterwards only when
123
+ * `value` is uncontrolled; a controlled host owns its value and clears it
124
+ * itself. Named `send`, not `submit`, to match the shared vocabulary. */
68
125
  send: () => controller?.send(),
126
+ /** Scroll the message viewport to the newest message. Defaults to `'smooth'`;
127
+ * pass `'instant'` to jump without animating. */
69
128
  scrollToBottom: (behavior?: ScrollBehavior) => controller?.scrollToBottom(behavior),
70
129
  });
71
130
 
72
131
  return (
73
132
  <ChatThread
74
- messages={props.messages} value={props.value as string | ComposerDoc | undefined} placeholder={props.placeholder as string}
133
+ messages={validMessages(props.messages)} value={props.value as string | ComposerDoc | undefined} placeholder={props.placeholder as string}
75
134
  loading={flag('loading')} suggestions={props.suggestions as string[] | undefined}
76
135
  suggestionMode={props.suggestionMode as 'submit' | 'fill'} persistSuggestions={flag('persistSuggestions')}
77
136
  proseSize={props.proseSize as ProseSize}
@@ -82,6 +141,8 @@ defineWebComponent<Props, Events>('kai-chat', {
82
141
  triggers={props.triggers as TriggerDef[] | undefined}
83
142
  kindIcons={props.kindIcons as Record<string, string> | undefined}
84
143
  actionsReveal={props.actionsReveal as 'always' | 'hover'}
144
+ cardTypes={cardComponentsFromTags(props.cardTypes as Record<string, string> | undefined, (props as { theme?: string }).theme)}
145
+ cardSchemas={props.cardSchemas as Record<string, object> | undefined}
85
146
  onValueChange={(value) => dispatch('kai-value-change', { value })}
86
147
  onSubmit={(detail) => dispatch('kai-submit', detail)}
87
148
  onAttachmentsChange={(attachments) => dispatch('kai-attachments-change', { attachments })}
@@ -6,7 +6,7 @@ interface Props extends Record<string, unknown> {
6
6
  /** The choice definition (the CardEnvelope.data). Set as a JS PROPERTY:
7
7
  * `el.data = { prompt, options:[…], allowOther?, submitLabel? }`. Import
8
8
  * `ChoiceCardData` from `@kitn.ai/ui` for the full shape. */
9
- data?: Record<string, unknown>;
9
+ data?: ChoiceCardData;
10
10
  /** Stable card id correlating every emitted CardEvent. Attribute: `card-id`. */
11
11
  cardId?: string;
12
12
  /** Heading rendered in the card chrome (= CardEnvelope.title). Attribute: `heading`. */
@@ -14,7 +14,7 @@ interface Props extends Record<string, unknown> {
14
14
  /** Set when the user resolved this card; renders the read-only view. Property:
15
15
  * `el.resolution = { kind:'action', action:'…' }`. */
16
16
  resolution?: Record<string, unknown>;
17
- /** Controlled selection the selected option id. When set, the consumer owns
17
+ /** Controlled selection: the selected option id. When set, the consumer owns
18
18
  * the current pick (RadioGroup `value`). Attribute: `value`. */
19
19
  value?: string;
20
20
  /** Option id to pre-select on mount (uncontrolled seed). Attribute: `default-value`. */
@@ -68,23 +68,23 @@ defineWebComponent<Props, Events>(
68
68
  expose({
69
69
  /** Focus the radiogroup roving tab stop (or the Other input when selected). */
70
70
  focus: (options?: FocusOptions) => controller?.focus(options),
71
- /** Select an option by id locally no emit, fires kai-value-change (same as
72
- * a row click). Lets a consumer pre-highlight or drive selection externally. */
71
+ /** Select an option by id locally: no emit, fires kai-value-change (same as a
72
+ * row click). Lets a consumer pre-highlight or drive selection externally. */
73
73
  select: (optionId: string) => controller?.select(optionId),
74
- /** Submit the current selection emits the `action` verb on kai-card and
74
+ /** Submit the current selection: emits the `action` verb on kai-card and
75
75
  * resolves the card (single-shot). Named `send`, not `submit`, per the shared
76
76
  * vocabulary. */
77
77
  send: () => controller?.send(),
78
- /** Trigger the dismiss path emits `dismiss` on kai-card and optimistically
78
+ /** Trigger the dismiss path: emits `dismiss` on kai-card and optimistically
79
79
  * collapses the card to its re-openable stub. */
80
80
  dismiss: () => controller?.dismiss(),
81
- /** Re-open a dismissed card from its stub emits `reopen` on kai-card. */
81
+ /** Re-open a dismissed card from its stub: emits `reopen` on kai-card. */
82
82
  reopen: () => controller?.reopen(),
83
83
  });
84
84
 
85
85
  return (
86
86
  <ChoiceCard
87
- data={props.data as ChoiceCardData | undefined}
87
+ data={props.data}
88
88
  cardId={props.cardId ?? (element.id || 'kai-choice')}
89
89
  heading={props.heading}
90
90
  resolution={props.resolution as CardResolution | undefined}
@@ -17,7 +17,7 @@ interface Props extends Record<string, unknown> {
17
17
  /** Floating placement relative to the anchor (default `bottom`). */
18
18
  placement?: string;
19
19
  /** Color tone: `primary` (default, theme accent), `info` (blue), `success`
20
- * (green), `warning` (amber), or `error` (red) reusing the kit's tool hues. */
20
+ * (green), `warning` (amber), or `error` (red), reusing the kit's tool hues. */
21
21
  tone?: 'primary' | 'info' | 'success' | 'warning' | 'error';
22
22
  /** Render the arrow that points at the anchor (default `true`). Set
23
23
  * `arrow="false"` for a plain bubble with no pointer. */