@artooi/agents-web-components 0.0.0-stage → 0.1.1

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 (543) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +21 -0
  3. package/README.md +4397 -2
  4. package/dist/agents-web-components.bundle.js +5708 -0
  5. package/dist/agents-web-components.bundle.js.map +7 -0
  6. package/dist/bundle.d.ts +3 -0
  7. package/dist/bundle.d.ts.map +1 -0
  8. package/dist/chat.d.ts +3 -0
  9. package/dist/chat.d.ts.map +1 -0
  10. package/dist/chat.js +16373 -0
  11. package/dist/chat.js.map +7 -0
  12. package/dist/chunk-ARNLFGCC.js +7715 -0
  13. package/dist/chunk-ARNLFGCC.js.map +7 -0
  14. package/dist/constants.d.ts +575 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/core/activity_registration.d.ts +19 -0
  17. package/dist/core/activity_registration.d.ts.map +1 -0
  18. package/dist/core/activity_registry.d.ts +46 -0
  19. package/dist/core/activity_registry.d.ts.map +1 -0
  20. package/dist/core/activity_renderer.d.ts +20 -0
  21. package/dist/core/activity_renderer.d.ts.map +1 -0
  22. package/dist/core/ag_ui_chat.d.ts +836 -0
  23. package/dist/core/ag_ui_chat.d.ts.map +1 -0
  24. package/dist/core/agui_client.d.ts +370 -0
  25. package/dist/core/agui_client.d.ts.map +1 -0
  26. package/dist/core/attachment.d.ts +42 -0
  27. package/dist/core/attachment.d.ts.map +1 -0
  28. package/dist/core/chat_registry.d.ts +23 -0
  29. package/dist/core/chat_registry.d.ts.map +1 -0
  30. package/dist/core/client_seed.d.ts +27 -0
  31. package/dist/core/client_seed.d.ts.map +1 -0
  32. package/dist/core/conversation_store.d.ts +195 -0
  33. package/dist/core/conversation_store.d.ts.map +1 -0
  34. package/dist/core/create_http_agent.d.ts +57 -0
  35. package/dist/core/create_http_agent.d.ts.map +1 -0
  36. package/dist/core/define_chat.d.ts +13 -0
  37. package/dist/core/define_chat.d.ts.map +1 -0
  38. package/dist/core/events/attachments_detail.d.ts +9 -0
  39. package/dist/core/events/attachments_detail.d.ts.map +1 -0
  40. package/dist/core/events/bar_height_detail.d.ts +6 -0
  41. package/dist/core/events/bar_height_detail.d.ts.map +1 -0
  42. package/dist/core/events/custom_agent_detail.d.ts +8 -0
  43. package/dist/core/events/custom_agent_detail.d.ts.map +1 -0
  44. package/dist/core/events/dock_width_detail.d.ts +8 -0
  45. package/dist/core/events/dock_width_detail.d.ts.map +1 -0
  46. package/dist/core/events/feedback_detail.d.ts +28 -0
  47. package/dist/core/events/feedback_detail.d.ts.map +1 -0
  48. package/dist/core/events/invalidate_detail.d.ts +16 -0
  49. package/dist/core/events/invalidate_detail.d.ts.map +1 -0
  50. package/dist/core/events/maximize_detail.d.ts +5 -0
  51. package/dist/core/events/maximize_detail.d.ts.map +1 -0
  52. package/dist/core/events/run_finished_detail.d.ts +36 -0
  53. package/dist/core/events/run_finished_detail.d.ts.map +1 -0
  54. package/dist/core/events/state_detail.d.ts +5 -0
  55. package/dist/core/events/state_detail.d.ts.map +1 -0
  56. package/dist/core/events/submit_detail.d.ts +8 -0
  57. package/dist/core/events/submit_detail.d.ts.map +1 -0
  58. package/dist/core/events/thread_detail.d.ts +27 -0
  59. package/dist/core/events/thread_detail.d.ts.map +1 -0
  60. package/dist/core/events/thread_title_detail.d.ts +8 -0
  61. package/dist/core/events/thread_title_detail.d.ts.map +1 -0
  62. package/dist/core/events/toggle_detail.d.ts +5 -0
  63. package/dist/core/events/toggle_detail.d.ts.map +1 -0
  64. package/dist/core/events/tool_run.d.ts +11 -0
  65. package/dist/core/events/tool_run.d.ts.map +1 -0
  66. package/dist/core/events/unread_detail.d.ts +11 -0
  67. package/dist/core/events/unread_detail.d.ts.map +1 -0
  68. package/dist/core/message_role.d.ts +4 -0
  69. package/dist/core/message_role.d.ts.map +1 -0
  70. package/dist/core/read_flag.d.ts +11 -0
  71. package/dist/core/read_flag.d.ts.map +1 -0
  72. package/dist/core/read_json_attribute.d.ts +15 -0
  73. package/dist/core/read_json_attribute.d.ts.map +1 -0
  74. package/dist/core/read_max_tool_rounds.d.ts +9 -0
  75. package/dist/core/read_max_tool_rounds.d.ts.map +1 -0
  76. package/dist/core/remote_conversation_store.d.ts +71 -0
  77. package/dist/core/remote_conversation_store.d.ts.map +1 -0
  78. package/dist/core/run_handlers.d.ts +85 -0
  79. package/dist/core/run_handlers.d.ts.map +1 -0
  80. package/dist/core/run_index.d.ts +58 -0
  81. package/dist/core/run_index.d.ts.map +1 -0
  82. package/dist/core/storage_scope.d.ts +118 -0
  83. package/dist/core/storage_scope.d.ts.map +1 -0
  84. package/dist/core/tool_outcome.d.ts +27 -0
  85. package/dist/core/tool_outcome.d.ts.map +1 -0
  86. package/dist/core/transcribe_audio.d.ts +32 -0
  87. package/dist/core/transcribe_audio.d.ts.map +1 -0
  88. package/dist/core/upload_attachment.d.ts +44 -0
  89. package/dist/core/upload_attachment.d.ts.map +1 -0
  90. package/dist/core/utils.d.ts +117 -0
  91. package/dist/core/utils.d.ts.map +1 -0
  92. package/dist/dom/animations.d.ts +122 -0
  93. package/dist/dom/animations.d.ts.map +1 -0
  94. package/dist/dom/dom_driver.d.ts +28 -0
  95. package/dist/dom/dom_driver.d.ts.map +1 -0
  96. package/dist/dom/highlight_overlay.d.ts +39 -0
  97. package/dist/dom/highlight_overlay.d.ts.map +1 -0
  98. package/dist/dom/native_setter.d.ts +5 -0
  99. package/dist/dom/native_setter.d.ts.map +1 -0
  100. package/dist/dom/ring_color.d.ts +16 -0
  101. package/dist/dom/ring_color.d.ts.map +1 -0
  102. package/dist/dom/utils.d.ts +3 -0
  103. package/dist/dom/utils.d.ts.map +1 -0
  104. package/dist/index.d.ts +62 -0
  105. package/dist/index.d.ts.map +1 -0
  106. package/dist/index.js +223 -0
  107. package/dist/index.js.map +7 -0
  108. package/dist/skills/fill_template.d.ts +16 -0
  109. package/dist/skills/fill_template.d.ts.map +1 -0
  110. package/dist/skills/parse_skills.d.ts +8 -0
  111. package/dist/skills/parse_skills.d.ts.map +1 -0
  112. package/dist/skills/skill.d.ts +33 -0
  113. package/dist/skills/skill.d.ts.map +1 -0
  114. package/dist/skills/skill_catalog.d.ts +69 -0
  115. package/dist/skills/skill_catalog.d.ts.map +1 -0
  116. package/dist/skills/skill_name_from.d.ts +12 -0
  117. package/dist/skills/skill_name_from.d.ts.map +1 -0
  118. package/dist/tools/chat_surface_tools.d.ts +77 -0
  119. package/dist/tools/chat_surface_tools.d.ts.map +1 -0
  120. package/dist/tools/client_tool_registry.d.ts +58 -0
  121. package/dist/tools/client_tool_registry.d.ts.map +1 -0
  122. package/dist/tools/is_destructive.d.ts +14 -0
  123. package/dist/tools/is_destructive.d.ts.map +1 -0
  124. package/dist/tools/is_navigates.d.ts +9 -0
  125. package/dist/tools/is_navigates.d.ts.map +1 -0
  126. package/dist/tools/page_action_tools.d.ts +30 -0
  127. package/dist/tools/page_action_tools.d.ts.map +1 -0
  128. package/dist/tools/page_map.d.ts +16 -0
  129. package/dist/tools/page_map.d.ts.map +1 -0
  130. package/dist/tools/page_state.d.ts +27 -0
  131. package/dist/tools/page_state.d.ts.map +1 -0
  132. package/dist/tools/parse_tool_catalog.d.ts +21 -0
  133. package/dist/tools/parse_tool_catalog.d.ts.map +1 -0
  134. package/dist/tools/route_map.d.ts +37 -0
  135. package/dist/tools/route_map.d.ts.map +1 -0
  136. package/dist/tools/tool_catalog.d.ts +86 -0
  137. package/dist/tools/tool_catalog.d.ts.map +1 -0
  138. package/dist/tools/tool_dispatch.d.ts +82 -0
  139. package/dist/tools/tool_dispatch.d.ts.map +1 -0
  140. package/dist/ui/charts/chart_block.d.ts +57 -0
  141. package/dist/ui/charts/chart_block.d.ts.map +1 -0
  142. package/dist/ui/charts/chart_spec_from.d.ts +12 -0
  143. package/dist/ui/charts/chart_spec_from.d.ts.map +1 -0
  144. package/dist/ui/charts/chart_styles.d.ts +2 -0
  145. package/dist/ui/charts/chart_styles.d.ts.map +1 -0
  146. package/dist/ui/charts/chart_tool.d.ts +15 -0
  147. package/dist/ui/charts/chart_tool.d.ts.map +1 -0
  148. package/dist/ui/composer/attachment_styles.d.ts +2 -0
  149. package/dist/ui/composer/attachment_styles.d.ts.map +1 -0
  150. package/dist/ui/composer/attachment_tray.d.ts +53 -0
  151. package/dist/ui/composer/attachment_tray.d.ts.map +1 -0
  152. package/dist/ui/composer/auto_grow.d.ts +10 -0
  153. package/dist/ui/composer/auto_grow.d.ts.map +1 -0
  154. package/dist/ui/composer/build_composer.d.ts +32 -0
  155. package/dist/ui/composer/build_composer.d.ts.map +1 -0
  156. package/dist/ui/composer/composer_attachments.d.ts +57 -0
  157. package/dist/ui/composer/composer_attachments.d.ts.map +1 -0
  158. package/dist/ui/composer/composer_styles.d.ts +2 -0
  159. package/dist/ui/composer/composer_styles.d.ts.map +1 -0
  160. package/dist/ui/composer/composer_voice.d.ts +48 -0
  161. package/dist/ui/composer/composer_voice.d.ts.map +1 -0
  162. package/dist/ui/composer/skill_styles.d.ts +2 -0
  163. package/dist/ui/composer/skill_styles.d.ts.map +1 -0
  164. package/dist/ui/composer/skills_menu.d.ts +34 -0
  165. package/dist/ui/composer/skills_menu.d.ts.map +1 -0
  166. package/dist/ui/composer/voice_input.d.ts +46 -0
  167. package/dist/ui/composer/voice_input.d.ts.map +1 -0
  168. package/dist/ui/excerpts/attach_copy_buttons.d.ts +13 -0
  169. package/dist/ui/excerpts/attach_copy_buttons.d.ts.map +1 -0
  170. package/dist/ui/excerpts/copy_payload.d.ts +30 -0
  171. package/dist/ui/excerpts/copy_payload.d.ts.map +1 -0
  172. package/dist/ui/excerpts/page_quote_offer.d.ts +33 -0
  173. package/dist/ui/excerpts/page_quote_offer.d.ts.map +1 -0
  174. package/dist/ui/excerpts/place_offer.d.ts +9 -0
  175. package/dist/ui/excerpts/place_offer.d.ts.map +1 -0
  176. package/dist/ui/excerpts/quote_selection.d.ts +66 -0
  177. package/dist/ui/excerpts/quote_selection.d.ts.map +1 -0
  178. package/dist/ui/excerpts/transcript_quote_offer.d.ts +57 -0
  179. package/dist/ui/excerpts/transcript_quote_offer.d.ts.map +1 -0
  180. package/dist/ui/fill_ui_string.d.ts +32 -0
  181. package/dist/ui/fill_ui_string.d.ts.map +1 -0
  182. package/dist/ui/history/checkpoint_menu.d.ts +41 -0
  183. package/dist/ui/history/checkpoint_menu.d.ts.map +1 -0
  184. package/dist/ui/history/conversation_history.d.ts +317 -0
  185. package/dist/ui/history/conversation_history.d.ts.map +1 -0
  186. package/dist/ui/history/history_styles.d.ts +2 -0
  187. package/dist/ui/history/history_styles.d.ts.map +1 -0
  188. package/dist/ui/history/relative_time.d.ts +23 -0
  189. package/dist/ui/history/relative_time.d.ts.map +1 -0
  190. package/dist/ui/history/thread_drawer.d.ts +64 -0
  191. package/dist/ui/history/thread_drawer.d.ts.map +1 -0
  192. package/dist/ui/history/utils.d.ts +2 -0
  193. package/dist/ui/history/utils.d.ts.map +1 -0
  194. package/dist/ui/interrupts/approval_card.d.ts +64 -0
  195. package/dist/ui/interrupts/approval_card.d.ts.map +1 -0
  196. package/dist/ui/interrupts/approval_styles.d.ts +2 -0
  197. package/dist/ui/interrupts/approval_styles.d.ts.map +1 -0
  198. package/dist/ui/interrupts/confirmation_card.d.ts +51 -0
  199. package/dist/ui/interrupts/confirmation_card.d.ts.map +1 -0
  200. package/dist/ui/interrupts/confirmation_styles.d.ts +2 -0
  201. package/dist/ui/interrupts/confirmation_styles.d.ts.map +1 -0
  202. package/dist/ui/interrupts/pending_decision.d.ts +22 -0
  203. package/dist/ui/interrupts/pending_decision.d.ts.map +1 -0
  204. package/dist/ui/interrupts/question_card.d.ts +49 -0
  205. package/dist/ui/interrupts/question_card.d.ts.map +1 -0
  206. package/dist/ui/interrupts/question_styles.d.ts +2 -0
  207. package/dist/ui/interrupts/question_styles.d.ts.map +1 -0
  208. package/dist/ui/place/place.d.ts +17 -0
  209. package/dist/ui/place/place.d.ts.map +1 -0
  210. package/dist/ui/place/place_chip.d.ts +26 -0
  211. package/dist/ui/place/place_chip.d.ts.map +1 -0
  212. package/dist/ui/place/place_from_route.d.ts +9 -0
  213. package/dist/ui/place/place_from_route.d.ts.map +1 -0
  214. package/dist/ui/place/place_styles.d.ts +2 -0
  215. package/dist/ui/place/place_styles.d.ts.map +1 -0
  216. package/dist/ui/placement/clamp_launcher.d.ts +20 -0
  217. package/dist/ui/placement/clamp_launcher.d.ts.map +1 -0
  218. package/dist/ui/placement/clamp_panel.d.ts +13 -0
  219. package/dist/ui/placement/clamp_panel.d.ts.map +1 -0
  220. package/dist/ui/placement/collapse_styles.d.ts +2 -0
  221. package/dist/ui/placement/collapse_styles.d.ts.map +1 -0
  222. package/dist/ui/placement/dock_styles.d.ts +2 -0
  223. package/dist/ui/placement/dock_styles.d.ts.map +1 -0
  224. package/dist/ui/placement/embedded_styles.d.ts +2 -0
  225. package/dist/ui/placement/embedded_styles.d.ts.map +1 -0
  226. package/dist/ui/placement/launcher_drag.d.ts +49 -0
  227. package/dist/ui/placement/launcher_drag.d.ts.map +1 -0
  228. package/dist/ui/placement/launcher_placement.d.ts +77 -0
  229. package/dist/ui/placement/launcher_placement.d.ts.map +1 -0
  230. package/dist/ui/placement/launcher_styles.d.ts +2 -0
  231. package/dist/ui/placement/launcher_styles.d.ts.map +1 -0
  232. package/dist/ui/placement/page_styles.d.ts +2 -0
  233. package/dist/ui/placement/page_styles.d.ts.map +1 -0
  234. package/dist/ui/placement/panel_drag.d.ts +40 -0
  235. package/dist/ui/placement/panel_drag.d.ts.map +1 -0
  236. package/dist/ui/placement/panel_placement.d.ts +173 -0
  237. package/dist/ui/placement/panel_placement.d.ts.map +1 -0
  238. package/dist/ui/placement/place_widget.d.ts +31 -0
  239. package/dist/ui/placement/place_widget.d.ts.map +1 -0
  240. package/dist/ui/placement/preset_styles.d.ts +2 -0
  241. package/dist/ui/placement/preset_styles.d.ts.map +1 -0
  242. package/dist/ui/placement/resize_handle.d.ts +78 -0
  243. package/dist/ui/placement/resize_handle.d.ts.map +1 -0
  244. package/dist/ui/placement/resize_styles.d.ts +2 -0
  245. package/dist/ui/placement/resize_styles.d.ts.map +1 -0
  246. package/dist/ui/placement/sidebar_styles.d.ts +2 -0
  247. package/dist/ui/placement/sidebar_styles.d.ts.map +1 -0
  248. package/dist/ui/placement/small_viewport_styles.d.ts +2 -0
  249. package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -0
  250. package/dist/ui/placement/surface_for.d.ts +93 -0
  251. package/dist/ui/placement/surface_for.d.ts.map +1 -0
  252. package/dist/ui/progress/prettify_tool_name.d.ts +11 -0
  253. package/dist/ui/progress/prettify_tool_name.d.ts.map +1 -0
  254. package/dist/ui/progress/run_announcer.d.ts +41 -0
  255. package/dist/ui/progress/run_announcer.d.ts.map +1 -0
  256. package/dist/ui/progress/run_notice.d.ts +21 -0
  257. package/dist/ui/progress/run_notice.d.ts.map +1 -0
  258. package/dist/ui/progress/run_notice_styles.d.ts +2 -0
  259. package/dist/ui/progress/run_notice_styles.d.ts.map +1 -0
  260. package/dist/ui/progress/subagent_panel.d.ts +101 -0
  261. package/dist/ui/progress/subagent_panel.d.ts.map +1 -0
  262. package/dist/ui/progress/subagent_progress.d.ts +57 -0
  263. package/dist/ui/progress/subagent_progress.d.ts.map +1 -0
  264. package/dist/ui/progress/subagent_update.d.ts +28 -0
  265. package/dist/ui/progress/subagent_update.d.ts.map +1 -0
  266. package/dist/ui/progress/thoughts_block.d.ts +57 -0
  267. package/dist/ui/progress/thoughts_block.d.ts.map +1 -0
  268. package/dist/ui/progress/thoughts_styles.d.ts +2 -0
  269. package/dist/ui/progress/thoughts_styles.d.ts.map +1 -0
  270. package/dist/ui/progress/tool_call_card.d.ts +167 -0
  271. package/dist/ui/progress/tool_call_card.d.ts.map +1 -0
  272. package/dist/ui/progress/tool_group_styles.d.ts +2 -0
  273. package/dist/ui/progress/tool_group_styles.d.ts.map +1 -0
  274. package/dist/ui/progress/tool_step_group.d.ts +50 -0
  275. package/dist/ui/progress/tool_step_group.d.ts.map +1 -0
  276. package/dist/ui/progress/tool_step_styles.d.ts +2 -0
  277. package/dist/ui/progress/tool_step_styles.d.ts.map +1 -0
  278. package/dist/ui/shell/adopt_styles.d.ts +28 -0
  279. package/dist/ui/shell/adopt_styles.d.ts.map +1 -0
  280. package/dist/ui/shell/build_header.d.ts +45 -0
  281. package/dist/ui/shell/build_header.d.ts.map +1 -0
  282. package/dist/ui/shell/build_launcher.d.ts +33 -0
  283. package/dist/ui/shell/build_launcher.d.ts.map +1 -0
  284. package/dist/ui/shell/collapse_glyph.d.ts +14 -0
  285. package/dist/ui/shell/collapse_glyph.d.ts.map +1 -0
  286. package/dist/ui/shell/frame_styles.d.ts +2 -0
  287. package/dist/ui/shell/frame_styles.d.ts.map +1 -0
  288. package/dist/ui/shell/glyph_slot.d.ts +7 -0
  289. package/dist/ui/shell/glyph_slot.d.ts.map +1 -0
  290. package/dist/ui/shell/header_button.d.ts +11 -0
  291. package/dist/ui/shell/header_button.d.ts.map +1 -0
  292. package/dist/ui/shell/icon_element.d.ts +12 -0
  293. package/dist/ui/shell/icon_element.d.ts.map +1 -0
  294. package/dist/ui/shell/is_unread_badge_enabled.d.ts +10 -0
  295. package/dist/ui/shell/is_unread_badge_enabled.d.ts.map +1 -0
  296. package/dist/ui/shell/read_launcher_icon_url.d.ts +8 -0
  297. package/dist/ui/shell/read_launcher_icon_url.d.ts.map +1 -0
  298. package/dist/ui/shell/theme_styles.d.ts +2 -0
  299. package/dist/ui/shell/theme_styles.d.ts.map +1 -0
  300. package/dist/ui/shell/token_styles.d.ts +2 -0
  301. package/dist/ui/shell/token_styles.d.ts.map +1 -0
  302. package/dist/ui/styles.d.ts +2 -0
  303. package/dist/ui/styles.d.ts.map +1 -0
  304. package/dist/ui/themes/classic_styles.d.ts +2 -0
  305. package/dist/ui/themes/classic_styles.d.ts.map +1 -0
  306. package/dist/ui/themes/classic_tokens.d.ts +2 -0
  307. package/dist/ui/themes/classic_tokens.d.ts.map +1 -0
  308. package/dist/ui/themes/code_tokens.d.ts +2 -0
  309. package/dist/ui/themes/code_tokens.d.ts.map +1 -0
  310. package/dist/ui/themes/ledger_styles.d.ts +2 -0
  311. package/dist/ui/themes/ledger_styles.d.ts.map +1 -0
  312. package/dist/ui/themes/ledger_tokens.d.ts +2 -0
  313. package/dist/ui/themes/ledger_tokens.d.ts.map +1 -0
  314. package/dist/ui/themes/modern_styles.d.ts +2 -0
  315. package/dist/ui/themes/modern_styles.d.ts.map +1 -0
  316. package/dist/ui/themes/quiet_styles.d.ts +2 -0
  317. package/dist/ui/themes/quiet_styles.d.ts.map +1 -0
  318. package/dist/ui/themes/scheme_styles.d.ts +2 -0
  319. package/dist/ui/themes/scheme_styles.d.ts.map +1 -0
  320. package/dist/ui/themes/soft_styles.d.ts +2 -0
  321. package/dist/ui/themes/soft_styles.d.ts.map +1 -0
  322. package/dist/ui/themes/soft_tokens.d.ts +2 -0
  323. package/dist/ui/themes/soft_tokens.d.ts.map +1 -0
  324. package/dist/ui/themes/theme_hosts.d.ts +15 -0
  325. package/dist/ui/themes/theme_hosts.d.ts.map +1 -0
  326. package/dist/ui/transcript/answer_actions.d.ts +50 -0
  327. package/dist/ui/transcript/answer_actions.d.ts.map +1 -0
  328. package/dist/ui/transcript/answer_stream.d.ts +56 -0
  329. package/dist/ui/transcript/answer_stream.d.ts.map +1 -0
  330. package/dist/ui/transcript/attachment_chip_styles.d.ts +2 -0
  331. package/dist/ui/transcript/attachment_chip_styles.d.ts.map +1 -0
  332. package/dist/ui/transcript/attachment_chips.d.ts +21 -0
  333. package/dist/ui/transcript/attachment_chips.d.ts.map +1 -0
  334. package/dist/ui/transcript/build_transcript.d.ts +21 -0
  335. package/dist/ui/transcript/build_transcript.d.ts.map +1 -0
  336. package/dist/ui/transcript/greeting_styles.d.ts +2 -0
  337. package/dist/ui/transcript/greeting_styles.d.ts.map +1 -0
  338. package/dist/ui/transcript/groups_tool_steps.d.ts +13 -0
  339. package/dist/ui/transcript/groups_tool_steps.d.ts.map +1 -0
  340. package/dist/ui/transcript/message_action_styles.d.ts +2 -0
  341. package/dist/ui/transcript/message_action_styles.d.ts.map +1 -0
  342. package/dist/ui/transcript/message_actions.d.ts +74 -0
  343. package/dist/ui/transcript/message_actions.d.ts.map +1 -0
  344. package/dist/ui/transcript/message_styles.d.ts +2 -0
  345. package/dist/ui/transcript/message_styles.d.ts.map +1 -0
  346. package/dist/ui/transcript/render_markdown.d.ts +40 -0
  347. package/dist/ui/transcript/render_markdown.d.ts.map +1 -0
  348. package/dist/ui/transcript/render_or_warn.d.ts +16 -0
  349. package/dist/ui/transcript/render_or_warn.d.ts.map +1 -0
  350. package/dist/ui/transcript/reveal_words.d.ts +8 -0
  351. package/dist/ui/transcript/reveal_words.d.ts.map +1 -0
  352. package/dist/ui/transcript/starter_chips.d.ts +21 -0
  353. package/dist/ui/transcript/starter_chips.d.ts.map +1 -0
  354. package/dist/ui/transcript/stick_to_bottom.d.ts +55 -0
  355. package/dist/ui/transcript/stick_to_bottom.d.ts.map +1 -0
  356. package/dist/ui/transcript/suggestion_chips.d.ts +29 -0
  357. package/dist/ui/transcript/suggestion_chips.d.ts.map +1 -0
  358. package/dist/ui/transcript/transcript.d.ts +196 -0
  359. package/dist/ui/transcript/transcript.d.ts.map +1 -0
  360. package/dist/ui/transcript/transcript_styles.d.ts +2 -0
  361. package/dist/ui/transcript/transcript_styles.d.ts.map +1 -0
  362. package/dist/ui/ui_strings.d.ts +352 -0
  363. package/dist/ui/ui_strings.d.ts.map +1 -0
  364. package/dist/version.d.ts +2 -0
  365. package/dist/version.d.ts.map +1 -0
  366. package/package.json +86 -3
  367. package/src/bundle.ts +2 -0
  368. package/src/chat.ts +2 -0
  369. package/src/constants.ts +650 -0
  370. package/src/core/activity_registration.ts +19 -0
  371. package/src/core/activity_registry.ts +133 -0
  372. package/src/core/activity_renderer.ts +19 -0
  373. package/src/core/ag_ui_chat.ts +3966 -0
  374. package/src/core/agui_client.ts +1028 -0
  375. package/src/core/attachment.ts +62 -0
  376. package/src/core/chat_registry.ts +53 -0
  377. package/src/core/client_seed.ts +27 -0
  378. package/src/core/conversation_store.ts +478 -0
  379. package/src/core/create_http_agent.ts +97 -0
  380. package/src/core/define_chat.ts +25 -0
  381. package/src/core/events/attachments_detail.ts +9 -0
  382. package/src/core/events/bar_height_detail.ts +5 -0
  383. package/src/core/events/custom_agent_detail.ts +7 -0
  384. package/src/core/events/dock_width_detail.ts +7 -0
  385. package/src/core/events/feedback_detail.ts +27 -0
  386. package/src/core/events/invalidate_detail.ts +15 -0
  387. package/src/core/events/maximize_detail.ts +4 -0
  388. package/src/core/events/run_finished_detail.ts +36 -0
  389. package/src/core/events/state_detail.ts +4 -0
  390. package/src/core/events/submit_detail.ts +8 -0
  391. package/src/core/events/thread_detail.ts +26 -0
  392. package/src/core/events/thread_title_detail.ts +7 -0
  393. package/src/core/events/toggle_detail.ts +4 -0
  394. package/src/core/events/tool_run.ts +10 -0
  395. package/src/core/events/unread_detail.ts +10 -0
  396. package/src/core/message_role.ts +4 -0
  397. package/src/core/read_flag.ts +13 -0
  398. package/src/core/read_json_attribute.ts +30 -0
  399. package/src/core/read_max_tool_rounds.ts +13 -0
  400. package/src/core/remote_conversation_store.ts +279 -0
  401. package/src/core/run_handlers.ts +524 -0
  402. package/src/core/run_index.ts +114 -0
  403. package/src/core/storage_scope.ts +291 -0
  404. package/src/core/tool_outcome.ts +39 -0
  405. package/src/core/transcribe_audio.ts +76 -0
  406. package/src/core/upload_attachment.ts +130 -0
  407. package/src/core/utils.ts +230 -0
  408. package/src/dom/animations.ts +341 -0
  409. package/src/dom/dom_driver.ts +91 -0
  410. package/src/dom/highlight_overlay.ts +204 -0
  411. package/src/dom/native_setter.ts +40 -0
  412. package/src/dom/ring_color.ts +206 -0
  413. package/src/dom/utils.ts +5 -0
  414. package/src/index.ts +220 -0
  415. package/src/skills/fill_template.ts +31 -0
  416. package/src/skills/parse_skills.ts +31 -0
  417. package/src/skills/skill.ts +32 -0
  418. package/src/skills/skill_catalog.ts +172 -0
  419. package/src/skills/skill_name_from.ts +19 -0
  420. package/src/tools/chat_surface_tools.ts +183 -0
  421. package/src/tools/client_tool_registry.ts +80 -0
  422. package/src/tools/is_destructive.ts +17 -0
  423. package/src/tools/is_navigates.ts +12 -0
  424. package/src/tools/page_action_tools.ts +123 -0
  425. package/src/tools/page_map.ts +26 -0
  426. package/src/tools/page_state.ts +57 -0
  427. package/src/tools/parse_tool_catalog.ts +41 -0
  428. package/src/tools/route_map.ts +132 -0
  429. package/src/tools/tool_catalog.ts +334 -0
  430. package/src/tools/tool_dispatch.ts +453 -0
  431. package/src/ui/charts/chart_block.ts +519 -0
  432. package/src/ui/charts/chart_spec_from.ts +125 -0
  433. package/src/ui/charts/chart_styles.ts +63 -0
  434. package/src/ui/charts/chart_tool.ts +72 -0
  435. package/src/ui/composer/attachment_styles.ts +71 -0
  436. package/src/ui/composer/attachment_tray.ts +295 -0
  437. package/src/ui/composer/auto_grow.ts +12 -0
  438. package/src/ui/composer/build_composer.ts +114 -0
  439. package/src/ui/composer/composer_attachments.ts +324 -0
  440. package/src/ui/composer/composer_styles.ts +177 -0
  441. package/src/ui/composer/composer_voice.ts +93 -0
  442. package/src/ui/composer/skill_styles.ts +120 -0
  443. package/src/ui/composer/skills_menu.ts +188 -0
  444. package/src/ui/composer/voice_input.ts +282 -0
  445. package/src/ui/excerpts/attach_copy_buttons.ts +73 -0
  446. package/src/ui/excerpts/copy_payload.ts +156 -0
  447. package/src/ui/excerpts/page_quote_offer.ts +203 -0
  448. package/src/ui/excerpts/place_offer.ts +24 -0
  449. package/src/ui/excerpts/quote_selection.ts +345 -0
  450. package/src/ui/excerpts/transcript_quote_offer.ts +175 -0
  451. package/src/ui/fill_ui_string.ts +41 -0
  452. package/src/ui/history/checkpoint_menu.ts +300 -0
  453. package/src/ui/history/conversation_history.ts +1169 -0
  454. package/src/ui/history/history_styles.ts +492 -0
  455. package/src/ui/history/relative_time.ts +50 -0
  456. package/src/ui/history/thread_drawer.ts +471 -0
  457. package/src/ui/history/utils.ts +11 -0
  458. package/src/ui/interrupts/approval_card.ts +202 -0
  459. package/src/ui/interrupts/approval_styles.ts +52 -0
  460. package/src/ui/interrupts/confirmation_card.ts +138 -0
  461. package/src/ui/interrupts/confirmation_styles.ts +114 -0
  462. package/src/ui/interrupts/pending_decision.ts +33 -0
  463. package/src/ui/interrupts/question_card.ts +213 -0
  464. package/src/ui/interrupts/question_styles.ts +73 -0
  465. package/src/ui/place/place.ts +16 -0
  466. package/src/ui/place/place_chip.ts +146 -0
  467. package/src/ui/place/place_from_route.ts +27 -0
  468. package/src/ui/place/place_styles.ts +108 -0
  469. package/src/ui/placement/clamp_launcher.ts +38 -0
  470. package/src/ui/placement/clamp_panel.ts +30 -0
  471. package/src/ui/placement/collapse_styles.ts +472 -0
  472. package/src/ui/placement/dock_styles.ts +116 -0
  473. package/src/ui/placement/embedded_styles.ts +14 -0
  474. package/src/ui/placement/launcher_drag.ts +206 -0
  475. package/src/ui/placement/launcher_placement.ts +133 -0
  476. package/src/ui/placement/launcher_styles.ts +189 -0
  477. package/src/ui/placement/page_styles.ts +47 -0
  478. package/src/ui/placement/panel_drag.ts +138 -0
  479. package/src/ui/placement/panel_placement.ts +1975 -0
  480. package/src/ui/placement/place_widget.ts +64 -0
  481. package/src/ui/placement/preset_styles.ts +49 -0
  482. package/src/ui/placement/resize_handle.ts +229 -0
  483. package/src/ui/placement/resize_styles.ts +201 -0
  484. package/src/ui/placement/sidebar_styles.ts +113 -0
  485. package/src/ui/placement/small_viewport_styles.ts +70 -0
  486. package/src/ui/placement/surface_for.ts +183 -0
  487. package/src/ui/progress/prettify_tool_name.ts +16 -0
  488. package/src/ui/progress/run_announcer.ts +67 -0
  489. package/src/ui/progress/run_notice.ts +61 -0
  490. package/src/ui/progress/run_notice_styles.ts +52 -0
  491. package/src/ui/progress/subagent_panel.ts +227 -0
  492. package/src/ui/progress/subagent_progress.ts +200 -0
  493. package/src/ui/progress/subagent_update.ts +89 -0
  494. package/src/ui/progress/thoughts_block.ts +165 -0
  495. package/src/ui/progress/thoughts_styles.ts +74 -0
  496. package/src/ui/progress/tool_call_card.ts +429 -0
  497. package/src/ui/progress/tool_group_styles.ts +313 -0
  498. package/src/ui/progress/tool_step_group.ts +317 -0
  499. package/src/ui/progress/tool_step_styles.ts +486 -0
  500. package/src/ui/shell/adopt_styles.ts +34 -0
  501. package/src/ui/shell/build_header.ts +121 -0
  502. package/src/ui/shell/build_launcher.ts +79 -0
  503. package/src/ui/shell/collapse_glyph.ts +42 -0
  504. package/src/ui/shell/frame_styles.ts +147 -0
  505. package/src/ui/shell/glyph_slot.ts +12 -0
  506. package/src/ui/shell/header_button.ts +22 -0
  507. package/src/ui/shell/icon_element.ts +33 -0
  508. package/src/ui/shell/is_unread_badge_enabled.ts +11 -0
  509. package/src/ui/shell/read_launcher_icon_url.ts +9 -0
  510. package/src/ui/shell/theme_styles.ts +11 -0
  511. package/src/ui/shell/token_styles.ts +480 -0
  512. package/src/ui/styles.ts +110 -0
  513. package/src/ui/themes/classic_styles.ts +32 -0
  514. package/src/ui/themes/classic_tokens.ts +51 -0
  515. package/src/ui/themes/code_tokens.ts +21 -0
  516. package/src/ui/themes/ledger_styles.ts +169 -0
  517. package/src/ui/themes/ledger_tokens.ts +33 -0
  518. package/src/ui/themes/modern_styles.ts +80 -0
  519. package/src/ui/themes/quiet_styles.ts +118 -0
  520. package/src/ui/themes/scheme_styles.ts +26 -0
  521. package/src/ui/themes/soft_styles.ts +149 -0
  522. package/src/ui/themes/soft_tokens.ts +29 -0
  523. package/src/ui/themes/theme_hosts.ts +14 -0
  524. package/src/ui/transcript/answer_actions.ts +165 -0
  525. package/src/ui/transcript/answer_stream.ts +123 -0
  526. package/src/ui/transcript/attachment_chip_styles.ts +116 -0
  527. package/src/ui/transcript/attachment_chips.ts +82 -0
  528. package/src/ui/transcript/build_transcript.ts +67 -0
  529. package/src/ui/transcript/greeting_styles.ts +171 -0
  530. package/src/ui/transcript/groups_tool_steps.ts +16 -0
  531. package/src/ui/transcript/message_action_styles.ts +155 -0
  532. package/src/ui/transcript/message_actions.ts +234 -0
  533. package/src/ui/transcript/message_styles.ts +262 -0
  534. package/src/ui/transcript/render_markdown.ts +181 -0
  535. package/src/ui/transcript/render_or_warn.ts +22 -0
  536. package/src/ui/transcript/reveal_words.ts +41 -0
  537. package/src/ui/transcript/starter_chips.ts +42 -0
  538. package/src/ui/transcript/stick_to_bottom.ts +126 -0
  539. package/src/ui/transcript/suggestion_chips.ts +73 -0
  540. package/src/ui/transcript/transcript.ts +555 -0
  541. package/src/ui/transcript/transcript_styles.ts +153 -0
  542. package/src/ui/ui_strings.ts +550 -0
  543. package/src/version.ts +1 -0
