@elabs-ai/components-ai 4.1.0 → 5.0.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 (527) hide show
  1. package/README.md +3 -3
  2. package/dist/{_audio-player-media-chrome-T3XVXWRZ.js → _audio-player-media-chrome.js} +1 -1
  3. package/dist/_code-block-theme.js +12 -0
  4. package/dist/_code-block-theme.js.map +1 -0
  5. package/dist/{_flow-boundary-SHNWLQG5.js → _flow-boundary.js} +1 -1
  6. package/dist/_flow-boundary.js.map +1 -0
  7. package/dist/_flow-lazy.js +8 -0
  8. package/dist/_flow-lazy.js.map +1 -0
  9. package/dist/_lazy-boundary-conformance.js +2 -0
  10. package/dist/_lazy-boundary-conformance.js.map +1 -0
  11. package/dist/_lazy-cjk.js +13 -0
  12. package/dist/_lazy-cjk.js.map +1 -0
  13. package/dist/_lazy-engine-boundary.js +9 -0
  14. package/dist/_lazy-engine-boundary.js.map +1 -0
  15. package/dist/_lazy-math.js +13 -0
  16. package/dist/_lazy-math.js.map +1 -0
  17. package/dist/_lazy-mermaid.js +12 -0
  18. package/dist/_lazy-mermaid.js.map +1 -0
  19. package/dist/_mermaid-error-panel.js +9 -0
  20. package/dist/_mermaid-error-panel.js.map +1 -0
  21. package/dist/{_persona-rive-JEG44YHX.js → _persona-rive.js} +19 -24
  22. package/dist/_persona-rive.js.map +1 -0
  23. package/dist/_streamdown-i18n.js +21 -0
  24. package/dist/_streamdown-i18n.js.map +1 -0
  25. package/dist/_streamdown-safety.js +10 -0
  26. package/dist/_streamdown-safety.js.map +1 -0
  27. package/dist/_theme-scope-store.js +13 -0
  28. package/dist/_theme-scope-store.js.map +1 -0
  29. package/dist/a2ui/a2ui-surface.js +17 -0
  30. package/dist/a2ui/a2ui-surface.js.map +1 -0
  31. package/dist/a2ui/core/catalog.generated.js +10 -0
  32. package/dist/a2ui/core/catalog.generated.js.map +1 -0
  33. package/dist/a2ui/core/complete-json.js +10 -0
  34. package/dist/a2ui/core/complete-json.js.map +1 -0
  35. package/dist/a2ui/core/index.js +37 -0
  36. package/dist/a2ui/core/index.js.map +1 -0
  37. package/dist/a2ui/core/schema.js +11 -0
  38. package/dist/a2ui/core/schema.js.map +1 -0
  39. package/dist/a2ui/core/spec.js +10 -0
  40. package/dist/a2ui/core/spec.js.map +1 -0
  41. package/dist/a2ui/core/validate.js +16 -0
  42. package/dist/a2ui/core/validate.js.map +1 -0
  43. package/dist/a2ui/index.js +54 -0
  44. package/dist/a2ui/index.js.map +1 -0
  45. package/dist/a2ui/ui-catalog.js +18 -0
  46. package/dist/a2ui/ui-catalog.js.map +1 -0
  47. package/dist/agent-event.js +10 -0
  48. package/dist/agent-event.js.map +1 -0
  49. package/dist/agent-timeline.js +11 -0
  50. package/dist/agent-timeline.js.map +1 -0
  51. package/dist/agent.js +25 -0
  52. package/dist/agent.js.map +1 -0
  53. package/dist/artifact.js +23 -0
  54. package/dist/artifact.js.map +1 -0
  55. package/dist/asset-preview.js +22 -0
  56. package/dist/asset-preview.js.map +1 -0
  57. package/dist/attachments.js +33 -0
  58. package/dist/attachments.js.map +1 -0
  59. package/dist/audio-player.js +30 -0
  60. package/dist/audio-player.js.map +1 -0
  61. package/dist/audio-visualizer.js +9 -0
  62. package/dist/audio-visualizer.js.map +1 -0
  63. package/dist/canvas.js +10 -0
  64. package/dist/canvas.js.map +1 -0
  65. package/dist/chain-of-thought.js +22 -0
  66. package/dist/chain-of-thought.js.map +1 -0
  67. package/dist/chat-greeting.js +8 -0
  68. package/dist/chat-greeting.js.map +1 -0
  69. package/dist/chat-shell.js +9 -0
  70. package/dist/chat-shell.js.map +1 -0
  71. package/dist/checkpoint.js +13 -0
  72. package/dist/checkpoint.js.map +1 -0
  73. package/dist/chunk-2XOIG5TG.js +72 -0
  74. package/dist/chunk-2XOIG5TG.js.map +1 -0
  75. package/dist/chunk-34CQ2VHM.js +172 -0
  76. package/dist/chunk-34CQ2VHM.js.map +1 -0
  77. package/dist/chunk-3TDHPXZZ.js +60 -0
  78. package/dist/chunk-3TDHPXZZ.js.map +1 -0
  79. package/dist/chunk-3XNPMDZY.js +478 -0
  80. package/dist/chunk-3XNPMDZY.js.map +1 -0
  81. package/dist/chunk-3YPT3V7L.js +56 -0
  82. package/dist/chunk-3YPT3V7L.js.map +1 -0
  83. package/dist/chunk-475UEU2Q.js +87 -0
  84. package/dist/chunk-475UEU2Q.js.map +1 -0
  85. package/dist/chunk-4CBTII2I.js +95 -0
  86. package/dist/chunk-4CBTII2I.js.map +1 -0
  87. package/dist/chunk-4XRNIZMG.js +22 -0
  88. package/dist/chunk-4XRNIZMG.js.map +1 -0
  89. package/dist/chunk-5NNWUKK5.js +2 -0
  90. package/dist/chunk-5NNWUKK5.js.map +1 -0
  91. package/dist/chunk-5UOMU27Z.js +164 -0
  92. package/dist/chunk-5UOMU27Z.js.map +1 -0
  93. package/dist/chunk-5VGYZ62I.js +264 -0
  94. package/dist/chunk-5VGYZ62I.js.map +1 -0
  95. package/dist/chunk-6IQPH2OS.js +21 -0
  96. package/dist/chunk-6IQPH2OS.js.map +1 -0
  97. package/dist/chunk-6PB2MXCI.js +482 -0
  98. package/dist/chunk-6PB2MXCI.js.map +1 -0
  99. package/dist/chunk-7FD5CZEU.js +215 -0
  100. package/dist/chunk-7FD5CZEU.js.map +1 -0
  101. package/dist/chunk-7RL6KZDF.js +266 -0
  102. package/dist/chunk-7RL6KZDF.js.map +1 -0
  103. package/dist/chunk-ADOYAGGK.js +482 -0
  104. package/dist/chunk-ADOYAGGK.js.map +1 -0
  105. package/dist/chunk-AXMNJMMH.js +984 -0
  106. package/dist/chunk-AXMNJMMH.js.map +1 -0
  107. package/dist/chunk-BA3AEMOU.js +21 -0
  108. package/dist/chunk-BA3AEMOU.js.map +1 -0
  109. package/dist/chunk-BBHFOYML.js +336 -0
  110. package/dist/chunk-BBHFOYML.js.map +1 -0
  111. package/dist/chunk-BHUVISIY.js +221 -0
  112. package/dist/chunk-BHUVISIY.js.map +1 -0
  113. package/dist/chunk-BM2LWERA.js +100 -0
  114. package/dist/chunk-BM2LWERA.js.map +1 -0
  115. package/dist/chunk-CMOYXNPJ.js +211 -0
  116. package/dist/chunk-CMOYXNPJ.js.map +1 -0
  117. package/dist/chunk-CZP3RHC4.js +74 -0
  118. package/dist/chunk-CZP3RHC4.js.map +1 -0
  119. package/dist/chunk-DDG5JHQT.js +112 -0
  120. package/dist/chunk-DDG5JHQT.js.map +1 -0
  121. package/dist/chunk-DJODXO7I.js +38 -0
  122. package/dist/chunk-DJODXO7I.js.map +1 -0
  123. package/dist/chunk-DWJDJLPU.js +192 -0
  124. package/dist/chunk-DWJDJLPU.js.map +1 -0
  125. package/dist/chunk-DZW6LM22.js +45 -0
  126. package/dist/chunk-DZW6LM22.js.map +1 -0
  127. package/dist/chunk-ELGCZLZF.js +305 -0
  128. package/dist/chunk-ELGCZLZF.js.map +1 -0
  129. package/dist/chunk-EV3U6ZZB.js +209 -0
  130. package/dist/chunk-EV3U6ZZB.js.map +1 -0
  131. package/dist/chunk-EY7LVUKQ.js +87 -0
  132. package/dist/chunk-EY7LVUKQ.js.map +1 -0
  133. package/dist/chunk-F4C74F7M.js +230 -0
  134. package/dist/chunk-F4C74F7M.js.map +1 -0
  135. package/dist/chunk-FERYDFZA.js +108 -0
  136. package/dist/chunk-FERYDFZA.js.map +1 -0
  137. package/dist/chunk-FUIYG2DS.js +166 -0
  138. package/dist/chunk-FUIYG2DS.js.map +1 -0
  139. package/dist/chunk-GKYZT3LA.js +136 -0
  140. package/dist/chunk-GKYZT3LA.js.map +1 -0
  141. package/dist/chunk-H42LRUQ4.js +102 -0
  142. package/dist/chunk-H42LRUQ4.js.map +1 -0
  143. package/dist/chunk-HVXM2G5F.js +222 -0
  144. package/dist/chunk-HVXM2G5F.js.map +1 -0
  145. package/dist/chunk-I4RDAGVY.js +53 -0
  146. package/dist/chunk-I4RDAGVY.js.map +1 -0
  147. package/dist/chunk-IQJG4IDX.js +208 -0
  148. package/dist/chunk-IQJG4IDX.js.map +1 -0
  149. package/dist/chunk-IX2PXG4Y.js +144 -0
  150. package/dist/chunk-IX2PXG4Y.js.map +1 -0
  151. package/dist/chunk-IXICSOOP.js +287 -0
  152. package/dist/chunk-IXICSOOP.js.map +1 -0
  153. package/dist/chunk-JY5HSN4D.js +84 -0
  154. package/dist/chunk-JY5HSN4D.js.map +1 -0
  155. package/dist/chunk-LMNSBOBG.js +19 -0
  156. package/dist/chunk-LMNSBOBG.js.map +1 -0
  157. package/dist/chunk-MBI7D6IL.js +42 -0
  158. package/dist/chunk-MBI7D6IL.js.map +1 -0
  159. package/dist/chunk-MLFMYCPH.js +192 -0
  160. package/dist/chunk-MLFMYCPH.js.map +1 -0
  161. package/dist/chunk-MOK66734.js +33 -0
  162. package/dist/chunk-MOK66734.js.map +1 -0
  163. package/dist/chunk-MXTAWPYM.js +196 -0
  164. package/dist/chunk-MXTAWPYM.js.map +1 -0
  165. package/dist/chunk-NCL2UZKI.js +96 -0
  166. package/dist/chunk-NCL2UZKI.js.map +1 -0
  167. package/dist/chunk-NET4YLRY.js +107 -0
  168. package/dist/chunk-NET4YLRY.js.map +1 -0
  169. package/dist/chunk-NIG67CFM.js +329 -0
  170. package/dist/chunk-NIG67CFM.js.map +1 -0
  171. package/dist/chunk-NMVNNO3L.js +10 -0
  172. package/dist/chunk-NMVNNO3L.js.map +1 -0
  173. package/dist/chunk-NP7VID4K.js +2 -0
  174. package/dist/chunk-NP7VID4K.js.map +1 -0
  175. package/dist/chunk-NPUCMAG2.js +382 -0
  176. package/dist/chunk-NPUCMAG2.js.map +1 -0
  177. package/dist/chunk-NSCLRHES.js +102 -0
  178. package/dist/chunk-NSCLRHES.js.map +1 -0
  179. package/dist/chunk-OEUXHVFW.js +86 -0
  180. package/dist/chunk-OEUXHVFW.js.map +1 -0
  181. package/dist/chunk-ONBHFIMZ.js +137 -0
  182. package/dist/chunk-ONBHFIMZ.js.map +1 -0
  183. package/dist/chunk-OPH2HHL2.js +228 -0
  184. package/dist/chunk-OPH2HHL2.js.map +1 -0
  185. package/dist/chunk-OQERHIQP.js +287 -0
  186. package/dist/chunk-OQERHIQP.js.map +1 -0
  187. package/dist/chunk-P6YJAZFG.js +103 -0
  188. package/dist/chunk-P6YJAZFG.js.map +1 -0
  189. package/dist/chunk-PG7ERDOD.js +65 -0
  190. package/dist/chunk-PG7ERDOD.js.map +1 -0
  191. package/dist/chunk-PIB5JBMA.js +90 -0
  192. package/dist/chunk-PIB5JBMA.js.map +1 -0
  193. package/dist/chunk-PQ5BPIWQ.js +22 -0
  194. package/dist/chunk-PQ5BPIWQ.js.map +1 -0
  195. package/dist/chunk-PQBF6ZIQ.js +55 -0
  196. package/dist/chunk-PQBF6ZIQ.js.map +1 -0
  197. package/dist/chunk-PTWCTSZL.js +173 -0
  198. package/dist/chunk-PTWCTSZL.js.map +1 -0
  199. package/dist/chunk-QJUNPVOS.js +101 -0
  200. package/dist/chunk-QJUNPVOS.js.map +1 -0
  201. package/dist/chunk-QUDZOTRV.js +43 -0
  202. package/dist/chunk-QUDZOTRV.js.map +1 -0
  203. package/dist/chunk-RB7G65JC.js +213 -0
  204. package/dist/chunk-RB7G65JC.js.map +1 -0
  205. package/dist/chunk-RPHAOR7P.js +45 -0
  206. package/dist/chunk-RPHAOR7P.js.map +1 -0
  207. package/dist/chunk-RTCSH2AN.js +331 -0
  208. package/dist/chunk-RTCSH2AN.js.map +1 -0
  209. package/dist/chunk-S3ISPW3A.js +28 -0
  210. package/dist/chunk-S3ISPW3A.js.map +1 -0
  211. package/dist/chunk-SEVN656N.js +36 -0
  212. package/dist/chunk-SEVN656N.js.map +1 -0
  213. package/dist/chunk-SKVG672B.js +64 -0
  214. package/dist/chunk-SKVG672B.js.map +1 -0
  215. package/dist/chunk-SPQIU7GA.js +236 -0
  216. package/dist/chunk-SPQIU7GA.js.map +1 -0
  217. package/dist/chunk-SSGJ6MEM.js +1076 -0
  218. package/dist/chunk-SSGJ6MEM.js.map +1 -0
  219. package/dist/chunk-SSKZ2AED.js +118 -0
  220. package/dist/chunk-SSKZ2AED.js.map +1 -0
  221. package/dist/chunk-T56JFGXI.js +561 -0
  222. package/dist/chunk-T56JFGXI.js.map +1 -0
  223. package/dist/chunk-TCB6O74A.js +137 -0
  224. package/dist/chunk-TCB6O74A.js.map +1 -0
  225. package/dist/chunk-TTEYPO6X.js +57 -0
  226. package/dist/chunk-TTEYPO6X.js.map +1 -0
  227. package/dist/chunk-TWPHAJNM.js +462 -0
  228. package/dist/chunk-TWPHAJNM.js.map +1 -0
  229. package/dist/chunk-TXJJLP4O.js +336 -0
  230. package/dist/chunk-TXJJLP4O.js.map +1 -0
  231. package/dist/chunk-TZ6TB7VM.js +245 -0
  232. package/dist/chunk-TZ6TB7VM.js.map +1 -0
  233. package/dist/chunk-UBLKJJ7K.js +278 -0
  234. package/dist/chunk-UBLKJJ7K.js.map +1 -0
  235. package/dist/chunk-UCJ6IUFS.js +52 -0
  236. package/dist/chunk-UCJ6IUFS.js.map +1 -0
  237. package/dist/chunk-UCKFJ3QF.js +197 -0
  238. package/dist/chunk-UCKFJ3QF.js.map +1 -0
  239. package/dist/chunk-UPXSLILN.js +20 -0
  240. package/dist/chunk-UPXSLILN.js.map +1 -0
  241. package/dist/chunk-V4DORGWJ.js +92 -0
  242. package/dist/chunk-V4DORGWJ.js.map +1 -0
  243. package/dist/chunk-V6E5DYZD.js +80 -0
  244. package/dist/chunk-V6E5DYZD.js.map +1 -0
  245. package/dist/chunk-VLLYKF3P.js +96 -0
  246. package/dist/chunk-VLLYKF3P.js.map +1 -0
  247. package/dist/chunk-VLNBTOH6.js +43 -0
  248. package/dist/chunk-VLNBTOH6.js.map +1 -0
  249. package/dist/chunk-WMDSMSPL.js +303 -0
  250. package/dist/chunk-WMDSMSPL.js.map +1 -0
  251. package/dist/chunk-WU5BLGTF.js +149 -0
  252. package/dist/chunk-WU5BLGTF.js.map +1 -0
  253. package/dist/chunk-WYTZVSGK.js +245 -0
  254. package/dist/chunk-WYTZVSGK.js.map +1 -0
  255. package/dist/chunk-X47QMM6K.js +187 -0
  256. package/dist/chunk-X47QMM6K.js.map +1 -0
  257. package/dist/chunk-XNBKO32Y.js +174 -0
  258. package/dist/chunk-XNBKO32Y.js.map +1 -0
  259. package/dist/chunk-YHUSW7D2.js +40 -0
  260. package/dist/chunk-YHUSW7D2.js.map +1 -0
  261. package/dist/chunk-YSKD7UXX.js +126 -0
  262. package/dist/chunk-YSKD7UXX.js.map +1 -0
  263. package/dist/chunk-YYRDGWOU.js +72 -0
  264. package/dist/chunk-YYRDGWOU.js.map +1 -0
  265. package/dist/chunk-ZIGZMWM7.js +19 -0
  266. package/dist/chunk-ZIGZMWM7.js.map +1 -0
  267. package/dist/chunk-ZKRTUKNP.js +40 -0
  268. package/dist/chunk-ZKRTUKNP.js.map +1 -0
  269. package/dist/code-block.js +38 -0
  270. package/dist/code-block.js.map +1 -0
  271. package/dist/commit.js +51 -0
  272. package/dist/commit.js.map +1 -0
  273. package/dist/composer.js +15 -0
  274. package/dist/composer.js.map +1 -0
  275. package/dist/confirmation.js +53 -0
  276. package/dist/confirmation.js.map +1 -0
  277. package/dist/connection.js +8 -0
  278. package/dist/connection.js.map +1 -0
  279. package/dist/context-panel.js +25 -0
  280. package/dist/context-panel.js.map +1 -0
  281. package/dist/controls.js +10 -0
  282. package/dist/controls.js.map +1 -0
  283. package/dist/conversation.js +19 -0
  284. package/dist/conversation.js.map +1 -0
  285. package/dist/diff-view.js +15 -0
  286. package/dist/diff-view.js.map +1 -0
  287. package/dist/edge.js +10 -0
  288. package/dist/edge.js.map +1 -0
  289. package/dist/environment-variables.js +29 -0
  290. package/dist/environment-variables.js.map +1 -0
  291. package/dist/file-tree.js +23 -0
  292. package/dist/file-tree.js.map +1 -0
  293. package/dist/gallery.js +9 -0
  294. package/dist/gallery.js.map +1 -0
  295. package/dist/grouped-parts.js +21 -0
  296. package/dist/grouped-parts.js.map +1 -0
  297. package/dist/image.js +9 -0
  298. package/dist/image.js.map +1 -0
  299. package/dist/index.d.ts +403 -108
  300. package/dist/index.js +671 -13205
  301. package/dist/index.js.map +1 -1
  302. package/dist/inline-citation.js +39 -0
  303. package/dist/inline-citation.js.map +1 -0
  304. package/dist/jsx-preview.js +17 -0
  305. package/dist/jsx-preview.js.map +1 -0
  306. package/dist/markdown-view.js +17 -0
  307. package/dist/markdown-view.js.map +1 -0
  308. package/dist/message-compare.js +12 -0
  309. package/dist/message-compare.js.map +1 -0
  310. package/dist/message-edit.js +19 -0
  311. package/dist/message-edit.js.map +1 -0
  312. package/dist/message-feedback.js +11 -0
  313. package/dist/message-feedback.js.map +1 -0
  314. package/dist/message-form-spec.js +38 -0
  315. package/dist/message-form-spec.js.map +1 -0
  316. package/dist/message-form.js +26 -0
  317. package/dist/message-form.js.map +1 -0
  318. package/dist/message-table-spec.js +26 -0
  319. package/dist/message-table-spec.js.map +1 -0
  320. package/dist/message-table.js +12 -0
  321. package/dist/message-table.js.map +1 -0
  322. package/dist/message.js +51 -0
  323. package/dist/message.js.map +1 -0
  324. package/dist/mic-selector.js +27 -0
  325. package/dist/mic-selector.js.map +1 -0
  326. package/dist/model-provider-logo.js +13 -0
  327. package/dist/model-provider-logo.js.map +1 -0
  328. package/dist/motion-config.js +9 -0
  329. package/dist/motion-config.js.map +1 -0
  330. package/dist/node.js +22 -0
  331. package/dist/node.js.map +1 -0
  332. package/dist/open-in-chat.js +31 -0
  333. package/dist/open-in-chat.js.map +1 -0
  334. package/dist/package-info.js +25 -0
  335. package/dist/package-info.js.map +1 -0
  336. package/dist/panel.js +10 -0
  337. package/dist/panel.js.map +1 -0
  338. package/dist/part-groups.js +18 -0
  339. package/dist/part-groups.js.map +1 -0
  340. package/dist/permission-mode-select.js +9 -0
  341. package/dist/permission-mode-select.js.map +1 -0
  342. package/dist/persona-sources.js +8 -0
  343. package/dist/persona-sources.js.map +1 -0
  344. package/dist/persona.js +14 -0
  345. package/dist/persona.js.map +1 -0
  346. package/dist/plan.js +32 -0
  347. package/dist/plan.js.map +1 -0
  348. package/dist/prompt-input-effort.js +9 -0
  349. package/dist/prompt-input-effort.js.map +1 -0
  350. package/dist/prompt-input-mode.js +10 -0
  351. package/dist/prompt-input-mode.js.map +1 -0
  352. package/dist/prompt-input-slash.js +12 -0
  353. package/dist/prompt-input-slash.js.map +1 -0
  354. package/dist/prompt-input.js +89 -0
  355. package/dist/prompt-input.js.map +1 -0
  356. package/dist/queue.js +37 -0
  357. package/dist/queue.js.map +1 -0
  358. package/dist/reasoning.js +23 -0
  359. package/dist/reasoning.js.map +1 -0
  360. package/dist/sandbox.js +28 -0
  361. package/dist/sandbox.js.map +1 -0
  362. package/dist/schema-display.js +33 -0
  363. package/dist/schema-display.js.map +1 -0
  364. package/dist/selection-toolbar.js +11 -0
  365. package/dist/selection-toolbar.js.map +1 -0
  366. package/dist/session-header.js +9 -0
  367. package/dist/session-header.js.map +1 -0
  368. package/dist/session-status-bar.js +9 -0
  369. package/dist/session-status-bar.js.map +1 -0
  370. package/dist/shimmer.js +9 -0
  371. package/dist/shimmer.js.map +1 -0
  372. package/dist/snippet.js +17 -0
  373. package/dist/snippet.js.map +1 -0
  374. package/dist/sources.js +17 -0
  375. package/dist/sources.js.map +1 -0
  376. package/dist/speech-input.js +9 -0
  377. package/dist/speech-input.js.map +1 -0
  378. package/dist/stack-trace.js +27 -0
  379. package/dist/stack-trace.js.map +1 -0
  380. package/dist/suggestion.js +16 -0
  381. package/dist/suggestion.js.map +1 -0
  382. package/dist/task.js +18 -0
  383. package/dist/task.js.map +1 -0
  384. package/dist/test-results.js +43 -0
  385. package/dist/test-results.js.map +1 -0
  386. package/dist/token-usage.js +27 -0
  387. package/dist/token-usage.js.map +1 -0
  388. package/dist/tool-result-card.js +9 -0
  389. package/dist/tool-result-card.js.map +1 -0
  390. package/dist/tool.js +27 -0
  391. package/dist/tool.js.map +1 -0
  392. package/dist/toolbar.js +10 -0
  393. package/dist/toolbar.js.map +1 -0
  394. package/dist/transcription.js +11 -0
  395. package/dist/transcription.js.map +1 -0
  396. package/dist/turn-status.js +9 -0
  397. package/dist/turn-status.js.map +1 -0
  398. package/dist/use-audio-level.js +9 -0
  399. package/dist/use-audio-level.js.map +1 -0
  400. package/dist/voice-selector.js +47 -0
  401. package/dist/voice-selector.js.map +1 -0
  402. package/dist/web-preview.js +19 -0
  403. package/dist/web-preview.js.map +1 -0
  404. package/package.json +12 -10
  405. package/schemas/a2ui-surface.v1.schema.json +5425 -0
  406. package/src/__contract__/audio-visualizer.contract.test.tsx +49 -0
  407. package/src/__contract__/chat-shell.contract.test.tsx +49 -0
  408. package/src/__contract__/grouped-parts.contract.test.tsx +49 -0
  409. package/src/__contract__/image.contract.test.tsx +49 -0
  410. package/src/__contract__/markdown-view.contract.test.tsx +49 -0
  411. package/src/__contract__/message-feedback.contract.test.tsx +49 -0
  412. package/src/__contract__/message-form.contract.test.tsx +49 -0
  413. package/src/__contract__/message-table.contract.test.tsx +49 -0
  414. package/src/__contract__/model-provider-logo.contract.test.tsx +49 -0
  415. package/src/__contract__/persona.contract.test.tsx +49 -0
  416. package/src/__contract__/prompt-input-effort.contract.test.tsx +49 -0
  417. package/src/__contract__/prompt-input-mode.contract.test.tsx +49 -0
  418. package/src/_chat-shell-rail.tsx +4 -2
  419. package/src/_flow-boundary.tsx +2 -2
  420. package/src/_lazy-cjk.test.ts +43 -0
  421. package/src/_lazy-cjk.ts +73 -0
  422. package/src/_lazy-math.test.ts +63 -0
  423. package/src/_lazy-math.ts +90 -0
  424. package/src/_persona-rive.tsx +27 -41
  425. package/src/_streamdown-i18n.ts +73 -21
  426. package/src/_streamdown-safety.ts +2 -2
  427. package/src/_theme-scope-store.test.ts +83 -0
  428. package/src/_theme-scope-store.ts +103 -0
  429. package/src/a2ui/a2ui-surface.stories.tsx +662 -0
  430. package/src/a2ui/a2ui-surface.test.tsx +201 -0
  431. package/src/a2ui/a2ui-surface.tsx +354 -0
  432. package/src/a2ui/catalog.source.json +772 -0
  433. package/src/a2ui/core/a2ui-core.test.ts +178 -0
  434. package/src/a2ui/core/catalog.generated.ts +1006 -0
  435. package/src/a2ui/core/complete-json.ts +81 -0
  436. package/src/a2ui/core/index.ts +10 -0
  437. package/src/a2ui/core/schema.ts +111 -0
  438. package/src/a2ui/core/spec.ts +148 -0
  439. package/src/a2ui/core/validate.ts +266 -0
  440. package/src/a2ui/index.ts +7 -0
  441. package/src/a2ui/ui-catalog.tsx +225 -0
  442. package/src/a2ui/wave1-chart-spec.test.ts +87 -0
  443. package/src/a2ui/wave2-chart-spec.test.ts +108 -0
  444. package/src/agent-event.tsx +1 -1
  445. package/src/agent.tsx +18 -13
  446. package/src/agentic-workspace.stories.tsx +6 -45
  447. package/src/artifact.tsx +2 -2
  448. package/src/asset-preview.test.tsx +40 -0
  449. package/src/asset-preview.tsx +83 -12
  450. package/src/attachments.tsx +7 -4
  451. package/src/chat-shell.test.tsx +40 -10
  452. package/src/chat-shell.tsx +90 -44
  453. package/src/chat.stories.tsx +47 -42
  454. package/src/code-block.test.tsx +100 -1
  455. package/src/code-block.tsx +166 -103
  456. package/src/commit.tsx +30 -41
  457. package/src/composer.stories.tsx +4 -5
  458. package/src/composer.test.tsx +45 -0
  459. package/src/composer.tsx +104 -21
  460. package/src/confirmation.tsx +1 -1
  461. package/src/context-panel.stories.tsx +1 -1
  462. package/src/context-panel.tsx +2 -2
  463. package/src/conversation.stories.tsx +24 -0
  464. package/src/conversation.test.tsx +69 -0
  465. package/src/conversation.tsx +47 -8
  466. package/src/diff-view.stories.tsx +79 -0
  467. package/src/diff-view.test.tsx +52 -2
  468. package/src/diff-view.tsx +92 -36
  469. package/src/environment-variables.tsx +20 -37
  470. package/src/file-tree.test.tsx +21 -0
  471. package/src/file-tree.tsx +33 -16
  472. package/src/gallery.stories.tsx +42 -0
  473. package/src/gallery.tsx +2 -2
  474. package/src/grouped-parts.stories.tsx +23 -0
  475. package/src/grouped-parts.tsx +1 -1
  476. package/src/index.ts +1 -0
  477. package/src/inline-citation.tsx +5 -5
  478. package/src/jsx-preview.tsx +151 -43
  479. package/src/markdown-view.test.tsx +7 -3
  480. package/src/markdown-view.tsx +8 -1
  481. package/src/message-compare.stories.tsx +40 -0
  482. package/src/message-compare.tsx +2 -1
  483. package/src/message-form.stories.tsx +36 -3
  484. package/src/message-form.test.tsx +8 -2
  485. package/src/message-form.tsx +16 -8
  486. package/src/message-table.stories.tsx +26 -2
  487. package/src/message-table.test.tsx +7 -0
  488. package/src/message-table.tsx +9 -5
  489. package/src/message.test.tsx +73 -3
  490. package/src/message.tsx +36 -12
  491. package/src/model-provider-logo.test.tsx +57 -3
  492. package/src/model-provider-logo.tsx +45 -11
  493. package/src/open-in-chat.tsx +50 -29
  494. package/src/package-info.tsx +23 -20
  495. package/src/prompt-input-slash.stories.tsx +1 -1
  496. package/src/prompt-input.test.tsx +67 -1
  497. package/src/prompt-input.tsx +42 -4
  498. package/src/queue.tsx +4 -4
  499. package/src/reasoning.stories.tsx +27 -0
  500. package/src/reasoning.tsx +17 -6
  501. package/src/sandbox.tsx +3 -3
  502. package/src/schema-display.test.tsx +56 -0
  503. package/src/schema-display.tsx +68 -37
  504. package/src/session-header.stories.tsx +35 -1
  505. package/src/session-header.tsx +1 -1
  506. package/src/snippet.test.tsx +6 -2
  507. package/src/snippet.tsx +14 -34
  508. package/src/sources.stories.tsx +30 -0
  509. package/src/sources.tsx +4 -1
  510. package/src/speech-input.test.tsx +109 -0
  511. package/src/speech-input.tsx +31 -3
  512. package/src/stack-trace.tsx +20 -36
  513. package/src/streamdown-i18n.test.tsx +23 -0
  514. package/src/templates-ai-assistant.stories.tsx +151 -87
  515. package/src/test-results.tsx +47 -27
  516. package/src/token-usage.tsx +6 -6
  517. package/src/tool.stories.tsx +39 -0
  518. package/src/tool.test.tsx +65 -0
  519. package/src/tool.tsx +61 -25
  520. package/src/toolbar.tsx +0 -10
  521. package/src/transcription.tsx +1 -1
  522. package/src/voice-selector.tsx +5 -5
  523. package/src/web-preview.test.tsx +51 -1
  524. package/src/web-preview.tsx +39 -8
  525. package/dist/_flow-boundary-SHNWLQG5.js.map +0 -1
  526. package/dist/_persona-rive-JEG44YHX.js.map +0 -1
  527. /package/dist/{_audio-player-media-chrome-T3XVXWRZ.js.map → _audio-player-media-chrome.js.map} +0 -0
