@kitn.ai/ui 0.17.0 → 0.18.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 (494) hide show
  1. package/README.md +28 -5
  2. package/dist/components/artifact.d.ts +39 -1
  3. package/dist/components/attachment-types.d.ts +12 -0
  4. package/dist/components/attachments.d.ts +2 -10
  5. package/dist/components/card.d.ts +27 -0
  6. package/dist/components/chain-of-thought.d.ts +78 -2
  7. package/dist/components/chat-scope-picker.d.ts +7 -0
  8. package/dist/components/chat-thread.d.ts +37 -12
  9. package/dist/components/choice-card.d.ts +26 -0
  10. package/dist/components/coachmark.d.ts +49 -0
  11. package/dist/components/composer-dom.d.ts +35 -0
  12. package/dist/components/composer-highlight.d.ts +48 -0
  13. package/dist/components/composer-history.d.ts +34 -0
  14. package/dist/components/composer.d.ts +86 -0
  15. package/dist/components/confirm-card.d.ts +17 -0
  16. package/dist/components/conversation-item.d.ts +9 -0
  17. package/dist/components/conversation-list.d.ts +36 -1
  18. package/dist/components/file-tree.d.ts +15 -0
  19. package/dist/components/form.d.ts +34 -0
  20. package/dist/components/markdown.d.ts +3 -0
  21. package/dist/components/message.d.ts +12 -0
  22. package/dist/components/model-switcher.d.ts +7 -0
  23. package/dist/components/prompt-input.d.ts +13 -4
  24. package/dist/components/prompt-suggestion.d.ts +9 -1
  25. package/dist/components/reasoning.d.ts +14 -1
  26. package/dist/components/response-compare.d.ts +14 -0
  27. package/dist/components/screen.d.ts +46 -0
  28. package/dist/components/tasks-card.d.ts +49 -1
  29. package/dist/components/toast.d.ts +12 -2
  30. package/dist/components/tool-types.d.ts +10 -0
  31. package/dist/components/tool.d.ts +8 -8
  32. package/dist/components/voice-input.d.ts +27 -0
  33. package/dist/components/voice-output.d.ts +33 -0
  34. package/dist/core-C8fzo39E.js +12 -0
  35. package/dist/custom-elements.json +8392 -1860
  36. package/dist/elements/agent-card.d.ts +1 -0
  37. package/dist/elements/agent-card.js +1 -0
  38. package/dist/elements/artifact.js +1 -1
  39. package/dist/elements/attachments.js +1 -1
  40. package/dist/elements/autoloader.js +1 -1
  41. package/dist/elements/avatar.d.ts +1 -0
  42. package/dist/elements/avatar.js +1 -0
  43. package/dist/elements/badge.d.ts +1 -0
  44. package/dist/elements/badge.js +1 -0
  45. package/dist/elements/button.d.ts +1 -0
  46. package/dist/elements/button.js +1 -0
  47. package/dist/elements/card.js +1 -1
  48. package/dist/elements/cards.js +1 -1
  49. package/dist/elements/chain-of-thought.js +1 -1
  50. package/dist/elements/chat-scope-picker.js +1 -1
  51. package/dist/elements/chat-types.d.ts +47 -0
  52. package/dist/elements/chat-workspace.js +1 -1
  53. package/dist/elements/chat.js +1 -1
  54. package/dist/elements/checkpoint.js +1 -1
  55. package/dist/elements/choice.js +1 -1
  56. package/dist/elements/chunks/Icon-DLLBeLG5.js +1 -0
  57. package/dist/elements/chunks/action-icons-UB4V5FNq.js +1 -0
  58. package/dist/elements/chunks/arrow-left-C-gwlUmx.js +1 -0
  59. package/dist/elements/chunks/attachments-CgbErf1r.js +1 -0
  60. package/dist/elements/chunks/badge-DTQpgB6N.js +1 -0
  61. package/dist/elements/chunks/button-XDUM6lXs.js +1 -0
  62. package/dist/elements/chunks/card-CBlFZ-7I.js +1 -0
  63. package/dist/elements/chunks/chat-thread-BIhmqwNL.js +1 -0
  64. package/dist/elements/chunks/check-hGUoVIKb.js +1 -0
  65. package/dist/elements/chunks/chevron-down-DDoaSUtO.js +1 -0
  66. package/dist/elements/chunks/chevron-right-CdGEUakB.js +1 -0
  67. package/dist/elements/chunks/circle-BKAZdmzb.js +1 -0
  68. package/dist/elements/chunks/circle-check-CmYG-y3I.js +1 -0
  69. package/dist/elements/chunks/circle-x-DewgAEym.js +1 -0
  70. package/dist/elements/chunks/cn-CU7UAWzk.js +1 -0
  71. package/dist/elements/chunks/code-block-DedwxwFI.js +1 -0
  72. package/dist/elements/chunks/collapsible-FfgmTHtM.js +1 -0
  73. package/dist/elements/chunks/composer-Cfbw5HKT.js +65 -0
  74. package/dist/elements/chunks/context-DwJmxlRE.js +1 -0
  75. package/dist/elements/chunks/conversation-list-DsCQMfPq.js +1 -0
  76. package/dist/elements/chunks/default-input-BuqsoENC.js +1 -0
  77. package/dist/elements/chunks/define-rGsaWsLL.js +1 -0
  78. package/dist/elements/chunks/disclosure-CwoAkpMH.js +1 -0
  79. package/dist/elements/chunks/download-DJ06G3Bz.js +1 -0
  80. package/dist/elements/chunks/dropdown-BFg8ri_R.js +1 -0
  81. package/dist/elements/chunks/ellipsis-dlN6YvGw.js +1 -0
  82. package/dist/elements/chunks/external-link-DBX2lc_R.js +1 -0
  83. package/dist/elements/chunks/file-text-HfwUx4F9.js +1 -0
  84. package/dist/elements/chunks/file-tree-C6Toj71u.js +1 -0
  85. package/dist/elements/chunks/folder-MYuqa9Xp.js +1 -0
  86. package/dist/elements/chunks/hover-card-gE7iyXdW.js +1 -0
  87. package/dist/elements/chunks/icon-Vqz4ivrY.js +1 -0
  88. package/dist/elements/chunks/{index-CTBEJeo6.js → index-BCRhi84a.js} +1 -1
  89. package/dist/elements/chunks/info-B_toFS0l.js +1 -0
  90. package/dist/elements/chunks/input-gzbHYZvQ.js +1 -0
  91. package/dist/elements/chunks/kbd-n49c4KZm.js +1 -0
  92. package/dist/elements/chunks/link-CKPs9yM0.js +1 -0
  93. package/dist/elements/chunks/loader-q6MamGus.js +1 -0
  94. package/dist/elements/chunks/{markdown-CMTGx9r8.js → markdown-DBrcqq4S.js} +9 -9
  95. package/dist/elements/chunks/message-CTqaYI0s.js +1 -0
  96. package/dist/elements/chunks/message-feedback-Cvzm03w0.js +1 -0
  97. package/dist/elements/chunks/message-square-CUg9eRCi.js +1 -0
  98. package/dist/elements/chunks/minimize-2-l2klxP6K.js +1 -0
  99. package/dist/elements/chunks/model-switcher-CmyjiHO1.js +1 -0
  100. package/dist/elements/chunks/overlay-C8sOYqjT.js +1 -0
  101. package/dist/elements/chunks/paperclip-42Ia7xHD.js +1 -0
  102. package/dist/elements/chunks/progress-bar-tzKMWAwO.js +1 -0
  103. package/dist/elements/chunks/prompt-suggestion-D3F6vP_A.js +1 -0
  104. package/dist/elements/chunks/reasoning-BJNmmyov.js +1 -0
  105. package/dist/elements/chunks/resizable-BRsk19qI.js +1 -0
  106. package/dist/elements/chunks/rotate-cw-BgcggLHC.js +1 -0
  107. package/dist/elements/chunks/scroll-area-CgGbFFbT.js +1 -0
  108. package/dist/elements/chunks/separator-8hM4GdHE.js +1 -0
  109. package/dist/elements/chunks/settings-CaUIYOg-.js +1 -0
  110. package/dist/elements/chunks/settings-group-CYjOVIZQ.js +1 -0
  111. package/dist/elements/chunks/share-BTYM3Ddt.js +1 -0
  112. package/dist/elements/chunks/skeleton-DsTYrPUe.js +1 -0
  113. package/dist/elements/chunks/slots-DkZ-Cmha.js +1 -0
  114. package/dist/elements/chunks/star-9R3LBQ9n.js +1 -0
  115. package/dist/elements/chunks/store-CYl5Y0_u.js +1 -0
  116. package/dist/elements/chunks/text-shimmer-CaYGv8Se.js +1 -0
  117. package/dist/elements/chunks/textarea-NEr2SLcD.js +1 -0
  118. package/dist/elements/chunks/thumbs-up-DZYZkFfc.js +1 -0
  119. package/dist/elements/chunks/toast-store-ClxVZRcc.js +1 -0
  120. package/dist/elements/chunks/tool-CHZOmoe9.js +1 -0
  121. package/dist/elements/chunks/tooltip-WpHElELC.js +1 -0
  122. package/dist/elements/chunks/triangle-alert-BlS80PUg.js +1 -0
  123. package/dist/elements/chunks/use-card-resolution-VSVoxDeJ.js +1 -0
  124. package/dist/elements/chunks/video-DxTPZqT8.js +1 -0
  125. package/dist/elements/chunks/x-C1qtndxn.js +1 -0
  126. package/dist/elements/coachmark.d.ts +1 -0
  127. package/dist/elements/coachmark.js +1 -0
  128. package/dist/elements/code-block.js +1 -1
  129. package/dist/elements/command.d.ts +1 -0
  130. package/dist/elements/command.js +1 -0
  131. package/dist/elements/compare.js +1 -1
  132. package/dist/elements/composer.d.ts +1 -0
  133. package/dist/elements/composer.js +1 -0
  134. package/dist/elements/confirm-card.js +1 -1
  135. package/dist/elements/context-meter.js +1 -1
  136. package/dist/elements/conversation-list.js +1 -1
  137. package/dist/elements/css.d.ts +1 -0
  138. package/dist/elements/default-input.d.ts +51 -0
  139. package/dist/elements/define.d.ts +53 -0
  140. package/dist/elements/dialog.d.ts +1 -0
  141. package/dist/elements/dialog.js +1 -0
  142. package/dist/elements/disclosure.d.ts +37 -0
  143. package/dist/elements/editable-label.d.ts +1 -0
  144. package/dist/elements/editable-label.js +1 -0
  145. package/dist/elements/embed.js +1 -1
  146. package/dist/elements/empty.js +1 -1
  147. package/dist/elements/feedback-bar.js +1 -1
  148. package/dist/elements/file-tree.js +1 -1
  149. package/dist/elements/file-upload.js +1 -1
  150. package/dist/elements/form.js +1 -1
  151. package/dist/elements/hover-card.d.ts +1 -0
  152. package/dist/elements/hover-card.js +1 -0
  153. package/dist/elements/icon.d.ts +1 -0
  154. package/dist/elements/icon.js +1 -0
  155. package/dist/elements/image.js +1 -1
  156. package/dist/elements/input.d.ts +1 -0
  157. package/dist/elements/input.js +1 -0
  158. package/dist/elements/kbd.d.ts +1 -0
  159. package/dist/elements/kbd.js +1 -0
  160. package/dist/elements/link-preview.js +1 -1
  161. package/dist/elements/loader.js +1 -1
  162. package/dist/elements/markdown.js +1 -1
  163. package/dist/elements/menu.d.ts +1 -0
  164. package/dist/elements/menu.js +1 -0
  165. package/dist/elements/message-skills.js +1 -1
  166. package/dist/elements/message.js +1 -1
  167. package/dist/elements/model-switcher.js +1 -1
  168. package/dist/elements/nav.d.ts +1 -0
  169. package/dist/elements/nav.js +1 -0
  170. package/dist/elements/notice.d.ts +1 -0
  171. package/dist/elements/notice.js +1 -0
  172. package/dist/elements/pane-group.d.ts +1 -0
  173. package/dist/elements/pane-group.js +1 -0
  174. package/dist/elements/pane.d.ts +1 -0
  175. package/dist/elements/pane.js +1 -0
  176. package/dist/elements/popover.js +1 -1
  177. package/dist/elements/progress-bar.d.ts +1 -0
  178. package/dist/elements/progress-bar.js +1 -0
  179. package/dist/elements/prompt-dock.d.ts +1 -0
  180. package/dist/elements/prompt-dock.js +1 -0
  181. package/dist/elements/prompt-input.js +1 -1
  182. package/dist/elements/prompt-suggestions.js +1 -1
  183. package/dist/elements/reasoning.js +1 -1
  184. package/dist/elements/register-impl.d.ts +0 -0
  185. package/dist/elements/register.d.ts +13 -0
  186. package/dist/elements/remote.d.ts +1 -0
  187. package/dist/elements/remote.js +1 -0
  188. package/dist/elements/resizable.js +1 -1
  189. package/dist/elements/response-stream.js +2 -2
  190. package/dist/elements/screen.d.ts +1 -0
  191. package/dist/elements/screen.js +1 -0
  192. package/dist/elements/scroll-area.d.ts +1 -0
  193. package/dist/elements/scroll-area.js +1 -0
  194. package/dist/elements/scroll-button.js +1 -1
  195. package/dist/elements/search.d.ts +1 -0
  196. package/dist/elements/search.js +1 -0
  197. package/dist/elements/segmented.d.ts +1 -0
  198. package/dist/elements/segmented.js +1 -0
  199. package/dist/elements/separator.d.ts +1 -0
  200. package/dist/elements/separator.js +1 -0
  201. package/dist/elements/setting-item.d.ts +1 -0
  202. package/dist/elements/setting-item.js +1 -0
  203. package/dist/elements/settings-group.d.ts +1 -0
  204. package/dist/elements/settings-group.js +1 -0
  205. package/dist/elements/skeleton.d.ts +1 -0
  206. package/dist/elements/skeleton.js +1 -0
  207. package/dist/elements/slots.d.ts +176 -0
  208. package/dist/elements/source.js +1 -1
  209. package/dist/elements/status.d.ts +1 -0
  210. package/dist/elements/status.js +1 -0
  211. package/dist/elements/switch.js +1 -1
  212. package/dist/elements/tabs.d.ts +1 -0
  213. package/dist/elements/tabs.js +1 -0
  214. package/dist/elements/tasks.js +1 -1
  215. package/dist/elements/text-shimmer.js +1 -1
  216. package/dist/elements/thinking-bar.js +1 -1
  217. package/dist/elements/toast.js +1 -1
  218. package/dist/elements/tool.js +1 -1
  219. package/dist/elements/tooltip.d.ts +1 -0
  220. package/dist/elements/tooltip.js +1 -0
  221. package/dist/elements/voice-input.js +1 -1
  222. package/dist/elements/voice-output.d.ts +1 -0
  223. package/dist/elements/voice-output.js +1 -0
  224. package/dist/elements.d.ts +733 -58
  225. package/dist/engine-javascript-C1x7zo1_.js +141 -0
  226. package/dist/index.d.ts +3 -2
  227. package/dist/index.js +8256 -5703
  228. package/dist/kai.es.js +1 -0
  229. package/dist/llms/llms-full.txt +1146 -64
  230. package/dist/llms/llms.txt +4 -4
  231. package/dist/mcp.es.js +62 -7
  232. package/dist/primitives/composer-model.d.ts +22 -0
  233. package/dist/primitives/composer-triggers.d.ts +19 -0
  234. package/dist/primitives/create-kai-chat.d.ts +38 -0
  235. package/dist/primitives/toast-store.d.ts +32 -2
  236. package/dist/primitives/use-speech-recognition.d.ts +26 -0
  237. package/dist/react/index.d.ts +1085 -97
  238. package/dist/react/runtime.d.ts +9 -2
  239. package/dist/react/use-kai-chat.d.ts +41 -0
  240. package/dist/react.js +572 -193
  241. package/dist/register-impl-CYWGkgbI.js +141 -0
  242. package/dist/schemas/tasks.schema.json +2 -2
  243. package/dist/state/index.d.ts +4 -0
  244. package/dist/state/messages.d.ts +11 -0
  245. package/dist/state/stream.d.ts +22 -0
  246. package/dist/state/suggestions.d.ts +4 -0
  247. package/dist/state.js +117 -0
  248. package/dist/theme.tokens.css +87 -0
  249. package/dist/types.d.ts +4 -0
  250. package/dist/ui/agent-card.d.ts +61 -0
  251. package/dist/ui/button.d.ts +5 -2
  252. package/dist/ui/card.d.ts +61 -0
  253. package/dist/ui/collapsible.d.ts +15 -1
  254. package/dist/ui/command.d.ts +33 -0
  255. package/dist/ui/dialog.d.ts +42 -0
  256. package/dist/ui/dropdown.d.ts +95 -1
  257. package/dist/ui/editable-label.d.ts +26 -0
  258. package/dist/ui/hover-card.d.ts +13 -1
  259. package/dist/ui/icon.d.ts +18 -0
  260. package/dist/ui/input.d.ts +33 -0
  261. package/dist/ui/kbd.d.ts +21 -0
  262. package/dist/ui/nav.d.ts +62 -0
  263. package/dist/ui/notice.d.ts +31 -0
  264. package/dist/ui/overlay.d.ts +12 -0
  265. package/dist/ui/pane-grid.d.ts +58 -0
  266. package/dist/ui/pane-group.d.ts +75 -0
  267. package/dist/ui/pane.d.ts +78 -0
  268. package/dist/ui/popover.d.ts +11 -1
  269. package/dist/ui/progress-bar.d.ts +23 -0
  270. package/dist/ui/prompt-dock.d.ts +96 -0
  271. package/dist/ui/resizable.d.ts +12 -0
  272. package/dist/ui/scroll-area.d.ts +4 -0
  273. package/dist/ui/segmented.d.ts +28 -0
  274. package/dist/ui/settings-group.d.ts +32 -0
  275. package/dist/ui/skeleton.d.ts +12 -0
  276. package/dist/ui/stat.d.ts +16 -0
  277. package/dist/ui/status.d.ts +13 -0
  278. package/dist/ui/switch.d.ts +8 -1
  279. package/dist/ui/tabs.d.ts +35 -0
  280. package/dist/ui/tooltip.d.ts +19 -1
  281. package/frameworks/react/index.tsx +1042 -157
  282. package/frameworks/react/runtime.tsx +30 -1
  283. package/frameworks/react/use-kai-chat.tsx +87 -0
  284. package/llms-full.txt +1146 -64
  285. package/llms.txt +4 -4
  286. package/package.json +23 -8
  287. package/src/agent-tooling/mcp/manifest.ts +14 -0
  288. package/src/agent-tooling/mcp/tools/debug.ts +10 -6
  289. package/src/agent-tooling/mcp/tools/reference.ts +32 -0
  290. package/src/agent-tooling/mcp/tools/scaffold.ts +30 -1
  291. package/src/components/artifact.tsx +98 -13
  292. package/src/components/attachment-types.ts +13 -0
  293. package/src/components/attachments.tsx +4 -14
  294. package/src/components/card.tsx +109 -15
  295. package/src/components/chain-of-thought.tsx +210 -1
  296. package/src/components/chat-scope-picker.tsx +13 -3
  297. package/src/components/chat-thread.tsx +225 -116
  298. package/src/components/choice-card.tsx +103 -11
  299. package/src/components/coachmark.tsx +245 -0
  300. package/src/components/component-meta.json +691 -102
  301. package/src/components/composer-dom.ts +159 -0
  302. package/src/components/composer-highlight.ts +242 -0
  303. package/src/components/composer-history.ts +82 -0
  304. package/src/components/composer.tsx +979 -0
  305. package/src/components/confirm-card.tsx +54 -1
  306. package/src/components/conversation-item.tsx +69 -7
  307. package/src/components/conversation-list.tsx +134 -37
  308. package/src/components/file-tree.tsx +197 -47
  309. package/src/components/form-widgets.tsx +9 -7
  310. package/src/components/form.tsx +140 -17
  311. package/src/components/image.tsx +3 -5
  312. package/src/components/link-preview.tsx +5 -4
  313. package/src/components/markdown.tsx +5 -2
  314. package/src/components/message.tsx +23 -4
  315. package/src/components/model-switcher.tsx +19 -4
  316. package/src/components/prompt-input.tsx +46 -75
  317. package/src/components/prompt-suggestion.tsx +48 -16
  318. package/src/components/reasoning.tsx +29 -6
  319. package/src/components/response-compare.tsx +31 -2
  320. package/src/components/screen.tsx +176 -0
  321. package/src/components/tasks-card.tsx +342 -21
  322. package/src/components/toast.tsx +119 -31
  323. package/src/components/tool-types.ts +10 -0
  324. package/src/components/tool.tsx +22 -16
  325. package/src/components/voice-input.tsx +102 -19
  326. package/src/components/voice-output.tsx +202 -0
  327. package/src/elements/agent-card.tsx +67 -0
  328. package/src/elements/artifact.tsx +53 -4
  329. package/src/elements/attachments.tsx +1 -0
  330. package/src/elements/avatar.tsx +33 -0
  331. package/src/elements/badge.tsx +32 -0
  332. package/src/elements/button.tsx +126 -0
  333. package/src/elements/card-media.jpg +0 -0
  334. package/src/elements/card.tsx +124 -31
  335. package/src/elements/cards.tsx +81 -7
  336. package/src/elements/chain-of-thought.tsx +77 -32
  337. package/src/elements/chat-scope-picker.tsx +35 -8
  338. package/src/elements/chat-types.ts +2 -2
  339. package/src/elements/chat-workspace.tsx +153 -41
  340. package/src/elements/chat.tsx +45 -23
  341. package/src/elements/choice.tsx +71 -19
  342. package/src/elements/coachmark.tsx +90 -0
  343. package/src/elements/command.tsx +209 -0
  344. package/src/elements/compare.tsx +24 -2
  345. package/src/elements/compiled.css +1 -1
  346. package/src/elements/composer.tsx +151 -0
  347. package/src/elements/confirm-card.tsx +36 -11
  348. package/src/elements/conversation-list.tsx +80 -11
  349. package/src/elements/default-input.tsx +75 -53
  350. package/src/elements/define.tsx +47 -6
  351. package/src/elements/dialog.tsx +98 -0
  352. package/src/elements/disclosure.ts +73 -0
  353. package/src/elements/editable-label.tsx +125 -0
  354. package/src/elements/element-manifest.json +129 -1
  355. package/src/elements/element-meta.json +5562 -1336
  356. package/src/elements/element-types.d.ts +732 -57
  357. package/src/elements/file-tree.tsx +12 -2
  358. package/src/elements/file-upload.tsx +1 -1
  359. package/src/elements/form.tsx +54 -11
  360. package/src/elements/hover-card.tsx +80 -0
  361. package/src/elements/icon-names.json +48 -0
  362. package/src/elements/icon.tsx +41 -0
  363. package/src/elements/input.tsx +203 -0
  364. package/src/elements/kbd.tsx +45 -0
  365. package/src/elements/menu.tsx +217 -0
  366. package/src/elements/message.tsx +58 -11
  367. package/src/elements/model-switcher.tsx +27 -1
  368. package/src/elements/nav.tsx +87 -0
  369. package/src/elements/notice.tsx +53 -0
  370. package/src/elements/pane-group.tsx +119 -0
  371. package/src/elements/pane.tsx +129 -0
  372. package/src/elements/popover.tsx +39 -17
  373. package/src/elements/progress-bar.tsx +39 -0
  374. package/src/elements/prompt-dock.tsx +81 -0
  375. package/src/elements/prompt-input.tsx +112 -63
  376. package/src/elements/prompt-suggestions.tsx +25 -9
  377. package/src/elements/reasoning.tsx +30 -9
  378. package/src/elements/register-impl.ts +38 -3
  379. package/src/elements/register.ts +11 -3
  380. package/src/elements/resizable.tsx +48 -11
  381. package/src/elements/screen.tsx +90 -0
  382. package/src/elements/scroll-area.tsx +33 -0
  383. package/src/elements/search.tsx +180 -0
  384. package/src/elements/segmented.tsx +135 -0
  385. package/src/elements/separator.tsx +36 -0
  386. package/src/elements/setting-item.tsx +50 -0
  387. package/src/elements/settings-group.tsx +37 -0
  388. package/src/elements/skeleton.tsx +45 -0
  389. package/src/elements/slots.ts +607 -0
  390. package/src/elements/source.tsx +13 -6
  391. package/src/elements/status.tsx +42 -0
  392. package/src/elements/switch.tsx +89 -14
  393. package/src/elements/tabs.tsx +95 -0
  394. package/src/elements/tasks.tsx +70 -14
  395. package/src/elements/toast.tsx +17 -2
  396. package/src/elements/tool.tsx +43 -9
  397. package/src/elements/tooltip.tsx +85 -0
  398. package/src/elements/video-poster.jpg +0 -0
  399. package/src/elements/voice-input.tsx +66 -16
  400. package/src/elements/voice-output.tsx +69 -0
  401. package/src/index.ts +5 -2
  402. package/src/primitives/card-schemas/tasks.schema.json +2 -2
  403. package/src/primitives/composer-model.ts +49 -0
  404. package/src/primitives/composer-triggers.ts +35 -0
  405. package/src/primitives/create-kai-chat.ts +66 -0
  406. package/src/primitives/toast-store.ts +43 -2
  407. package/src/primitives/use-speech-recognition.ts +135 -0
  408. package/src/state/index.ts +6 -0
  409. package/src/state/messages.ts +36 -0
  410. package/src/state/stream.ts +92 -0
  411. package/src/state/suggestions.ts +9 -0
  412. package/src/types.ts +4 -0
  413. package/src/ui/agent-card.tsx +212 -0
  414. package/src/ui/button.tsx +16 -5
  415. package/src/ui/card.tsx +245 -0
  416. package/src/ui/collapsible.tsx +30 -4
  417. package/src/ui/command.tsx +99 -0
  418. package/src/ui/dialog.tsx +217 -0
  419. package/src/ui/dropdown.tsx +375 -13
  420. package/src/ui/editable-label.tsx +112 -0
  421. package/src/ui/hover-card.tsx +28 -5
  422. package/src/ui/icon.tsx +110 -0
  423. package/src/ui/input.tsx +132 -0
  424. package/src/ui/kbd.tsx +118 -0
  425. package/src/ui/nav.tsx +282 -0
  426. package/src/ui/notice.tsx +84 -0
  427. package/src/ui/overlay.tsx +108 -2
  428. package/src/ui/pane-grid.tsx +116 -0
  429. package/src/ui/pane-group.tsx +280 -0
  430. package/src/ui/pane.tsx +193 -0
  431. package/src/ui/popover.tsx +16 -2
  432. package/src/ui/progress-bar.tsx +83 -0
  433. package/src/ui/prompt-dock.tsx +145 -0
  434. package/src/ui/resizable.tsx +69 -1
  435. package/src/ui/scroll-area.tsx +14 -3
  436. package/src/ui/segmented.tsx +109 -0
  437. package/src/ui/settings-group.tsx +67 -0
  438. package/src/ui/skeleton.tsx +62 -5
  439. package/src/ui/stat.tsx +41 -0
  440. package/src/ui/status.tsx +48 -0
  441. package/src/ui/switch.tsx +49 -23
  442. package/src/ui/tabs.tsx +168 -0
  443. package/src/ui/tooltip.tsx +52 -8
  444. package/theme.css +113 -0
  445. package/dist/components/slash-command.d.ts +0 -15
  446. package/dist/elements/chunks/Icon-D_Zmwmwh.js +0 -1
  447. package/dist/elements/chunks/action-icons-PVfIvcuG.js +0 -1
  448. package/dist/elements/chunks/attachments-Dp6vqtrc.js +0 -1
  449. package/dist/elements/chunks/button-CKyYD9G4.js +0 -1
  450. package/dist/elements/chunks/card-Cjho-PYk.js +0 -1
  451. package/dist/elements/chunks/chat-thread-RT808iPf.js +0 -1
  452. package/dist/elements/chunks/check-CDYaMYrM.js +0 -1
  453. package/dist/elements/chunks/chevron-down-3SBiq8HF.js +0 -1
  454. package/dist/elements/chunks/chevron-right-k2UFlIVK.js +0 -1
  455. package/dist/elements/chunks/cn-Dogu6PbV.js +0 -1
  456. package/dist/elements/chunks/code-block-BYUmfFSd.js +0 -1
  457. package/dist/elements/chunks/collapsible-BiNwdOn6.js +0 -1
  458. package/dist/elements/chunks/context-18g6oi4J.js +0 -1
  459. package/dist/elements/chunks/conversation-list-D9Y0NVdo.js +0 -1
  460. package/dist/elements/chunks/default-input-CSAoYYMd.js +0 -1
  461. package/dist/elements/chunks/download-D8K0Je8r.js +0 -1
  462. package/dist/elements/chunks/dropdown-bUs2iTia.js +0 -1
  463. package/dist/elements/chunks/external-link-6mA0wxab.js +0 -1
  464. package/dist/elements/chunks/file-text-DnaYk3Dm.js +0 -1
  465. package/dist/elements/chunks/file-tree-CgtRLlxK.js +0 -1
  466. package/dist/elements/chunks/hover-card-CIGw62gP.js +0 -1
  467. package/dist/elements/chunks/link-BlGSeoPy.js +0 -1
  468. package/dist/elements/chunks/loader-DvhR4qa0.js +0 -1
  469. package/dist/elements/chunks/message-CDZwXjhL.js +0 -1
  470. package/dist/elements/chunks/message-feedback-CYx81QiA.js +0 -1
  471. package/dist/elements/chunks/model-switcher-O_tUhoOT.js +0 -1
  472. package/dist/elements/chunks/overlay-DydXYMQW.js +0 -1
  473. package/dist/elements/chunks/prompt-suggestion-ldlWV5kd.js +0 -1
  474. package/dist/elements/chunks/reasoning-2PUnHlmr.js +0 -1
  475. package/dist/elements/chunks/resizable-B5WNbSeb.js +0 -1
  476. package/dist/elements/chunks/star-t9tI-P0q.js +0 -1
  477. package/dist/elements/chunks/store-C6rIooZz.js +0 -1
  478. package/dist/elements/chunks/text-shimmer-uh9V_KUh.js +0 -1
  479. package/dist/elements/chunks/textarea-3nm6Ia9U.js +0 -1
  480. package/dist/elements/chunks/thumbs-up-BBtguGld.js +0 -1
  481. package/dist/elements/chunks/toast-store-D8cL3fWl.js +0 -1
  482. package/dist/elements/chunks/tool-GJ3vwp1U.js +0 -1
  483. package/dist/elements/chunks/tooltip-DwKAz4XR.js +0 -1
  484. package/dist/elements/chunks/triangle-alert-Ct1zt2JL.js +0 -1
  485. package/dist/elements/chunks/use-card-resolution-D-_0Alzy.js +0 -1
  486. package/dist/elements/chunks/video-mVYiM99-.js +0 -1
  487. package/dist/elements/chunks/x-CzxL27Ch.js +0 -1
  488. package/dist/kitn-chat.es.js +0 -1
  489. package/dist/register-JyTglR6m.js +0 -1
  490. package/dist/register-impl-C6wlSsts.js +0 -77
  491. package/src/components/slash-command.tsx +0 -232
  492. package/src/elements/framework-usage.json +0 -588
  493. /package/dist/{kitn-chat-provider.d.ts → kai-provider.d.ts} +0 -0
  494. /package/dist/{kitn-chat-provider.es.js → kai-provider.es.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { defineWebComponent } from './define';
2
- import { VoiceInput } from '../components/voice-input';
2
+ import { VoiceInput, type VoiceInputController } from '../components/voice-input';
3
3
 
4
4
  interface Props extends Record<string, unknown> {
5
5
  /**
@@ -10,32 +10,82 @@ interface Props extends Record<string, unknown> {
10
10
  transcribe?: (audio: Blob) => Promise<string>;
11
11
  /** Disable the mic button (non-interactive). */
12
12
  disabled?: boolean;
13
+ /**
14
+ * BCP-47 language tag for the native `SpeechRecognition` path (e.g. `en-US`).
15
+ * Attribute: `recognition-lang` (the plain `lang` attribute is reserved by
16
+ * `HTMLElement` and can't be a custom-element property). No effect when
17
+ * `transcribe` is set or the browser lacks SpeechRecognition.
18
+ */
19
+ recognitionLang?: string;
20
+ /** Emit live partial transcripts (`kai-transcript-interim`) during native
21
+ * recognition. Attribute: `interim`. No-op on the transcribe/fallback paths. */
22
+ interim?: boolean;
13
23
  }
14
24
 
15
25
  /** Events fired by `<kai-voice-input>`. */
16
26
  interface Events {
17
27
  /** Raw audio captured (before transcription) — for hosts that prefer to
18
- * handle transcription themselves instead of via the `transcribe` property. */
28
+ * handle transcription themselves instead of via the `transcribe` property.
29
+ * Also the unsupported-fallback signal: no `transcribe`, no SpeechRecognition,
30
+ * so only the blob is produced (no text). */
19
31
  'kai-audio-captured': { blob: Blob };
20
- /** Transcription completed (the `transcribe` property resolved). */
32
+ /** Final transcript the `transcribe` property resolved, OR native
33
+ * `SpeechRecognition` produced final text (no `transcribe` set). */
21
34
  'kai-transcription': { text: string };
35
+ /** Live partial transcript during native recognition (only when `interim` is
36
+ * set). Fires repeatedly before the final `kai-transcription`. */
37
+ 'kai-transcript-interim': { text: string };
38
+ /** Recording started or stopped — lets the host drive its own UI (waveform,
39
+ * push-to-talk indicator) in sync with the mic. Fires on real transitions
40
+ * only (manual click and programmatic start()/stop()), never on mount. */
41
+ 'kai-recording-change': { recording: boolean };
22
42
  }
23
43
 
24
44
  /**
25
- * `<kai-voice-input>` — a mic button that records and transcribes. The
26
- * canonical **function-property** element: set `el.transcribe` to your async
27
- * transcriber. Also emits `kai-audio-captured` (raw blob) and `kai-transcription` (text).
45
+ * `<kai-voice-input>` — a mic button that records and transcribes. Works
46
+ * natively by default: with no `transcribe` callback it uses the browser's
47
+ * `SpeechRecognition` (Chrome/Safari; no Firefox — and cloud-based in Chrome).
48
+ * Set `el.transcribe` to route audio through your own async transcriber instead.
49
+ * Where neither is available it records the blob and emits `kai-audio-captured`
50
+ * with no text. Also emits `kai-transcription` (final text) and, with `interim`,
51
+ * `kai-transcript-interim` (live partials).
28
52
  */
29
53
  defineWebComponent<Props, Events>('kai-voice-input', {
30
54
  transcribe: undefined,
31
55
  disabled: false,
32
- }, (props, { dispatch, flag }) => (
33
- <VoiceInput
34
- disabled={flag('disabled')}
35
- onTranscribe={async (blob) => {
36
- dispatch('kai-audio-captured', { blob });
37
- return props.transcribe ? props.transcribe(blob) : '';
38
- }}
39
- onTranscription={(text) => dispatch('kai-transcription', { text })}
40
- />
41
- ));
56
+ recognitionLang: undefined,
57
+ interim: false,
58
+ }, (props, { dispatch, flag, expose }) => {
59
+ // Pattern C: the VoiceInput component owns useVoiceRecorder; it hands up a
60
+ // start/stop controller and an onRecordingChange callback. The facade captures
61
+ // the controller and exposes delegating methods (start/stop both run the same
62
+ // record→transcribe path as the mic click, so manual + programmatic emit the
63
+ // same kai-audio-captured/kai-transcription/kai-recording-change events).
64
+ let controller: VoiceInputController | undefined;
65
+ expose({
66
+ /** Begin recording programmatically (e.g. push-to-talk bound to a global
67
+ * key). Runs the same getUserMedia path as clicking the mic; no-ops if
68
+ * already recording. */
69
+ start: () => controller?.start(),
70
+ /** Stop the in-progress recording, producing the blob (→ kai-audio-captured)
71
+ * and running transcription. Pairs with start() for push-to-talk. */
72
+ stop: () => controller?.stop(),
73
+ });
74
+
75
+ return (
76
+ <VoiceInput
77
+ disabled={flag('disabled')}
78
+ hasTranscribe={typeof props.transcribe === 'function'}
79
+ lang={props.recognitionLang}
80
+ interim={flag('interim')}
81
+ onTranscribe={async (blob) => {
82
+ dispatch('kai-audio-captured', { blob });
83
+ return props.transcribe ? props.transcribe(blob) : '';
84
+ }}
85
+ onTranscription={(text) => dispatch('kai-transcription', { text })}
86
+ onInterim={(text) => dispatch('kai-transcript-interim', { text })}
87
+ onRecordingChange={(recording) => dispatch('kai-recording-change', { recording })}
88
+ controllerRef={(c) => (controller = c)}
89
+ />
90
+ );
91
+ });
@@ -0,0 +1,69 @@
1
+ import { defineWebComponent } from './define';
2
+ import { VoiceOutput, type VoiceOutputController } from '../components/voice-output';
3
+
4
+ interface Props extends Record<string, unknown> {
5
+ /** The utterance to read aloud. */
6
+ text?: string;
7
+ /** Speak automatically when `text` is set/changed. */
8
+ autoplay?: boolean;
9
+ /**
10
+ * TTS model seam the host supplies — given text, returns an audio `Blob` to
11
+ * play. This is a **function-valued property** (`el.synthesize = async text =>
12
+ * blob`); when set, the native `speechSynthesis` path is bypassed. Mirrors
13
+ * `<kai-voice-input>`'s `transcribe`. A value-returning callback can't be
14
+ * modelled as a fire-and-forget event, hence a property.
15
+ */
16
+ synthesize?: (text: string) => Promise<Blob>;
17
+ /** Disable the button (non-interactive). */
18
+ disabled?: boolean;
19
+ }
20
+
21
+ /** Events fired by `<kai-voice-output>`. */
22
+ interface Events {
23
+ /** Playback started or stopped — drive your own UI in sync. Fires on real
24
+ * transitions only (manual click and programmatic speak()/stop()), never on mount. */
25
+ 'kai-speaking-change': { speaking: boolean };
26
+ /** The model path (`synthesize`) resolved audio — the raw `Blob` before playback. */
27
+ 'kai-synthesized': { blob: Blob };
28
+ }
29
+
30
+ /**
31
+ * `<kai-voice-output>` — a speaker button that reads `text` aloud. Native by
32
+ * default (`speechSynthesis`); set `el.synthesize` to route through your TTS
33
+ * model instead. The output sibling of `<kai-voice-input>`. Emits
34
+ * `kai-speaking-change` and (model path) `kai-synthesized`.
35
+ */
36
+ defineWebComponent<Props, Events>('kai-voice-output', {
37
+ text: '',
38
+ autoplay: false,
39
+ synthesize: undefined,
40
+ disabled: false,
41
+ }, (props, { dispatch, flag, expose }) => {
42
+ // Pattern C: the VoiceOutput component owns playback; it hands up a
43
+ // speak/pause/resume/stop controller. The facade captures it and exposes
44
+ // delegating methods (manual + programmatic run the same path, so both emit
45
+ // the same kai-speaking-change / kai-synthesized events).
46
+ let controller: VoiceOutputController | undefined;
47
+ expose({
48
+ /** Speak the current `text` (native, or via `synthesize` if set). */
49
+ speak: () => controller?.speak(),
50
+ /** Pause playback (resumable). */
51
+ pause: () => controller?.pause(),
52
+ /** Resume paused playback. */
53
+ resume: () => controller?.resume(),
54
+ /** Stop playback and reset. */
55
+ stop: () => controller?.stop(),
56
+ });
57
+
58
+ return (
59
+ <VoiceOutput
60
+ text={(props.text as string | undefined) ?? ''}
61
+ autoplay={flag('autoplay')}
62
+ disabled={flag('disabled')}
63
+ onSynthesize={props.synthesize ? (text) => props.synthesize!(text) : undefined}
64
+ onSpeakingChange={(speaking) => dispatch('kai-speaking-change', { speaking })}
65
+ onSynthesized={(blob) => dispatch('kai-synthesized', { blob })}
66
+ controllerRef={(c) => (controller = c)}
67
+ />
68
+ );
69
+ });
package/src/index.ts CHANGED
@@ -5,6 +5,8 @@ export type { ModelOption, SearchFilters, ConversationScope, ConversationSummary
5
5
  export { cn } from './utils/cn';
6
6
 
7
7
  // Layer 1: Headless Primitives
8
+ export { createKaiChat } from './primitives/create-kai-chat';
9
+ export type { CreateKaiChatOptions, KaiChatStore } from './primitives/create-kai-chat';
8
10
  export { useAutoResize } from './primitives/use-auto-resize';
9
11
  export { useStickToBottom } from './primitives/use-stick-to-bottom';
10
12
  export { useTextStream } from './primitives/use-text-stream';
@@ -204,8 +206,6 @@ export {
204
206
  PromptInput, PromptInputTextarea, PromptInputActions, PromptInputAction,
205
207
  usePromptInput,
206
208
  } from './components/prompt-input';
207
- export { SlashCommand } from './components/slash-command';
208
- export type { SlashCommandItem, SlashCommandProps } from './components/slash-command';
209
209
  export { ResponseStream } from './components/response-stream';
210
210
  export { Markdown } from './components/markdown';
211
211
  export { CodeBlock, CodeBlockCode, CodeBlockGroup } from './components/code-block';
@@ -281,3 +281,6 @@ export type {
281
281
  AttachmentInfoProps, AttachmentRemoveProps, AttachmentEmptyProps,
282
282
  AttachmentHoverCardProps, AttachmentHoverCardTriggerProps, AttachmentHoverCardContentProps,
283
283
  } from './components/attachments';
284
+
285
+ // Chat message types — public API for consumers who need to type their own message arrays.
286
+ export type { ChatMessage, ChatMessageAction, CustomAction, AvatarData, FeedbackVote } from './elements/chat-types';
@@ -8,9 +8,9 @@
8
8
  "properties": {
9
9
  "mode": {
10
10
  "type": "string",
11
- "enum": ["select"],
11
+ "enum": ["select", "progress"],
12
12
  "default": "select",
13
- "description": "v1 supports only 'select' (toggle + confirm). 'progress' (live AG-UI status) is a future enum value; restricting it now keeps the wire forward-compatible.",
13
+ "description": "'select' (default) = toggle + a confirm button that emits `submit`. 'progress' = an onboarding-checklist look (header `done / total` count, circular indicators, per-item title/description, no confirm button, where checking a row IS the action). Both share the selection model.",
14
14
  "x-kai-mode": true
15
15
  },
16
16
  "heading": {
@@ -0,0 +1,49 @@
1
+ export interface EntityRef {
2
+ kind: string;
3
+ id: string;
4
+ label: string;
5
+ icon?: string;
6
+ promptText?: string;
7
+ data?: Record<string, unknown>;
8
+ }
9
+ export type Segment =
10
+ | { type: 'text'; text: string }
11
+ | { type: 'entity'; entity: EntityRef };
12
+ export type ComposerDoc = Segment[];
13
+
14
+ export function normalizeValue(value: string | ComposerDoc | null | undefined): ComposerDoc {
15
+ if (value == null) return [];
16
+ if (typeof value === 'string') return value.length ? [{ type: 'text', text: value }] : [];
17
+ const out: ComposerDoc = [];
18
+ for (const seg of value) {
19
+ if (seg.type === 'text') {
20
+ if (!seg.text) continue;
21
+ const last = out[out.length - 1];
22
+ // Replace (don't mutate) the prior segment so every object in the returned
23
+ // doc is freshly built and never an aliased/held reference.
24
+ if (last && last.type === 'text') out[out.length - 1] = { type: 'text', text: last.text + seg.text };
25
+ else out.push({ type: 'text', text: seg.text });
26
+ } else {
27
+ out.push({ type: 'entity', entity: seg.entity });
28
+ }
29
+ }
30
+ return out;
31
+ }
32
+
33
+ export function serializeToText(
34
+ doc: ComposerDoc,
35
+ opts?: { entity?: (e: EntityRef) => string },
36
+ ): string {
37
+ let out = '';
38
+ for (const seg of doc) {
39
+ if (seg.type === 'text') out += seg.text;
40
+ else out += opts?.entity ? opts.entity(seg.entity) : (seg.entity.promptText ?? seg.entity.label);
41
+ }
42
+ return out;
43
+ }
44
+ export function entitiesOf(doc: ComposerDoc): EntityRef[] {
45
+ return doc.filter((s): s is Extract<Segment, { type: 'entity' }> => s.type === 'entity').map((s) => s.entity);
46
+ }
47
+ export function docIsEmpty(doc: ComposerDoc): boolean {
48
+ return doc.every((s) => s.type === 'text' && s.text.length === 0);
49
+ }
@@ -0,0 +1,35 @@
1
+ export interface ActiveTrigger { char: string; query: string; start: number; }
2
+
3
+ export function detectTrigger(text: string, caret: number, chars: string[]): ActiveTrigger | null {
4
+ // Caret is a position within `text` (0..text.length). Out-of-range = no trigger.
5
+ if (caret < 0 || caret > text.length) return null;
6
+ for (let i = caret - 1; i >= 0; i--) {
7
+ const c = text[i];
8
+ if (/\s/.test(c)) return null; // hit whitespace before any trigger char
9
+ if (chars.includes(c)) {
10
+ const boundaryOk = i === 0 || /\s/.test(text[i - 1]);
11
+ if (!boundaryOk) return null;
12
+ return { char: c, query: text.slice(i + 1, caret), start: i };
13
+ }
14
+ }
15
+ return null;
16
+ }
17
+
18
+ /**
19
+ * Wraps detectTrigger with a list of trigger definitions.
20
+ * Returns { def, query, start } when a trigger is active, else null.
21
+ * Accepts generic defs so it does not import from composer.tsx (no cycle).
22
+ */
23
+ export function activeTriggerFor<T extends { char: string; kind: string }>(
24
+ text: string,
25
+ caret: number,
26
+ defs: T[],
27
+ ): { def: T; query: string; start: number } | null {
28
+ if (!defs.length) return null;
29
+ const chars = defs.map((d) => d.char);
30
+ const hit = detectTrigger(text, caret, chars);
31
+ if (!hit) return null;
32
+ const def = defs.find((d) => d.char === hit.char);
33
+ if (!def) return null;
34
+ return { def, query: hit.query, start: hit.start };
35
+ }
@@ -0,0 +1,66 @@
1
+ // src/primitives/create-kai-chat.ts
2
+ import { createSignal } from 'solid-js';
3
+ import type { ChatMessage } from '../elements/chat-types';
4
+ import type { AttachmentData } from '../components/attachments';
5
+ import {
6
+ appendMessage, updateMessage, removeMessage, addSuggestion, removeSuggestion,
7
+ createAssistantStream, onStreamSettled, type AssistantStream, type SetMessages,
8
+ } from '../state';
9
+
10
+ export interface CreateKaiChatOptions {
11
+ /** Seed messages, read once at creation and copied. Later changes are ignored — drive updates through the returned ops. */
12
+ initialMessages?: ChatMessage[];
13
+ /** Seed suggestions, read once at creation and copied. Later changes are ignored. */
14
+ initialSuggestions?: string[];
15
+ onSubmit?: (detail: { value: string; attachments: AttachmentData[] }) => void | Promise<void>;
16
+ }
17
+
18
+ /** Solid store: consumer-owned chat state + the same ergonomic ops as `useKaiChat`. */
19
+ export interface KaiChatStore {
20
+ messages: () => ChatMessage[];
21
+ setMessages: SetMessages;
22
+ suggestions: () => string[];
23
+ loading: () => boolean;
24
+ append: (msg: ChatMessage) => void;
25
+ update: (id: string, patch: Partial<ChatMessage> | ((m: ChatMessage) => ChatMessage)) => void;
26
+ remove: (id: string) => void;
27
+ addSuggestion: (s: string) => void;
28
+ removeSuggestion: (s: string) => void;
29
+ clearSuggestions: () => void;
30
+ streamAssistant: (init?: Partial<ChatMessage>) => AssistantStream;
31
+ handleSubmit: (event: CustomEvent<{ value: string; attachments: AttachmentData[] }>) => void;
32
+ /** Spread onto `<kai-chat {...chat.bind} />` (reactive getters). Wire submit via `on:kai-submit={chat.handleSubmit}`. */
33
+ bind: { readonly messages: ChatMessage[]; readonly loading: boolean; readonly suggestions: string[] };
34
+ }
35
+
36
+ export function createKaiChat(options: CreateKaiChatOptions = {}): KaiChatStore {
37
+ // Copy the seed arrays so a caller mutating the array it passed in can't reach our state.
38
+ const [messages, setMessagesSignal] = createSignal<ChatMessage[]>([...(options.initialMessages ?? [])]);
39
+ const [suggestions, setSuggestions] = createSignal<string[]>([...(options.initialSuggestions ?? [])]);
40
+ const [loading, setLoading] = createSignal(false);
41
+
42
+ const setMessages: SetMessages = (updater) => setMessagesSignal((prev) => updater(prev));
43
+
44
+ return {
45
+ messages,
46
+ setMessages,
47
+ suggestions,
48
+ loading,
49
+ append: (msg) => setMessages((prev) => appendMessage(prev, msg)),
50
+ update: (id, patch) => setMessages((prev) => updateMessage(prev, id, patch)),
51
+ remove: (id) => setMessages((prev) => removeMessage(prev, id)),
52
+ addSuggestion: (s) => setSuggestions((prev) => addSuggestion(prev, s)),
53
+ removeSuggestion: (s) => setSuggestions((prev) => removeSuggestion(prev, s)),
54
+ clearSuggestions: () => setSuggestions([]),
55
+ streamAssistant: (init) => {
56
+ setLoading(true);
57
+ return onStreamSettled(createAssistantStream(setMessages, init), () => setLoading(false));
58
+ },
59
+ handleSubmit: (event) => { void options.onSubmit?.(event.detail); },
60
+ bind: {
61
+ get messages() { return messages(); },
62
+ get loading() { return loading(); },
63
+ get suggestions() { return suggestions(); },
64
+ },
65
+ };
66
+ }
@@ -16,12 +16,20 @@ import { createRoot, createSignal } from 'solid-js';
16
16
  import { createStore, produce } from 'solid-js/store';
17
17
  import type { ToastPosition } from '../components/toast';
18
18
 
19
- export type ToastVariant = 'neutral' | 'success';
19
+ export type ToastVariant = 'neutral' | 'success' | 'warning' | 'error' | 'info';
20
+ /** Visual treatment: `'pill'` (default, compact single-line) or `'card'` (richer
21
+ * rounded card with an optional description line). */
22
+ export type ToastAppearance = 'pill' | 'card';
20
23
 
21
24
  export interface ToastConfig {
22
25
  stack?: 'expanded' | 'collapsed';
23
26
  position?: ToastPosition;
24
27
  max?: number;
28
+ /** Default appearance for imperatively-raised toasts. Defaults to `'pill'`. */
29
+ appearance?: ToastAppearance;
30
+ /** Default high-contrast inverse treatment for imperatively-raised toasts.
31
+ * Defaults to `false`. */
32
+ inverse?: boolean;
25
33
  }
26
34
 
27
35
  // Module-level config the imperative singleton regions inherit. Defaults match
@@ -33,6 +41,11 @@ function applyConfig(el: HTMLElement): void {
33
41
  if (toastConfig.stack) el.setAttribute('stack', toastConfig.stack);
34
42
  if (toastConfig.position) el.setAttribute('position', toastConfig.position);
35
43
  if (toastConfig.max !== undefined) el.setAttribute('max', String(toastConfig.max));
44
+ if (toastConfig.appearance) el.setAttribute('appearance', toastConfig.appearance);
45
+ if (toastConfig.inverse !== undefined) {
46
+ if (toastConfig.inverse) el.setAttribute('inverse', '');
47
+ else el.removeAttribute('inverse');
48
+ }
36
49
  }
37
50
 
38
51
  /**
@@ -59,6 +72,15 @@ export interface ToastItem {
59
72
  id: string;
60
73
  message: string;
61
74
  variant?: ToastVariant;
75
+ /** Visual treatment: `'pill'` (default, compact single-line) or `'card'` (richer
76
+ * rounded card with an optional description line). */
77
+ appearance?: ToastAppearance;
78
+ /** High-contrast inverse surface — works on either appearance, popping in light
79
+ * AND dark. Defaults to `false`. */
80
+ inverse?: boolean;
81
+ /** Secondary line shown below the message in the `'card'` appearance. The
82
+ * `'pill'` appearance ignores it. */
83
+ description?: string;
62
84
  action?: ToastAction;
63
85
  /** Auto-dismiss delay in ms. `0` = sticky (never auto-dismisses). When an
64
86
  * `action` is present the effective floor is 4000ms so it stays long enough
@@ -77,6 +99,13 @@ export interface ToastItem {
77
99
  export interface ToastOptions {
78
100
  id?: string;
79
101
  variant?: ToastVariant;
102
+ /** Visual treatment: `'pill'` (default) or `'card'`. Falls back to the value set
103
+ * via `configureToasts`, then `'pill'`. */
104
+ appearance?: ToastAppearance;
105
+ /** High-contrast inverse surface. Falls back to `configureToasts`, then `false`. */
106
+ inverse?: boolean;
107
+ /** Secondary line shown below the message in the `'card'` appearance. */
108
+ description?: string;
80
109
  action?: ToastAction;
81
110
  duration?: number;
82
111
  dismissible?: boolean;
@@ -193,6 +222,9 @@ function raise(message: string, opts: ToastOptions | undefined, variant: ToastVa
193
222
  id,
194
223
  message,
195
224
  variant: opts?.variant ?? variant,
225
+ appearance: opts?.appearance ?? toastConfig.appearance ?? 'pill',
226
+ inverse: opts?.inverse ?? toastConfig.inverse ?? false,
227
+ description: opts?.description,
196
228
  action: opts?.action,
197
229
  duration: opts?.duration,
198
230
  dismissible: opts?.dismissible,
@@ -204,8 +236,14 @@ function raise(message: string, opts: ToastOptions | undefined, variant: ToastVa
204
236
 
205
237
  export interface ToastFn {
206
238
  (message: string, opts?: ToastOptions): ToastHandle;
207
- /** Raise a success (emerald check) toast. */
239
+ /** Raise a success (green check) toast. */
208
240
  success: (message: string, opts?: ToastOptions) => ToastHandle;
241
+ /** Raise a warning (amber) toast — e.g. an agent needs your input. */
242
+ warning: (message: string, opts?: ToastOptions) => ToastHandle;
243
+ /** Raise an error (destructive/red) toast — e.g. an agent failed. */
244
+ error: (message: string, opts?: ToastOptions) => ToastHandle;
245
+ /** Raise an info (blue) toast. */
246
+ info: (message: string, opts?: ToastOptions) => ToastHandle;
209
247
  /** Dismiss a toast by id. */
210
248
  dismiss: (id: string) => void;
211
249
  /** Dismiss every active toast. */
@@ -226,6 +264,9 @@ export const toast: ToastFn = Object.assign(
226
264
  (message: string, opts?: ToastOptions) => raise(message, opts, 'neutral'),
227
265
  {
228
266
  success: (message: string, opts?: ToastOptions) => raise(message, opts, 'success'),
267
+ warning: (message: string, opts?: ToastOptions) => raise(message, opts, 'warning'),
268
+ error: (message: string, opts?: ToastOptions) => raise(message, opts, 'error'),
269
+ info: (message: string, opts?: ToastOptions) => raise(message, opts, 'info'),
229
270
  dismiss,
230
271
  clear: () => setToasts([]),
231
272
  },
@@ -0,0 +1,135 @@
1
+ import { createSignal, onCleanup } from 'solid-js';
2
+
3
+ // Minimal Web Speech API surface. The DOM lib doesn't ship these types reliably
4
+ // across TS versions, so we declare only what we touch. `webkitSpeechRecognition`
5
+ // is the Chrome/Safari-prefixed constructor; the unprefixed one is rare.
6
+ interface SpeechRecognitionAlternative {
7
+ transcript: string;
8
+ }
9
+ interface SpeechRecognitionResult {
10
+ readonly isFinal: boolean;
11
+ readonly length: number;
12
+ [index: number]: SpeechRecognitionAlternative;
13
+ }
14
+ interface SpeechRecognitionResultList {
15
+ readonly length: number;
16
+ [index: number]: SpeechRecognitionResult;
17
+ }
18
+ interface SpeechRecognitionEventLike {
19
+ readonly resultIndex: number;
20
+ readonly results: SpeechRecognitionResultList;
21
+ }
22
+ interface SpeechRecognitionLike {
23
+ lang: string;
24
+ continuous: boolean;
25
+ interimResults: boolean;
26
+ start(): void;
27
+ stop(): void;
28
+ abort(): void;
29
+ onresult: ((event: SpeechRecognitionEventLike) => void) | null;
30
+ onerror: ((event: { error?: string }) => void) | null;
31
+ onend: (() => void) | null;
32
+ }
33
+ type SpeechRecognitionCtor = new () => SpeechRecognitionLike;
34
+
35
+ function getCtor(): SpeechRecognitionCtor | undefined {
36
+ if (typeof window === 'undefined') return undefined;
37
+ const w = window as unknown as {
38
+ SpeechRecognition?: SpeechRecognitionCtor;
39
+ webkitSpeechRecognition?: SpeechRecognitionCtor;
40
+ };
41
+ return w.SpeechRecognition ?? w.webkitSpeechRecognition;
42
+ }
43
+
44
+ export interface UseSpeechRecognitionOptions {
45
+ /** Emit live, non-final partials via the `onInterim` callback passed to start(). */
46
+ interim?: boolean;
47
+ }
48
+
49
+ export interface SpeechRecognitionStartOptions {
50
+ /** BCP-47 language tag, e.g. `en-US`. */
51
+ lang?: string;
52
+ /** Called with each interim (non-final) transcript when `interim` is enabled. */
53
+ onInterim?: (text: string) => void;
54
+ }
55
+
56
+ /**
57
+ * Wrap the browser's Web Speech `SpeechRecognition` (Chrome/Safari; no Firefox).
58
+ * Mirrors `useVoiceRecorder`'s shape: an `isListening` signal, an `error` signal,
59
+ * and `start`/`stop` controls. `start()` resolves with the final transcript when
60
+ * recognition ends; `stop()` ends the in-progress session (resolving start()).
61
+ *
62
+ * Caveat (documented at the element): in Chrome this is cloud-based — audio is
63
+ * sent to Google — so it is "native to the browser," not on-device/private.
64
+ */
65
+ export function useSpeechRecognition(options: UseSpeechRecognitionOptions = {}) {
66
+ const [isListening, setIsListening] = createSignal(false);
67
+ const [error, setError] = createSignal<string | null>(null);
68
+
69
+ const isSupported = getCtor() !== undefined;
70
+
71
+ let recognition: SpeechRecognitionLike | undefined;
72
+ let resolveText: ((text: string) => void) | undefined;
73
+ let finalText = '';
74
+
75
+ function start(opts: SpeechRecognitionStartOptions = {}): Promise<string> {
76
+ setError(null);
77
+ finalText = '';
78
+ const Ctor = getCtor();
79
+ if (!Ctor) {
80
+ const message = 'SpeechRecognition is not supported in this browser';
81
+ setError(message);
82
+ return Promise.reject(new Error(message));
83
+ }
84
+ try {
85
+ recognition = new Ctor();
86
+ if (opts.lang) recognition.lang = opts.lang;
87
+ recognition.interimResults = options.interim === true;
88
+ recognition.continuous = false;
89
+
90
+ recognition.onresult = (event) => {
91
+ let interim = '';
92
+ for (let i = event.resultIndex; i < event.results.length; i++) {
93
+ const result = event.results[i];
94
+ const transcript = result[0]?.transcript ?? '';
95
+ if (result.isFinal) {
96
+ finalText += transcript;
97
+ } else {
98
+ interim += transcript;
99
+ }
100
+ }
101
+ if (interim && opts.onInterim) opts.onInterim(interim);
102
+ };
103
+
104
+ recognition.onerror = (event) => {
105
+ setError(event.error ?? 'Speech recognition error');
106
+ };
107
+
108
+ recognition.onend = () => {
109
+ setIsListening(false);
110
+ resolveText?.(finalText);
111
+ recognition = undefined;
112
+ };
113
+
114
+ recognition.start();
115
+ setIsListening(true);
116
+ return new Promise<string>((resolve) => { resolveText = resolve; });
117
+ } catch (err) {
118
+ setError(err instanceof Error ? err.message : 'Speech recognition failed to start');
119
+ setIsListening(false);
120
+ throw err;
121
+ }
122
+ }
123
+
124
+ function stop() {
125
+ if (recognition && isListening()) {
126
+ recognition.stop();
127
+ }
128
+ }
129
+
130
+ onCleanup(() => {
131
+ if (recognition) recognition.abort();
132
+ });
133
+
134
+ return { isSupported, isListening, error, start, stop };
135
+ }
@@ -0,0 +1,6 @@
1
+ // Framework-neutral state core for @kitn.ai/ui. Pure functions over ChatMessage[]
2
+ // + a typed streaming handle. No React/Solid runtime — drives a consumer setter.
3
+ export { appendMessage, upsertMessage, updateMessage, removeMessage, appendContent } from './messages';
4
+ export { addSuggestion, removeSuggestion } from './suggestions';
5
+ export { createAssistantStream, onStreamSettled } from './stream';
6
+ export type { SetMessages, AssistantStream } from './stream';
@@ -0,0 +1,36 @@
1
+ import type { ChatMessage } from '../elements/chat-types';
2
+
3
+ /** Append a message; returns a new array. */
4
+ export function appendMessage(messages: ChatMessage[], msg: ChatMessage): ChatMessage[] {
5
+ return [...messages, msg];
6
+ }
7
+
8
+ /** Replace a same-id message, or append when absent. */
9
+ export function upsertMessage(messages: ChatMessage[], msg: ChatMessage): ChatMessage[] {
10
+ const i = messages.findIndex((x) => x.id === msg.id);
11
+ if (i === -1) return [...messages, msg];
12
+ const next = messages.slice();
13
+ next[i] = msg;
14
+ return next;
15
+ }
16
+
17
+ /** Patch the matched message (object patch or updater). Untouched items keep their reference. */
18
+ export function updateMessage(
19
+ messages: ChatMessage[],
20
+ id: string,
21
+ patch: Partial<ChatMessage> | ((m: ChatMessage) => ChatMessage),
22
+ ): ChatMessage[] {
23
+ return messages.map((x) =>
24
+ x.id === id ? (typeof patch === 'function' ? patch(x) : { ...x, ...patch }) : x,
25
+ );
26
+ }
27
+
28
+ /** Remove the matched message. */
29
+ export function removeMessage(messages: ChatMessage[], id: string): ChatMessage[] {
30
+ return messages.filter((x) => x.id !== id);
31
+ }
32
+
33
+ /** Streaming primitive: concatenate `delta` onto the matched message's content. */
34
+ export function appendContent(messages: ChatMessage[], id: string, delta: string): ChatMessage[] {
35
+ return messages.map((x) => (x.id === id ? { ...x, content: x.content + delta } : x));
36
+ }