@@ -0,0 +1,519 @@
1
+ /**
2
+ * Draw a {@link ChartSpec} as SVG.
3
+ *
4
+ * Every node is built with `createElement`, never parsed from a string, so this
5
+ * path never reaches the markdown sanitiser and cannot be widened by model
6
+ * output. That is the argument for taking a *spec* rather than markup: the model
7
+ * chooses the numbers, this module chooses the DOM. It is why a chart can be
8
+ * shown on a surface that keeps `img` off by default, a model-controlled URL
9
+ * being a zero-click exfiltration channel.
10
+ *
11
+ * Hand-rolled rather than a charting library, and the difference is not
12
+ * marginal: the whole renderer costs single-digit kilobytes where a library
13
+ * costs roughly half this bundle again, in a component distributed over a CDN.
14
+ *
15
+ * **The drawing is sized in CSS pixels, not scaled to them.** An SVG with a
16
+ * fixed viewBox and `width: 100%` is a picture the browser magnifies: widen the
17
+ * panel and every stroke, every label and the whole frame grow with it. So the
18
+ * geometry is computed for the width the block actually has, one user unit to
19
+ * one CSS pixel, and recomputed when that width changes -- a 10px label is
20
+ * 10px at every size the block is given.
21
+ *
22
+ * How wide the block is allowed to get is the stylesheet's question, not this
23
+ * module's, and the answer there is that a chart stops at its own width rather
24
+ * than stretching with the panel, the way a message does. The two halves are
25
+ * separate on purpose: this one keeps a chart from being magnified, that one
26
+ * keeps it from being stretched, and a host that raises the cap gets a bigger
27
+ * chart with the same 10px labels rather than a magnified one.
28
+ */
29
+
30
+ const SVG_NS = "http://www.w3.org/2000/svg";
31
+
32
+ /** One named series of numbers. */
33
+ export interface ChartSeries {
34
+ readonly label: string;
35
+ readonly points: readonly number[];
36
+ }
37
+
38
+ /** How a spec is drawn. */
39
+ export type ChartKind = "bar" | "line" | "pie" | "scatter" | "stacked";
40
+
41
+ /** A chart, as data. */
42
+ export interface ChartSpec {
43
+ readonly kind: ChartKind;
44
+ readonly title?: string;
45
+ readonly labels: readonly string[];
46
+ readonly series: readonly ChartSeries[];
47
+ }
48
+
49
+ /** The frame a chart is drawn into, in CSS pixels. */
50
+ interface Geometry {
51
+ readonly width: number;
52
+ readonly height: number;
53
+ /** The plotting area inside the padding. */
54
+ readonly plotW: number;
55
+ readonly plotH: number;
56
+ }
57
+
58
+ const PAD = { top: 20, right: 12, bottom: 30, left: 44 };
59
+
60
+ /**
61
+ * The width drawn before the block has been measured -- while it is still
62
+ * detached, and in a caller that never puts it in a document at all. It is the
63
+ * width this renderer drew at unconditionally before it could measure, so a
64
+ * chart that is never measured looks exactly as it always did.
65
+ */
66
+ const DEFAULT_WIDTH = 480;
67
+
68
+ /**
69
+ * The narrowest frame worth computing. Below this the SVG scales down as it
70
+ * always did, which is the right answer at the bottom end: a 200px chart with
71
+ * 10px labels has no room for the labels either way, and shrinking them keeps
72
+ * the shape readable.
73
+ */
74
+ const MIN_WIDTH = 220;
75
+
76
+ /**
77
+ * How tall a chart is for its width, and the band that holds. The ratio is the
78
+ * old fixed 480x220 frame, so the default width draws precisely what it drew
79
+ * before; the band is what stops a wide panel from turning a chart into a
80
+ * banner or a narrow one into a strip.
81
+ */
82
+ const HEIGHT_RATIO = 220 / 480;
83
+ const MIN_HEIGHT = 160;
84
+ const MAX_HEIGHT = 320;
85
+
86
+ /**
87
+ * The step a measured width is rounded to before it is redrawn.
88
+ *
89
+ * The SVG keeps `width="100%"`, so it fills its block exactly whatever the
90
+ * viewBox says; rounding the viewBox to 8px therefore costs at most a 3%
91
+ * scale at the narrow end and nothing anyone can see, while cutting the
92
+ * redraws during a panel drag from one per pixel to one per eight.
93
+ */
94
+ const WIDTH_STEP = 8;
95
+
96
+ /** A rough advance width per character for the 10px axis font. */
97
+ const AXIS_CHAR_WIDTH = 5.6;
98
+
99
+ // Read from the theme's palette rather than a fixed ramp. The private alias
100
+ // reads the host's --ag-ui-chart-N first (see token_styles), so a host's
101
+ // colour wins over any theme's, and a theme can still supply its own.
102
+ const SERIES_COLORS: readonly string[] = [
103
+ "var(--_chart-1)",
104
+ "var(--_chart-2)",
105
+ "var(--_chart-3)",
106
+ "var(--_chart-4)",
107
+ "var(--_chart-5)",
108
+ "var(--_chart-6)",
109
+ ];
110
+
111
+ /** The colour for series `index`, wrapping when there are more series than colours. */
112
+ export function seriesColor(index: number): string {
113
+ // Cast rather than a `??` fallback: the modulo guarantees a hit, so a
114
+ // fallback would be a branch no test could ever reach.
115
+ return SERIES_COLORS[index % SERIES_COLORS.length] as string;
116
+ }
117
+
118
+ /** The frame for a block of this width. */
119
+ function geometryFor(width: number): Geometry {
120
+ const w = Math.max(MIN_WIDTH, width);
121
+ const h = Math.min(MAX_HEIGHT, Math.max(MIN_HEIGHT, Math.round(w * HEIGHT_RATIO)));
122
+ return {
123
+ width: w,
124
+ height: h,
125
+ plotW: w - PAD.left - PAD.right,
126
+ plotH: h - PAD.top - PAD.bottom,
127
+ };
128
+ }
129
+
130
+ function el<K extends keyof SVGElementTagNameMap>(
131
+ name: K,
132
+ attrs: Record<string, string | number>,
133
+ ): SVGElementTagNameMap[K] {
134
+ const node = document.createElementNS(SVG_NS, name);
135
+ for (const [key, value] of Object.entries(attrs)) {
136
+ node.setAttribute(key, String(value));
137
+ }
138
+ return node;
139
+ }
140
+
141
+ function text(value: string, attrs: Record<string, string | number>): SVGTextElement {
142
+ const node = el("text", {
143
+ "font-size": 10,
144
+ fill: "currentColor",
145
+ "fill-opacity": 0.65,
146
+ ...attrs,
147
+ });
148
+ // `textContent`, so a model-supplied label is text and never markup.
149
+ node.textContent = value;
150
+ return node;
151
+ }
152
+
153
+ /** Every running subtotal a stack passes through, column by column. */
154
+ function stackRunning(spec: ChartSpec): number[] {
155
+ const seen: number[] = [];
156
+ spec.labels.forEach((_label, i) => {
157
+ let running = 0;
158
+ for (const series of spec.series) {
159
+ running += series.points[i] ?? 0;
160
+ seen.push(running);
161
+ }
162
+ });
163
+ return seen;
164
+ }
165
+
166
+ function extent(spec: ChartSpec): { min: number; max: number } {
167
+ // A stack's extent has to cover every *running subtotal*, not just the column
168
+ // totals: with mixed signs the running value swings wider than the total it
169
+ // ends on, and scaling to the total alone puts segments far off the canvas.
170
+ const values =
171
+ spec.kind === "stacked"
172
+ ? stackRunning(spec)
173
+ : spec.series.flatMap((series) => [...series.points]);
174
+ const max = Math.max(0, ...values);
175
+ const min = Math.min(0, ...values);
176
+ // A flat series would divide by zero when scaling; give it a nominal span so
177
+ // it draws as a flat line rather than vanishing.
178
+ return max === min ? { min, max: max + 1 } : { min, max };
179
+ }
180
+
181
+ function scaleY(value: number, min: number, max: number, geo: Geometry): number {
182
+ return PAD.top + geo.plotH - ((value - min) / (max - min)) * geo.plotH;
183
+ }
184
+
185
+ function bandCentre(index: number, count: number, geo: Geometry): number {
186
+ const step = geo.plotW / count;
187
+ return PAD.left + step * index + step / 2;
188
+ }
189
+
190
+ /**
191
+ * Draw every nth label, for the smallest n whose labels have room.
192
+ *
193
+ * Axis text is a fixed 10px now rather than something that shrank with the
194
+ * frame, so at the narrow end the labels are the first thing to collide -- and
195
+ * a smear of overlapping words says less than half as many words with space
196
+ * around them. The character estimate only has to be good enough to pick a
197
+ * step; measuring text properly would mean laying it out first.
198
+ */
199
+ function labelStride(labels: readonly string[], geo: Geometry): number {
200
+ const band = geo.plotW / labels.length;
201
+ const widest = Math.max(...labels.map((label) => label.length)) * AXIS_CHAR_WIDTH;
202
+ return Math.max(1, Math.ceil(widest / band));
203
+ }
204
+
205
+ function drawAxes(
206
+ svg: SVGSVGElement,
207
+ spec: ChartSpec,
208
+ geo: Geometry,
209
+ min: number,
210
+ max: number,
211
+ ): void {
212
+ for (const value of [min, max]) {
213
+ const y = scaleY(value, min, max, geo);
214
+ svg.appendChild(
215
+ el("line", {
216
+ x1: PAD.left,
217
+ y1: y,
218
+ x2: geo.width - PAD.right,
219
+ y2: y,
220
+ stroke: "currentColor",
221
+ "stroke-opacity": value === min ? 0.35 : 0.12,
222
+ }),
223
+ );
224
+ svg.appendChild(
225
+ text(String(Math.round(value)), { x: PAD.left - 6, y: y + 4, "text-anchor": "end" }),
226
+ );
227
+ }
228
+ const stride = labelStride(spec.labels, geo);
229
+ spec.labels.forEach((label, i) => {
230
+ if (i % stride !== 0) {
231
+ return;
232
+ }
233
+ svg.appendChild(
234
+ text(label, {
235
+ x: bandCentre(i, spec.labels.length, geo),
236
+ y: geo.height - PAD.bottom + 16,
237
+ "text-anchor": "middle",
238
+ }),
239
+ );
240
+ });
241
+ }
242
+
243
+ function drawBars(
244
+ svg: SVGSVGElement,
245
+ spec: ChartSpec,
246
+ geo: Geometry,
247
+ min: number,
248
+ max: number,
249
+ ): void {
250
+ const step = geo.plotW / spec.labels.length;
251
+ const width = (step * 0.7) / spec.series.length;
252
+ const base = scaleY(min, min, max, geo);
253
+ spec.series.forEach((series, s) => {
254
+ series.points.forEach((value, i) => {
255
+ const y = scaleY(value, min, max, geo);
256
+ svg.appendChild(
257
+ el("rect", {
258
+ x: PAD.left + step * i + step * 0.15 + width * s,
259
+ y,
260
+ width,
261
+ height: Math.max(1, base - y),
262
+ fill: seriesColor(s),
263
+ rx: 2,
264
+ }),
265
+ );
266
+ });
267
+ });
268
+ }
269
+
270
+ function drawStacked(
271
+ svg: SVGSVGElement,
272
+ spec: ChartSpec,
273
+ geo: Geometry,
274
+ min: number,
275
+ max: number,
276
+ ): void {
277
+ const step = geo.plotW / spec.labels.length;
278
+ const width = step * 0.7;
279
+ // Indexed by the same `i` it was built from, so every read is a hit; cast
280
+ // rather than defaulting, which would add a branch nothing can reach.
281
+ const running = spec.labels.map(() => 0);
282
+ spec.series.forEach((series, s) => {
283
+ series.points.forEach((value, i) => {
284
+ // `?? 0` rather than a cast: `renderChart` is exported, so a caller can
285
+ // hand it a series carrying more points than there are labels, which
286
+ // `chartSpecFrom` would have refused. The cast that used to be here
287
+ // claimed that could not happen and wrote `y="NaN"` into the DOM when it
288
+ // did.
289
+ const from = running[i] ?? 0;
290
+ const to = from + value;
291
+ running[i] = to;
292
+ const y = scaleY(to, min, max, geo);
293
+ svg.appendChild(
294
+ el("rect", {
295
+ x: PAD.left + step * i + step * 0.15,
296
+ y,
297
+ width,
298
+ height: Math.max(1, scaleY(from, min, max, geo) - y),
299
+ fill: seriesColor(s),
300
+ }),
301
+ );
302
+ });
303
+ });
304
+ }
305
+
306
+ function drawLines(
307
+ svg: SVGSVGElement,
308
+ spec: ChartSpec,
309
+ geo: Geometry,
310
+ min: number,
311
+ max: number,
312
+ ): void {
313
+ spec.series.forEach((series, s) => {
314
+ const points = series.points
315
+ .map(
316
+ (value, i) => `${bandCentre(i, spec.labels.length, geo)},${scaleY(value, min, max, geo)}`,
317
+ )
318
+ .join(" ");
319
+ svg.appendChild(
320
+ el("polyline", {
321
+ points,
322
+ fill: "none",
323
+ stroke: seriesColor(s),
324
+ "stroke-width": 2,
325
+ "stroke-linejoin": "round",
326
+ }),
327
+ );
328
+ });
329
+ }
330
+
331
+ function drawScatter(
332
+ svg: SVGSVGElement,
333
+ spec: ChartSpec,
334
+ geo: Geometry,
335
+ min: number,
336
+ max: number,
337
+ ): void {
338
+ spec.series.forEach((series, s) => {
339
+ series.points.forEach((value, i) => {
340
+ svg.appendChild(
341
+ el("circle", {
342
+ cx: bandCentre(i, spec.labels.length, geo),
343
+ cy: scaleY(value, min, max, geo),
344
+ r: 4,
345
+ fill: seriesColor(s),
346
+ "fill-opacity": 0.85,
347
+ }),
348
+ );
349
+ });
350
+ });
351
+ }
352
+
353
+ /**
354
+ * Pie draws the **first** series' points as shares of their own total, one
355
+ * wedge per label -- the only kind whose slices are the labels rather than the
356
+ * series, so a second series has nowhere to go and is ignored rather than
357
+ * silently summed into the first.
358
+ */
359
+ function drawPie(svg: SVGSVGElement, points: readonly number[], geo: Geometry): void {
360
+ const total = points.reduce((sum, value) => sum + value, 0);
361
+ const cx = geo.width / 2;
362
+ const cy = PAD.top + geo.plotH / 2;
363
+ const r = Math.min(geo.plotW, geo.plotH) / 2;
364
+ if (total === 0) {
365
+ // Every share is zero, so there is no wedge to draw and a full circle would
366
+ // claim one slice owns everything. An outline says "nothing here" honestly.
367
+ svg.appendChild(
368
+ el("circle", { cx, cy, r, fill: "none", stroke: "currentColor", "stroke-opacity": 0.3 }),
369
+ );
370
+ return;
371
+ }
372
+ let angle = -Math.PI / 2;
373
+ points.forEach((value, i) => {
374
+ const sweep = (value / total) * Math.PI * 2;
375
+ const end = angle + sweep;
376
+ // A wedge of the whole circle cannot be drawn as one arc (start and end
377
+ // coincide, so the path collapses); draw it as a plain circle instead.
378
+ if (sweep >= Math.PI * 2) {
379
+ svg.appendChild(el("circle", { cx, cy, r, fill: seriesColor(i) }));
380
+ } else {
381
+ const x1 = cx + r * Math.cos(angle);
382
+ const y1 = cy + r * Math.sin(angle);
383
+ const x2 = cx + r * Math.cos(end);
384
+ const y2 = cy + r * Math.sin(end);
385
+ const large = sweep > Math.PI ? 1 : 0;
386
+ svg.appendChild(
387
+ el("path", {
388
+ d: `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} Z`,
389
+ fill: seriesColor(i),
390
+ }),
391
+ );
392
+ }
393
+ angle = end;
394
+ });
395
+ }
396
+
397
+ /** The whole drawing for one spec at one width. */
398
+ function drawSvg(spec: ChartSpec, geo: Geometry): SVGSVGElement {
399
+ const svg = el("svg", {
400
+ viewBox: `0 0 ${geo.width} ${geo.height}`,
401
+ width: "100%",
402
+ role: "img",
403
+ });
404
+ svg.setAttribute("aria-label", spec.title ?? `${spec.kind} chart`);
405
+
406
+ if (spec.kind === "pie") {
407
+ // `series[0]` is guaranteed by renderChart's early return; a pie's slices
408
+ // are its labels, so a second series has nowhere to go and is ignored
409
+ // rather than silently summed into the first. Negative shares are floored,
410
+ // since a wedge cannot sweep backwards.
411
+ const first = spec.series[0] as ChartSeries;
412
+ drawPie(
413
+ svg,
414
+ first.points.map((value) => Math.max(0, value)),
415
+ geo,
416
+ );
417
+ return svg;
418
+ }
419
+ const { min, max } = extent(spec);
420
+ drawAxes(svg, spec, geo, min, max);
421
+ if (spec.kind === "bar") {
422
+ drawBars(svg, spec, geo, min, max);
423
+ } else if (spec.kind === "stacked") {
424
+ drawStacked(svg, spec, geo, min, max);
425
+ } else if (spec.kind === "line") {
426
+ drawLines(svg, spec, geo, min, max);
427
+ } else {
428
+ drawScatter(svg, spec, geo, min, max);
429
+ }
430
+ return svg;
431
+ }
432
+
433
+ function buildLegend(entries: readonly string[]): HTMLDivElement | null {
434
+ if (entries.length < 2) {
435
+ return null;
436
+ }
437
+ const row = document.createElement("div");
438
+ row.className = "chart-legend";
439
+ row.setAttribute("part", "chart-legend");
440
+ entries.forEach((label, i) => {
441
+ const item = document.createElement("span");
442
+ item.className = "chart-legend-item";
443
+ const swatch = document.createElement("span");
444
+ swatch.className = "chart-legend-swatch";
445
+ swatch.style.background = seriesColor(i);
446
+ item.append(swatch, document.createTextNode(label));
447
+ row.appendChild(item);
448
+ });
449
+ return row;
450
+ }
451
+
452
+ /**
453
+ * Redraw `block`'s chart whenever the width it has to fill changes.
454
+ *
455
+ * Nothing disconnects this, and nothing needs to: the observer is referenced
456
+ * only by the closure that made it, and an active observer holds its target
457
+ * rather than the other way round -- so a chart removed from the transcript
458
+ * takes its observer with it.
459
+ *
460
+ * The block's own width is read rather than the entry's box, because that is
461
+ * the number the redraw has to match and the entry carries several.
462
+ */
463
+ function fitToWidth(block: HTMLElement, redraw: (width: number) => void): void {
464
+ const observer = new ResizeObserver(() => {
465
+ redraw(Math.round(block.clientWidth / WIDTH_STEP) * WIDTH_STEP);
466
+ });
467
+ observer.observe(block);
468
+ }
469
+
470
+ /**
471
+ * Render one spec as a self-contained block, or `null` when it says nothing.
472
+ *
473
+ * A spec with no labels or no series is not drawn: an empty frame reads as
474
+ * "there is no data" when the truth is "the caller sent nothing", and the two
475
+ * deserve different answers.
476
+ *
477
+ * The block returned is already drawn at {@link DEFAULT_WIDTH} and redraws
478
+ * itself once it is in a document and knows how wide it really is, so a caller
479
+ * appends it exactly as before and never has to say how big it should be.
480
+ */
481
+ export function renderChart(spec: ChartSpec): HTMLDivElement | null {
482
+ if (spec.labels.length === 0 || spec.series.length === 0) {
483
+ return null;
484
+ }
485
+ const block = document.createElement("div");
486
+ block.className = "chart-block";
487
+ block.setAttribute("part", "chart-block");
488
+
489
+ if (spec.title !== undefined && spec.title !== "") {
490
+ const heading = document.createElement("div");
491
+ heading.className = "chart-title";
492
+ heading.setAttribute("part", "chart-title");
493
+ heading.textContent = spec.title;
494
+ block.appendChild(heading);
495
+ }
496
+
497
+ let width = DEFAULT_WIDTH;
498
+ let svg = drawSvg(spec, geometryFor(width));
499
+ block.appendChild(svg);
500
+
501
+ // Pie's slices are its labels; every other kind's are its series.
502
+ const legend = buildLegend(
503
+ spec.kind === "pie" ? spec.labels : spec.series.map((series) => series.label),
504
+ );
505
+ if (legend !== null) {
506
+ block.appendChild(legend);
507
+ }
508
+
509
+ fitToWidth(block, (measured) => {
510
+ if (measured === width) {
511
+ return;
512
+ }
513
+ width = measured;
514
+ const next = drawSvg(spec, geometryFor(width));
515
+ svg.replaceWith(next);
516
+ svg = next;
517
+ });
518
+ return block;
519
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Narrow untrusted input into a {@link ChartSpec}.
3
+ *
4
+ * Both arrival routes are untrusted in the same way — a model writes one, a
5
+ * server the other — so neither is taken on shape. Kept out of the renderer
6
+ * because the renderer's job is drawing, and a value that reaches it has
7
+ * already been vouched for.
8
+ */
9
+
10
+ import type { ChartKind, ChartSpec } from "./chart_block.js";
11
+
12
+ const KINDS: readonly ChartKind[] = ["bar", "line", "pie", "scatter", "stacked"];
13
+
14
+ /**
15
+ * Most points a spec may carry, across every series.
16
+ *
17
+ * Not a taste limit. `Math.max(0, ...values)` throws `RangeError` on a large
18
+ * enough spread, and the renderer runs inside the history replay, where a throw
19
+ * abandons the replay and takes every later turn of the transcript with it —
20
+ * permanently, on every reload. A chart nobody can read is a far smaller
21
+ * problem than a conversation that silently loses its tail.
22
+ */
23
+ const MAX_POINTS = 20_000;
24
+
25
+ /**
26
+ * Whether a spec's *labels* are cheap enough to draw.
27
+ *
28
+ * `MAX_POINTS` bounds the data; this bounds the DOM. Every label produces an
29
+ * axis text node whatever the series count, so a spec well inside the point
30
+ * budget can still emit tens of thousands of nodes and block the main thread —
31
+ * again on every reload, since it is in the transcript. Kept separate because
32
+ * the two limits answer different questions and a single number cannot.
33
+ */
34
+ const MAX_LABELS = 2_000;
35
+
36
+ /**
37
+ * Largest magnitude a point may carry.
38
+ *
39
+ * `Number.isFinite` is not enough on its own: two finite extremes still give an
40
+ * infinite *range*, and `(value - min) / Infinity` is `NaN`, which reaches the
41
+ * DOM as `y="NaN"`. Bounding the values bounds the range.
42
+ */
43
+ const MAX_MAGNITUDE = 1e15;
44
+
45
+ function asKind(value: unknown): ChartKind {
46
+ // Anything unrecognised falls back to `bar` rather than refusing the spec: an
47
+ // unknown kind is a caller reaching for a chart type we do not draw, and the
48
+ // data is still worth showing.
49
+ return KINDS.includes(value as ChartKind) ? (value as ChartKind) : "bar";
50
+ }
51
+
52
+ function asNumbers(value: unknown): number[] | null {
53
+ if (!Array.isArray(value)) {
54
+ return null;
55
+ }
56
+ const out: number[] = [];
57
+ for (const item of value) {
58
+ // `Number.isFinite` rather than `typeof === "number"`: JSON encoders render
59
+ // NaN and Infinity as nulls or strings depending on the encoder, and either
60
+ // would scale into a chart with no visible extent.
61
+ if (typeof item !== "number" || !Number.isFinite(item)) {
62
+ return null;
63
+ }
64
+ if (Math.abs(item) > MAX_MAGNITUDE) {
65
+ return null;
66
+ }
67
+ out.push(item);
68
+ }
69
+ return out;
70
+ }
71
+
72
+ function asStrings(value: unknown): string[] | null {
73
+ if (!Array.isArray(value)) {
74
+ return null;
75
+ }
76
+ // `every` over an index range rather than `Array.prototype.some`, which skips
77
+ // holes: a sparse array passed the old check and drew a chart with blank axis
78
+ // labels, which reads as a rendering bug rather than bad input.
79
+ for (let i = 0; i < value.length; i += 1) {
80
+ if (typeof value[i] !== "string") {
81
+ return null;
82
+ }
83
+ }
84
+ return value as string[];
85
+ }
86
+
87
+ /** A well-formed spec, or `null` for anything that cannot be drawn honestly. */
88
+ export function chartSpecFrom(value: unknown): ChartSpec | null {
89
+ if (typeof value !== "object" || value === null) {
90
+ return null;
91
+ }
92
+ const raw = value as Record<string, unknown>;
93
+ const labels = asStrings(raw["labels"]);
94
+ if (labels === null || !Array.isArray(raw["series"])) {
95
+ return null;
96
+ }
97
+
98
+ const series: { label: string; points: number[] }[] = [];
99
+ for (const entry of raw["series"]) {
100
+ if (typeof entry !== "object" || entry === null) {
101
+ return null;
102
+ }
103
+ const item = entry as Record<string, unknown>;
104
+ const points = asNumbers(item["points"]);
105
+ // A series with a different number of points than there are labels would
106
+ // silently misalign every value after the gap. A chart that is subtly wrong
107
+ // still reads as authoritative, which is worse than no chart at all.
108
+ if (points === null || points.length !== labels.length) {
109
+ return null;
110
+ }
111
+ series.push({ label: typeof item["label"] === "string" ? item["label"] : "", points });
112
+ }
113
+ if (series.length === 0) {
114
+ return null;
115
+ }
116
+ if (series.length * labels.length > MAX_POINTS || labels.length > MAX_LABELS) {
117
+ return null;
118
+ }
119
+
120
+ const kind = asKind(raw["kind"]);
121
+ const title = raw["title"];
122
+ // The key is omitted rather than set to `undefined`: `title` is genuinely
123
+ // optional and this tsconfig distinguishes absent from present-and-undefined.
124
+ return typeof title === "string" ? { kind, title, labels, series } : { kind, labels, series };
125
+ }
@@ -0,0 +1,63 @@
1
+ // Charts drawn in the transcript: the block, its title and legend.
2
+ export const CHART_STYLES: string = `
3
+ /* Charts.
4
+ *
5
+ * The SVG scales to the column and carries no colours of its own beyond the
6
+ * series palette, so a host restyles it the same way it restyles everything
7
+ * else. Series colours are custom properties with fallbacks rather than fixed
8
+ * values, and the axis furniture inherits currentColor at low opacity so it
9
+ * reads correctly in either theme without a second palette.
10
+ */
11
+ /* A chart is sized like a message, not like a panel: it takes the width it
12
+ needs and stops, rather than stretching into whatever room the transcript
13
+ has. A message bubble caps at 80% for the same reason -- widening the panel
14
+ should not resize what is already in it. The cap is a token so a host with a
15
+ wide panel and a real reason can raise it; the default is the width this
16
+ renderer has always drawn at. Below the cap the block still fills its column,
17
+ which is what a narrow panel needs. */
18
+ .chart-block {
19
+ align-self: flex-start;
20
+ width: 100%;
21
+ max-width: var(--_chart-max-width);
22
+ margin: 6px 0;
23
+ color: var(--_fg);
24
+ }
25
+
26
+ /* The drawing fills the block's width and carries its own height in the
27
+ viewBox, so it is laid out rather than magnified: block display keeps the
28
+ inline baseline gap from adding a stripe under every chart. */
29
+ .chart-block svg {
30
+ display: block;
31
+ width: 100%;
32
+ height: auto;
33
+ }
34
+
35
+ .chart-title {
36
+ margin-bottom: 2px;
37
+ font-size: 0.85em;
38
+ font-weight: 600;
39
+ opacity: 0.85;
40
+ }
41
+
42
+ .chart-legend {
43
+ display: flex;
44
+ flex-wrap: wrap;
45
+ gap: 4px 12px;
46
+ margin-top: 4px;
47
+ font-size: 0.78em;
48
+ opacity: 0.75;
49
+ }
50
+
51
+ .chart-legend-item {
52
+ display: inline-flex;
53
+ align-items: center;
54
+ gap: 5px;
55
+ }
56
+
57
+ .chart-legend-swatch {
58
+ width: 9px;
59
+ height: 9px;
60
+ border-radius: 2px;
61
+ flex: 0 0 auto;
62
+ }
63
+ `;