@@ -3,20 +3,11 @@
3
3
  import { useControllableState } from "@radix-ui/react-use-controllable-state";
4
4
  import { Button } from "@elabs-ai/components-ui";
5
5
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@elabs-ai/components-ui";
6
- import { useLocale } from "@elabs-ai/components-ui";
6
+ import { useCopyToClipboard, useLocale } from "@elabs-ai/components-ui";
7
7
  import { cn } from "@elabs-ai/components-ui/lib/cn";
8
8
  import { AlertTriangleIcon, CheckIcon, ChevronDownIcon, CopyIcon } from "lucide-react";
9
9
  import type { ComponentProps } from "react";
10
- import {
11
- createContext,
12
- memo,
13
- useCallback,
14
- useContext,
15
- useEffect,
16
- useMemo,
17
- useRef,
18
- useState,
19
- } from "react";
10
+ import { createContext, memo, useCallback, useContext, useMemo } from "react";
20
11
 
21
12
  // Regex patterns for parsing stack traces
22
13
  const STACK_FRAME_WITH_PARENS_REGEX = /^at\s+(.+?)\s+\((.+):(\d+):(\d+)\)$/;
@@ -188,7 +179,7 @@ export const StackTrace = memo(
188
179
  <StackTraceContext.Provider value={contextValue}>
189
180
  <div
190
181
  className={cn(
191
- "not-prose w-full overflow-hidden rounded-lg border bg-background font-mono text-sm",
182
+ "not-prose w-full overflow-hidden rounded-lg border bg-background font-mono text-body",
192
183
  className,
193
184
  )}
194
185
  {...props}
@@ -293,42 +284,35 @@ export const StackTraceCopyButton = memo(
293
284
  ({
294
285
  onCopy,
295
286
  onError,
296
- timeout = 2000,
287
+ timeout,
297
288
  className,
298
289
  children,
290
+ "aria-label": ariaLabel,
299
291
  ...props
300
292
  }: StackTraceCopyButtonProps) => {
301
- const [isCopied, setIsCopied] = useState(false);
302
- const timeoutRef = useRef<number>(0);
293
+ const { t } = useLocale();
303
294
  const { raw } = useStackTrace();
295
+ // Shared implementation (`@elabs-ai/components-ui`) instead of a private
296
+ // copy of the same copy-to-clipboard state machine (issue-workflow.md
297
+ // dedupe finding) — see `CodeBlockCopyButton` for the reference usage.
298
+ const { copied: isCopied, copy } = useCopyToClipboard(
299
+ timeout === undefined ? undefined : { resetAfterMs: timeout },
300
+ );
304
301
 
305
302
  const copyToClipboard = useCallback(async () => {
306
- if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {
307
- onError?.(new Error("Clipboard API not available"));
308
- return;
309
- }
310
-
311
- try {
312
- await navigator.clipboard.writeText(raw);
313
- setIsCopied(true);
303
+ const ok = await copy(raw);
304
+ if (ok) {
314
305
  onCopy?.();
315
- timeoutRef.current = window.setTimeout(() => setIsCopied(false), timeout);
316
- } catch (error) {
317
- onError?.(error as Error);
306
+ } else {
307
+ onError?.(new Error("Clipboard API not available"));
318
308
  }
319
- }, [raw, onCopy, onError, timeout]);
320
-
321
- useEffect(
322
- () => () => {
323
- window.clearTimeout(timeoutRef.current);
324
- },
325
- [],
326
- );
309
+ }, [copy, raw, onCopy, onError]);
327
310
 
328
311
  const Icon = isCopied ? CheckIcon : CopyIcon;
329
312
 
330
313
  return (
331
314
  <Button
315
+ aria-label={ariaLabel ?? t("copy")}
332
316
  className={cn("size-7", className)}
333
317
  onClick={copyToClipboard}
334
318
  size="icon"
@@ -440,7 +424,7 @@ export const StackTraceFrames = memo(
440
424
  {framesToShow.map((frame) => (
441
425
  <div
442
426
  className={cn(
443
- "text-xs",
427
+ "text-meta",
444
428
  frame.isInternal ? "text-muted-foreground/50" : "text-foreground/90",
445
429
  )}
446
430
  key={frame.raw}
@@ -464,7 +448,7 @@ export const StackTraceFrames = memo(
464
448
  </div>
465
449
  ))}
466
450
  {framesToShow.length === 0 && (
467
- <div className="text-muted-foreground text-xs">{t("ai.stackTrace.empty")}</div>
451
+ <div className="text-muted-foreground text-meta">{t("ai.stackTrace.empty")}</div>
468
452
  )}
469
453
  </div>
470
454
  );
@@ -13,6 +13,7 @@ import { LocaleProvider } from "@elabs-ai/components-ui";
13
13
  import { MessageResponse } from "./message";
14
14
  import { MarkdownView } from "./markdown-view";
15
15
  import { Reasoning, ReasoningContent } from "./reasoning";
16
+ import { _debugActiveThemeScopeCount } from "./_theme-scope-store";
16
17
 
17
18
  const CODE_MARKDOWN = "```js\nconst a = 1;\n```";
18
19
  // `MarkdownView` re-maps `code` onto `ProseInlineCode`, so its Streamdown chrome
@@ -107,6 +108,28 @@ describe("Streamdown chrome microcopy (#310)", () => {
107
108
  });
108
109
  });
109
110
 
111
+ describe("useReactiveCodePlugin shares ONE theme-scope observer (perf review §3.3)", () => {
112
+ it("registers a single tracked scope for many simultaneously-mounted MessageResponse instances", () => {
113
+ const before = _debugActiveThemeScopeCount();
114
+
115
+ const { unmount } = render(
116
+ <>
117
+ <MessageResponse>{CODE_MARKDOWN}</MessageResponse>
118
+ <MessageResponse>{CODE_MARKDOWN}</MessageResponse>
119
+ <MessageResponse>{CODE_MARKDOWN}</MessageResponse>
120
+ </>,
121
+ );
122
+
123
+ // Under the old per-hook `MutationObserver`, a message-dense conversation
124
+ // registered one observer PER instance; the shared store collapses every
125
+ // instance watching the same `<html>` scope into exactly one.
126
+ expect(_debugActiveThemeScopeCount()).toBe(before + 1);
127
+
128
+ unmount();
129
+ expect(_debugActiveThemeScopeCount()).toBe(before);
130
+ });
131
+ });
132
+
110
133
  /**
111
134
  * #315 follow-up — the "major" carve-out: only `<CodeBlock>` had been
112
135
  * de-GitHub-ed; every fenced code block rendered through `MessageResponse`/
@@ -1,6 +1,7 @@
1
1
  /**
2
- * AI assistant template — the canonical full-screen AI assistant composition
3
- * (app-shell + chat shell: Conversation + PromptInput). This story is the
2
+ * AI assistant template — the canonical full-screen AI assistant composition:
3
+ * app-shell nav, an immersive `ChatShell` (transcript scrolls behind a floating
4
+ * `Composer`, one centred reading column) and the `ContextPanel` right rail. This story is the
4
5
  * single source of truth: `pnpm gen:templates` derives the consumer template
5
6
  * source (`docs/playbooks/templates/ai-assistant.tsx`) from it.
6
7
  * Verify across both themes with globals=theme:<slug>.
@@ -10,8 +11,10 @@ import { useState } from "react";
10
11
  import { AppIcon } from "@elabs-ai/components-icons";
11
12
  import {
12
13
  Button,
14
+ NavUser,
13
15
  Sidebar,
14
16
  SidebarContent,
17
+ SidebarFooter,
15
18
  SidebarGroup,
16
19
  SidebarGroupContent,
17
20
  SidebarHeader,
@@ -23,7 +26,16 @@ import {
23
26
  SidebarTrigger,
24
27
  } from "@elabs-ai/components-ui";
25
28
  import {
29
+ AssetPreview,
30
+ ChatShell,
26
31
  Composer,
32
+ ContextPanel,
33
+ ContextPanelBody,
34
+ ContextPanelDetail,
35
+ ContextPanelHeader,
36
+ ContextPanelProvider,
37
+ ContextPanelSection,
38
+ ContextPanelTrigger,
27
39
  Conversation,
28
40
  ConversationContent,
29
41
  ConversationEmptyState,
@@ -31,6 +43,9 @@ import {
31
43
  Message,
32
44
  MessageContent,
33
45
  MessageResponse,
46
+ ProducedAssetTree,
47
+ useContextPanel,
48
+ type ContextAsset,
34
49
  } from "./index";
35
50
  import { Bot, History, Home, MessageSquare, Settings } from "lucide-react";
36
51
 
@@ -47,10 +62,36 @@ const nav = [
47
62
  { id: "settings", label: "Settings", icon: Settings },
48
63
  ];
49
64
 
65
+ /** Right rail root — what the assistant produced; selecting one drills in. */
66
+ function ContextRailRoot({ assets }: { assets: ContextAsset[] }) {
67
+ const { state, actions } = useContextPanel();
68
+ return (
69
+ <ContextPanelSection label="Produced assets">
70
+ <ProducedAssetTree
71
+ assets={assets}
72
+ selectedId={state.selectedAsset?.id}
73
+ onSelect={actions.openDetail}
74
+ />
75
+ </ContextPanelSection>
76
+ );
77
+ }
78
+
79
+ /** Right rail detail — the focused asset, with Back in the panel header. */
80
+ function ContextRailDetail() {
81
+ const { state } = useContextPanel();
82
+ return (
83
+ <ContextPanelDetail>
84
+ {state.selectedAsset ? <AssetPreview asset={state.selectedAsset} /> : null}
85
+ </ContextPanelDetail>
86
+ );
87
+ }
88
+
50
89
  function AiAssistantTemplate() {
51
90
  const [active, setActive] = useState("chat");
52
91
  const [messages, setMessages] = useState<ChatMessage[]>([]);
53
92
  const [status, setStatus] = useState<"ready" | "submitted">("ready");
93
+ // Files the assistant produced — wire to your runtime's tool outputs.
94
+ const [assets] = useState<ContextAsset[]>([]);
54
95
 
55
96
  function send(text: string) {
56
97
  setMessages((m) => [...m, { id: crypto.randomUUID(), role: "user", text }]);
@@ -61,98 +102,121 @@ function AiAssistantTemplate() {
61
102
  }
62
103
 
63
104
  return (
64
- <SidebarProvider>
65
- <Sidebar collapsible="icon">
66
- <SidebarHeader className="px-3 py-2">
67
- <div className="flex items-center gap-2">
68
- <AppIcon height={20} aria-hidden />
69
- <span className="truncate font-semibold group-data-[collapsible=icon]:hidden">
70
- Assistant
71
- </span>
72
- </div>
73
- </SidebarHeader>
74
- <SidebarContent>
75
- <SidebarGroup>
76
- <SidebarGroupContent>
77
- <SidebarMenu>
78
- {nav.map((n) => (
79
- <SidebarMenuItem key={n.id}>
80
- <SidebarMenuButton
81
- isActive={active === n.id}
82
- tooltip={n.label}
83
- onClick={() => setActive(n.id)}
84
- >
85
- <n.icon aria-hidden="true" />
86
- <span>{n.label}</span>
87
- </SidebarMenuButton>
88
- </SidebarMenuItem>
89
- ))}
90
- </SidebarMenu>
91
- </SidebarGroupContent>
92
- </SidebarGroup>
93
- </SidebarContent>
94
- </Sidebar>
95
- <SidebarInset className="flex flex-col overflow-hidden">
96
- <header className="flex h-14 shrink-0 items-center gap-2 border-b px-4">
97
- <SidebarTrigger />
98
- <h1 className="text-body font-medium">AI Assistant</h1>
99
- </header>
100
- <div className="flex flex-1 flex-col overflow-hidden">
101
- <Conversation className="flex-1">
102
- <ConversationContent>
103
- {messages.length === 0 ? (
104
- <ConversationEmptyState
105
- icon={<MessageSquare className="size-8" aria-hidden="true" />}
106
- title="Start the conversation"
107
- description="Ask anything to begin."
108
- actions={
109
- <>
110
- <Button
111
- onClick={() => send("What can you help me with?")}
112
- size="sm"
113
- variant="outline"
105
+ // The provider wraps the whole shell so the header trigger and the right
106
+ // rail share one open/closed state.
107
+ <ContextPanelProvider>
108
+ <SidebarProvider className="h-svh min-h-0">
109
+ <Sidebar collapsible="icon">
110
+ <SidebarHeader className="px-3 py-2">
111
+ <div className="flex items-center gap-2">
112
+ <AppIcon height={20} aria-hidden />
113
+ <span className="truncate font-semibold group-data-[collapsible=icon]:hidden">
114
+ Assistant
115
+ </span>
116
+ </div>
117
+ </SidebarHeader>
118
+ <SidebarContent>
119
+ <SidebarGroup>
120
+ <SidebarGroupContent>
121
+ <SidebarMenu>
122
+ {nav.map((n) => (
123
+ <SidebarMenuItem key={n.id}>
124
+ <SidebarMenuButton
125
+ isActive={active === n.id}
126
+ tooltip={n.label}
127
+ onClick={() => setActive(n.id)}
114
128
  >
115
- What can you help me with?
116
- </Button>
117
- <Button
118
- onClick={() => send("Summarize my recent activity")}
119
- size="sm"
120
- variant="outline"
121
- >
122
- Summarize my recent activity
123
- </Button>
124
- </>
125
- }
129
+ <n.icon aria-hidden="true" />
130
+ <span>{n.label}</span>
131
+ </SidebarMenuButton>
132
+ </SidebarMenuItem>
133
+ ))}
134
+ </SidebarMenu>
135
+ </SidebarGroupContent>
136
+ </SidebarGroup>
137
+ </SidebarContent>
138
+ <SidebarFooter>
139
+ <NavUser user={{ name: "Avery Rao", email: "avery@example.com" }} />
140
+ </SidebarFooter>
141
+ </Sidebar>
142
+ <SidebarInset className="flex min-w-0 flex-col overflow-hidden">
143
+ <header className="flex h-header shrink-0 items-center gap-2 border-b px-4">
144
+ <SidebarTrigger />
145
+ <h1 className="text-body font-medium">AI Assistant</h1>
146
+ <ContextPanelTrigger className="ms-auto" />
147
+ </header>
148
+ {/* `bare`: the transcript scrolls behind the floating composer and
149
+ both share one centred reading column. */}
150
+ <div className="min-h-0 flex-1">
151
+ <ChatShell
152
+ variant="bare"
153
+ composer={
154
+ <Composer
155
+ placeholder="Send a message…"
156
+ status={status === "submitted" ? "Generating…" : "Awaiting your input"}
157
+ sendStatus={status}
158
+ onSubmit={(message) => {
159
+ const text = message.text?.trim();
160
+ if (text) send(text);
161
+ }}
126
162
  />
127
- ) : (
128
- messages.map((m) => (
129
- <Message from={m.role} key={m.id}>
130
- <MessageContent>
131
- <MessageResponse>{m.text}</MessageResponse>
132
- </MessageContent>
133
- </Message>
134
- ))
135
- )}
136
- </ConversationContent>
137
- <ConversationScrollButton />
138
- </Conversation>
139
- <Composer
140
- placeholder="Send a message…"
141
- status={status === "submitted" ? "Generating…" : "Awaiting your input"}
142
- sendStatus={status}
143
- onSubmit={(message) => {
144
- const text = message.text?.trim();
145
- if (text) send(text);
146
- }}
163
+ }
164
+ >
165
+ <Conversation className="flex-1">
166
+ <ConversationContent>
167
+ {messages.length === 0 ? (
168
+ <ConversationEmptyState
169
+ icon={<MessageSquare className="size-8" aria-hidden="true" />}
170
+ title="Start the conversation"
171
+ description="Ask anything to begin."
172
+ actions={
173
+ <>
174
+ <Button
175
+ onClick={() => send("What can you help me with?")}
176
+ size="sm"
177
+ variant="outline"
178
+ >
179
+ What can you help me with?
180
+ </Button>
181
+ <Button
182
+ onClick={() => send("Summarize my recent activity")}
183
+ size="sm"
184
+ variant="outline"
185
+ >
186
+ Summarize my recent activity
187
+ </Button>
188
+ </>
189
+ }
190
+ />
191
+ ) : (
192
+ messages.map((m) => (
193
+ <Message from={m.role} key={m.id}>
194
+ <MessageContent>
195
+ <MessageResponse>{m.text}</MessageResponse>
196
+ </MessageContent>
197
+ </Message>
198
+ ))
199
+ )}
200
+ </ConversationContent>
201
+ <ConversationScrollButton />
202
+ </Conversation>
203
+ </ChatShell>
204
+ </div>
205
+ </SidebarInset>
206
+ <ContextPanel>
207
+ <ContextPanelHeader title="Context" />
208
+ <ContextPanelBody
209
+ root={<ContextRailRoot assets={assets} />}
210
+ detail={<ContextRailDetail />}
147
211
  />
148
- </div>
149
- </SidebarInset>
150
- </SidebarProvider>
212
+ </ContextPanel>
213
+ </SidebarProvider>
214
+ </ContextPanelProvider>
151
215
  );
152
216
  }
153
217
 
154
218
  const meta = {
155
- title: "Patterns/Templates/AI Assistant",
219
+ title: "Patterns/Templates/Starters/AI Assistant",
156
220
  parameters: { layout: "fullscreen" },
157
221
  tags: ["autodocs"],
158
222
  } satisfies Meta;
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { StatusBadge, StatusIcon, type Status } from "@elabs-ai/components-ui";
3
+ import { StatusBadge, StatusIcon, useLocale, type Status } from "@elabs-ai/components-ui";
4
4
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@elabs-ai/components-ui";
5
5
  import { cn } from "@elabs-ai/components-ui/lib/cn";
6
6
  import { ChevronRightIcon } from "lucide-react";
@@ -64,7 +64,7 @@ export const TestResultsDuration = ({
64
64
 
65
65
  return (
66
66
  <span
67
- className={cn("shrink-0 text-muted-foreground text-sm tabular-nums", className)}
67
+ className={cn("shrink-0 text-muted-foreground text-body tabular-nums", className)}
68
68
  {...props}
69
69
  >
70
70
  {children ?? formatDuration(summary.duration)}
@@ -76,6 +76,7 @@ export type TestResultsSummaryProps = HTMLAttributes<HTMLDivElement>;
76
76
 
77
77
  export const TestResultsSummary = ({ className, children, ...props }: TestResultsSummaryProps) => {
78
78
  const { summary } = useContext(TestResultsContext);
79
+ const { t } = useLocale();
79
80
 
80
81
  if (!summary) {
81
82
  return null;
@@ -86,16 +87,16 @@ export const TestResultsSummary = ({ className, children, ...props }: TestResult
86
87
  {children ?? (
87
88
  <>
88
89
  <StatusBadge size="sm" status="complete">
89
- {summary.passed} passed
90
+ {t("ai.testResults.passedCount", { count: summary.passed })}
90
91
  </StatusBadge>
91
92
  {summary.failed > 0 && (
92
93
  <StatusBadge size="sm" status="failed">
93
- {summary.failed} failed
94
+ {t("ai.testResults.failedCount", { count: summary.failed })}
94
95
  </StatusBadge>
95
96
  )}
96
97
  {summary.skipped > 0 && (
97
98
  <StatusBadge size="sm" status="skipped">
98
- {summary.skipped} skipped
99
+ {t("ai.testResults.skippedCount", { count: summary.skipped })}
99
100
  </StatusBadge>
100
101
  )}
101
102
  </>
@@ -134,6 +135,7 @@ export const TestResultsProgress = ({
134
135
  ...props
135
136
  }: TestResultsProgressProps) => {
136
137
  const { summary } = useContext(TestResultsContext);
138
+ const { t, formatNumber } = useLocale();
137
139
 
138
140
  if (!summary) {
139
141
  return null;
@@ -156,11 +158,14 @@ export const TestResultsProgress = ({
156
158
  style={{ width: `${failedPercent}%` }}
157
159
  />
158
160
  </div>
159
- <div className="flex justify-between text-muted-foreground text-xs tabular-nums">
161
+ <div className="flex justify-between text-muted-foreground text-meta tabular-nums">
160
162
  <span>
161
- {summary.passed}/{summary.total} tests passed
163
+ {t("ai.testResults.testsPassed", { passed: summary.passed, total: summary.total })}
164
+ </span>
165
+ <span>
166
+ {formatNumber(passedPercent, { maximumFractionDigits: 0 })}
167
+ {"%"}
162
168
  </span>
163
- <span>{passedPercent.toFixed(0)}%</span>
164
169
  </div>
165
170
  </>
166
171
  )}
@@ -247,7 +252,7 @@ export const TestSuiteName = ({ className, children, ...props }: TestSuiteNamePr
247
252
  >
248
253
  <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform duration-fast ease-standard motion-reduce:transition-none group-data-[state=open]:rotate-90" />
249
254
  <TestStatusIcon status={status} />
250
- <span className="min-w-0 flex-1 truncate font-medium text-sm">{children ?? name}</span>
255
+ <span className="min-w-0 flex-1 truncate font-medium text-body">{children ?? name}</span>
251
256
  </CollapsibleTrigger>
252
257
  );
253
258
  };
@@ -265,20 +270,35 @@ export const TestSuiteStats = ({
265
270
  className,
266
271
  children,
267
272
  ...props
268
- }: TestSuiteStatsProps) => (
269
- <div
270
- className={cn("ms-auto flex shrink-0 items-center gap-3 text-xs tabular-nums", className)}
271
- {...props}
272
- >
273
- {children ?? (
274
- <>
275
- {passed > 0 && <span className="text-success-text">{passed} passed</span>}
276
- {failed > 0 && <span className="text-destructive-text">{failed} failed</span>}
277
- {skipped > 0 && <span className="text-muted-foreground">{skipped} skipped</span>}
278
- </>
279
- )}
280
- </div>
281
- );
273
+ }: TestSuiteStatsProps) => {
274
+ const { t } = useLocale();
275
+ return (
276
+ <div
277
+ className={cn("ms-auto flex shrink-0 items-center gap-3 text-meta tabular-nums", className)}
278
+ {...props}
279
+ >
280
+ {children ?? (
281
+ <>
282
+ {passed > 0 && (
283
+ <span className="text-success-text">
284
+ {t("ai.testResults.passedCount", { count: passed })}
285
+ </span>
286
+ )}
287
+ {failed > 0 && (
288
+ <span className="text-destructive-text">
289
+ {t("ai.testResults.failedCount", { count: failed })}
290
+ </span>
291
+ )}
292
+ {skipped > 0 && (
293
+ <span className="text-muted-foreground">
294
+ {t("ai.testResults.skippedCount", { count: skipped })}
295
+ </span>
296
+ )}
297
+ </>
298
+ )}
299
+ </div>
300
+ );
301
+ };
282
302
 
283
303
  export type TestSuiteContentProps = ComponentProps<typeof CollapsibleContent>;
284
304
 
@@ -328,7 +348,7 @@ export const TestDuration = ({ className, children, ...props }: TestDurationProp
328
348
 
329
349
  return (
330
350
  <span
331
- className={cn("shrink-0 text-muted-foreground text-xs tabular-nums", className)}
351
+ className={cn("shrink-0 text-muted-foreground text-meta tabular-nums", className)}
332
352
  {...props}
333
353
  >
334
354
  {children ?? `${duration}ms`}
@@ -365,7 +385,7 @@ export const Test = ({ name, status, duration, className, children, ...props }:
365
385
  return (
366
386
  <TestContext.Provider value={contextValue}>
367
387
  <div
368
- className={cn("flex min-w-0 items-center gap-2 ps-10 pe-4 py-2 text-sm", className)}
388
+ className={cn("flex min-w-0 items-center gap-2 ps-10 pe-4 py-2 text-body", className)}
369
389
  {...props}
370
390
  >
371
391
  {children ?? (
@@ -391,7 +411,7 @@ export const TestError = ({ className, children, ...props }: TestErrorProps) =>
391
411
  export type TestErrorMessageProps = HTMLAttributes<HTMLParagraphElement>;
392
412
 
393
413
  export const TestErrorMessage = ({ className, children, ...props }: TestErrorMessageProps) => (
394
- <p className={cn("font-medium text-destructive-text text-sm", className)} {...props}>
414
+ <p className={cn("font-medium text-destructive-text text-body", className)} {...props}>
395
415
  {children}
396
416
  </p>
397
417
  );
@@ -400,7 +420,7 @@ export type TestErrorStackProps = HTMLAttributes<HTMLPreElement>;
400
420
 
401
421
  export const TestErrorStack = ({ className, children, ...props }: TestErrorStackProps) => (
402
422
  <pre
403
- className={cn("mt-2 overflow-auto font-mono text-destructive-text text-xs", className)}
423
+ className={cn("mt-2 overflow-auto font-mono text-destructive-text text-meta", className)}
404
424
  {...props}
405
425
  >
406
426
  {children}
@@ -154,7 +154,7 @@ export const TokenUsageContentHeader = ({
154
154
  <div className={cn("w-full space-y-2 p-3", className)} {...props}>
155
155
  {children ?? (
156
156
  <>
157
- <div className="flex items-center justify-between gap-3 text-xs">
157
+ <div className="flex items-center justify-between gap-3 text-meta">
158
158
  <p>{displayPct}</p>
159
159
  <p className="font-mono text-muted-foreground">
160
160
  {used} / {total}
@@ -207,7 +207,7 @@ export const TokenUsageContentFooter = ({
207
207
  return (
208
208
  <div
209
209
  className={cn(
210
- "flex w-full items-center justify-between gap-3 bg-secondary p-3 text-xs",
210
+ "flex w-full items-center justify-between gap-3 bg-secondary p-3 text-meta",
211
211
  className,
212
212
  )}
213
213
  {...props}
@@ -259,7 +259,7 @@ export const TokenUsageInput = ({ className, children, ...props }: TokenUsageInp
259
259
  });
260
260
 
261
261
  return (
262
- <div className={cn("flex items-center justify-between text-xs", className)} {...props}>
262
+ <div className={cn("flex items-center justify-between text-meta", className)} {...props}>
263
263
  <span className="text-muted-foreground">{t("ai.tokenUsage.input")}</span>
264
264
  <TokensWithCost costText={inputCostText} tokens={inputTokens} />
265
265
  </div>
@@ -293,7 +293,7 @@ export const TokenUsageOutput = ({ className, children, ...props }: TokenUsageOu
293
293
  });
294
294
 
295
295
  return (
296
- <div className={cn("flex items-center justify-between text-xs", className)} {...props}>
296
+ <div className={cn("flex items-center justify-between text-meta", className)} {...props}>
297
297
  <span className="text-muted-foreground">{t("ai.tokenUsage.output")}</span>
298
298
  <TokensWithCost costText={outputCostText} tokens={outputTokens} />
299
299
  </div>
@@ -333,7 +333,7 @@ export const TokenUsageReasoning = ({
333
333
  });
334
334
 
335
335
  return (
336
- <div className={cn("flex items-center justify-between text-xs", className)} {...props}>
336
+ <div className={cn("flex items-center justify-between text-meta", className)} {...props}>
337
337
  <span className="text-muted-foreground">{t("ai.tokenUsage.reasoning")}</span>
338
338
  <TokensWithCost costText={reasoningCostText} tokens={reasoningTokens} />
339
339
  </div>
@@ -369,7 +369,7 @@ export const TokenUsageCache = ({ className, children, ...props }: TokenUsageCac
369
369
  });
370
370
 
371
371
  return (
372
- <div className={cn("flex items-center justify-between text-xs", className)} {...props}>
372
+ <div className={cn("flex items-center justify-between text-meta", className)} {...props}>
373
373
  <span className="text-muted-foreground">{t("ai.tokenUsage.cache")}</span>
374
374
  <TokensWithCost costText={cacheCostText} tokens={cacheTokens} />
375
375
  </div>