@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,62 @@
1
+ import type { Message } from "@ag-ui/core";
2
+ import { metadataOrTopLevel } from "./utils.js";
3
+
4
+ /**
5
+ * A durable, lightweight reference to one uploaded file — what an upload
6
+ * returns and what rides on a sent message, never the bytes.
7
+ *
8
+ * Mirrors django-ag-ui's `AttachmentRef`: the file uploads out-of-band to the
9
+ * attachments endpoint, the server hands back this ref, and the agent reads the
10
+ * content server-side via the `read_attachment` tool.
11
+ */
12
+ export interface AttachmentRef {
13
+ /** Opaque, owner-scoped handle the server resolves back to bytes. */
14
+ readonly id: string;
15
+ /** Original filename, for display on the chip. */
16
+ readonly name: string;
17
+ /** Declared content type (a hint — the server is authoritative). */
18
+ readonly mime: string;
19
+ /** Size in bytes. */
20
+ readonly size: number;
21
+ /** Optional direct fetch URL (the owner-checked download endpoint). */
22
+ readonly url?: string;
23
+ }
24
+
25
+ /**
26
+ * The attachment refs a user message carries.
27
+ *
28
+ * `AgUiClient.send` writes them into the message's `metadata`, under
29
+ * `attachments`. That is the one place they survive the trip: `@ag-ui/client`
30
+ * 1.0 strips every key its schemas do not declare from the outgoing input, so
31
+ * refs written at the top level of the message never reach the server, while
32
+ * `metadata` is declared open by key and sent as it is. The server reads them
33
+ * from there to tell the agent which files it can read, and the default store
34
+ * round-trips them, so a restored conversation re-renders its chips.
35
+ *
36
+ * A conversation stored by an earlier release has them at the top level, so
37
+ * that is read when the metadata has none. An older server reads only the top
38
+ * level, so against one the agent is never told about a file at all.
39
+ *
40
+ * Storage is untrusted — hand-edited, truncated, or corrupted — so malformed
41
+ * entries are dropped here; a shapeless one would throw in `iconFor` and abort
42
+ * the whole history replay.
43
+ */
44
+ export function messageAttachments(message: Message): readonly AttachmentRef[] {
45
+ const refs = metadataOrTopLevel(message, "attachments");
46
+ return Array.isArray(refs) ? refs.filter(isAttachmentRef) : [];
47
+ }
48
+
49
+ /** Whether an unknown value is a structurally valid {@link AttachmentRef}. */
50
+ function isAttachmentRef(value: unknown): value is AttachmentRef {
51
+ if (typeof value !== "object" || value === null) {
52
+ return false;
53
+ }
54
+ const ref = value as Record<string, unknown>;
55
+ return (
56
+ typeof ref["id"] === "string" &&
57
+ typeof ref["name"] === "string" &&
58
+ typeof ref["mime"] === "string" &&
59
+ typeof ref["size"] === "number" &&
60
+ (ref["url"] === undefined || typeof ref["url"] === "string")
61
+ );
62
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The `<ag-ui-chat>` elements connected to this document, oldest first.
3
+ *
4
+ * The highlight ring is drawn in the host's page, outside every chat, so a
5
+ * token set on a chat never reaches it through the cascade. A free `flash()`
6
+ * still has to answer "which widget is this ring speaking for", and that is a
7
+ * question about the live elements rather than about any one of them.
8
+ *
9
+ * Module-level on purpose, and the second piece of shared mutable state the
10
+ * repository's `CLAUDE.md` records, beside the claimed storage namespaces. See
11
+ * the conditions it states, and how this one meets them, before adding a
12
+ * third.
13
+ */
14
+ const CONNECTED_CHATS = new Set<HTMLElement>();
15
+
16
+ /**
17
+ * One chat's place in the document's list of connected chats.
18
+ *
19
+ * Owned one-to-one by an `<ag-ui-chat>`, which joins on connect and leaves on
20
+ * disconnect, so the list holds exactly the elements that are in a document
21
+ * now. Typed as `HTMLElement` rather than the element's class, because the DOM
22
+ * driver reads it and must not import the element.
23
+ */
24
+ export class ChatRegistration {
25
+ readonly #chat: HTMLElement;
26
+
27
+ constructor(chat: HTMLElement) {
28
+ this.#chat = chat;
29
+ }
30
+
31
+ /**
32
+ * Join, as the most recently connected chat. An element moved in the DOM
33
+ * left on disconnect before it reconnected, so it rejoins at the end and no
34
+ * entry needs removing first.
35
+ */
36
+ join(): void {
37
+ CONNECTED_CHATS.add(this.#chat);
38
+ }
39
+
40
+ /** Leave. The previous chat, if one is still connected, becomes the latest. */
41
+ leave(): void {
42
+ CONNECTED_CHATS.delete(this.#chat);
43
+ }
44
+
45
+ /** The most recently connected chat still in the document, or `null`. */
46
+ static latest(): HTMLElement | null {
47
+ let latest: HTMLElement | null = null;
48
+ for (const chat of CONNECTED_CHATS) {
49
+ latest = chat;
50
+ }
51
+ return latest;
52
+ }
53
+ }
@@ -0,0 +1,27 @@
1
+ import type { Message } from "@ag-ui/core";
2
+
3
+ /**
4
+ * What differs between the clients one conversation builds -- its own, and one
5
+ * per checkpoint continuation. Everything else about a client comes from the
6
+ * element's single construction, so an option added for one reaches the other.
7
+ */
8
+ export interface ClientSeed {
9
+ /** Where the client's runs are sent. */
10
+ readonly endpoint: string;
11
+ /** The history the agent starts from, and sends with its first run. */
12
+ readonly initialMessages: readonly Message[];
13
+ /**
14
+ * The conversation this client's own history continues, which every save
15
+ * writes ahead of it.
16
+ *
17
+ * Empty for the conversation's own client, whose history is the whole
18
+ * conversation. A continuation's history is only the turn it adds and its
19
+ * answer -- the endpoint supplies the rest from its snapshot -- and a store
20
+ * keeps one list per thread, so a save of that history alone would replace
21
+ * the conversation with its last exchange, and not saving it lost the
22
+ * exchange on the next reload.
23
+ */
24
+ readonly follows: readonly Message[];
25
+ /** Handed the whole conversation each time the client saves it, as written. */
26
+ readonly onSaved?: (conversation: readonly Message[]) => void;
27
+ }
@@ -0,0 +1,478 @@
1
+ import { randomUUID } from "@ag-ui/client";
2
+ import type { Message } from "@ag-ui/core";
3
+ import { STORAGE_ROOT } from "../constants.js";
4
+ import { prettifyToolName } from "../ui/progress/prettify_tool_name.js";
5
+
6
+ /**
7
+ * A checkpoint recorded just before a navigating tool reloads the page.
8
+ *
9
+ * The reload destroys the in-memory run loop, so the element persists this
10
+ * marker first; on the next mount it supplies the tool's result and resumes.
11
+ */
12
+ export interface NavigationCheckpoint {
13
+ /** The tool-call id whose result must be supplied after the reload. */
14
+ readonly toolCallId: string;
15
+ }
16
+
17
+ /**
18
+ * Lightweight metadata for one conversation — the thread-drawer row shape, so
19
+ * the drawer renders without loading message bodies. `title` defaults to a
20
+ * truncation of the first user message until an explicit rename, `preview` is a
21
+ * one-line excerpt of the latest message, and `updatedAt` is epoch ms of the
22
+ * last change, which orders the list.
23
+ */
24
+ export interface ThreadMeta {
25
+ readonly threadId: string;
26
+ readonly title: string;
27
+ readonly updatedAt: number;
28
+ readonly preview: string;
29
+ /**
30
+ * Whether the thread holds an answer the user has not seen, as a server store
31
+ * knows it (from a last-read timestamp). Optional: a store that cannot tell
32
+ * leaves it out, and the element counts only what finishes in this page.
33
+ */
34
+ readonly unread?: boolean;
35
+ }
36
+
37
+ /**
38
+ * Client-side persistence seam for the conversation and a pending-navigation
39
+ * checkpoint, keyed by `thread_id`.
40
+ *
41
+ * The default {@link SessionStorageStore} keeps everything per-tab. A host may
42
+ * inject a server-backed store instead, which is why `loadMessages` and
43
+ * `listThreads` are async. The checkpoint methods stay synchronous: the marker
44
+ * is a small local hint a server store can derive from history and no-op.
45
+ *
46
+ * Thread enumeration backs the chat-history drawer; deleting a thread reuses
47
+ * {@link clear}, and "new chat" is {@link newThread} — which leaves the
48
+ * conversation it moves off of intact, for the drawer to offer back.
49
+ */
50
+ export interface ClientConversationStore {
51
+ /** The active conversation id, generated and persisted on first read. */
52
+ threadId(): string;
53
+ /**
54
+ * Start a fresh conversation, make it active, and return its id.
55
+ *
56
+ * Existing threads are left where they are: "new chat" adds one, and
57
+ * {@link clear} is the only method that takes one away.
58
+ *
59
+ * Optional: for a store without it, the caller mints the id itself and
60
+ * hands it to {@link setActiveThread}, which loses only the store's own
61
+ * record that the thread is new (see {@link isUnsent}).
62
+ */
63
+ newThread?(): string;
64
+ /** Load the persisted message history, or `null` when none exists. */
65
+ loadMessages(threadId: string): Promise<readonly Message[] | null>;
66
+ /** Persist the message history (and refresh the thread's drawer metadata). */
67
+ saveMessages(threadId: string, messages: readonly Message[]): void;
68
+ /** Load the pending-navigation checkpoint, or `null` when none is set. */
69
+ loadCheckpoint(threadId: string): NavigationCheckpoint | null;
70
+ /** Set the pending-navigation checkpoint, or clear it when given `null`. */
71
+ saveCheckpoint(threadId: string, checkpoint: NavigationCheckpoint | null): void;
72
+ /** Forget the conversation and checkpoint (a "delete thread" / "new chat"). */
73
+ clear(threadId: string): void;
74
+ /** The user's threads as drawer metadata (no message bodies), newest first. */
75
+ listThreads(): Promise<readonly ThreadMeta[]>;
76
+ /** Make `threadId` the active conversation (the drawer selecting a row). */
77
+ setActiveThread(threadId: string): void;
78
+ /** Set a thread's display title (the drawer renaming a row). */
79
+ renameThread(threadId: string, title: string): void;
80
+ /**
81
+ * Whether `threadId` was minted here and has never been saved — a thread in
82
+ * which nothing has been sent yet.
83
+ *
84
+ * Exists so a server-backed store can skip asking a server for history that
85
+ * cannot be there: the element mints an id on first mount and immediately tries
86
+ * to restore it, which answers `404` and logs one in the console on every first
87
+ * visit. Nothing is wrong, and it looks exactly like something being wrong.
88
+ *
89
+ * Optional, and deliberately narrow. A store that cannot tell omits it and the
90
+ * fetch happens as before, which is also the right answer for a store that
91
+ * holds nothing locally: "I have no messages for this id" is not the same claim
92
+ * as "this id is new", and only the store that minted the id can make the
93
+ * second one. A thread picked from the drawer was never minted here, so it is
94
+ * still fetched.
95
+ */
96
+ isUnsent?(threadId: string): boolean;
97
+ /**
98
+ * Record that the user has seen `threadId`'s answers.
99
+ *
100
+ * The element calls it when a thread with unseen answers is on screen with
101
+ * the panel expanded, and when an answer finishes there in view. A server
102
+ * store maps it to its read endpoint, and should report the thread with
103
+ * `unread: false` from {@link listThreads} afterwards. It is called inside the
104
+ * element's expand and thread-change paths, so it must not throw: a store that
105
+ * writes to a server sends the request without awaiting it and handles its own
106
+ * failure, the way a failed save is handled.
107
+ *
108
+ * Optional: a store without it still has its threads counted and cleared in
109
+ * the page; nothing is recorded beyond it.
110
+ */
111
+ markRead?(threadId: string): void;
112
+ }
113
+
114
+ const THREAD_SUFFIX = "thread";
115
+ const THREADS_SUFFIX = "threads";
116
+ const MESSAGES_SUFFIX = "messages:";
117
+ const CHECKPOINT_SUFFIX = "checkpoint:";
118
+ // Marks an id this store minted and nothing has been sent in yet. Dropped on
119
+ // the first save, so it never outlives the one question it answers.
120
+ const MINTED_SUFFIX = "minted:";
121
+
122
+ const TITLE_LIMIT = 60;
123
+ const PREVIEW_LIMIT = 100;
124
+ const DEFAULT_TITLE = "New conversation";
125
+ // A message that is one skill's name and nothing else, as a server-resolved skill sends.
126
+ const SKILL_TOKEN = /^\/([A-Za-z0-9][\w.-]*)$/;
127
+
128
+ /**
129
+ * Whether its owner has warned about a refused write yet. Each store and each
130
+ * storage scope holds one, so an origin-wide, persistent refusal (a full quota
131
+ * stays full) warns once per owner, not once per persisted turn or, on the
132
+ * resize path, per keystroke.
133
+ */
134
+ export interface WriteFailureReport {
135
+ reported: boolean;
136
+ }
137
+
138
+ /**
139
+ * `sessionStorage.setItem` that survives a store which refuses to write.
140
+ *
141
+ * `setItem` throws on an exhausted quota (a long conversation, or one turn
142
+ * carrying a large tool result) and in privacy modes that deny storage
143
+ * altogether. Every write here is a *durability* concern — surviving a reload —
144
+ * and none of them is worth an exception, because of where they are called
145
+ * from: the element persists the transcript from inside the run loop, so an
146
+ * unguarded throw escapes as a run error and tells the user the agent failed
147
+ * when nothing but the browser's storage did. On the cancel path it escapes as
148
+ * an unhandled rejection instead.
149
+ *
150
+ * So a failed write loses the reload, never the conversation on screen, and
151
+ * says so once per `report`; without one, it says so on every refusal.
152
+ * Recovery is in the user's hands already: deleting the oversized thread from
153
+ * the history drawer is a `removeItem`, which frees the quota.
154
+ */
155
+ export function writeStoredItem(
156
+ key: string,
157
+ value: string,
158
+ report: WriteFailureReport = { reported: false },
159
+ ): void {
160
+ try {
161
+ sessionStorage.setItem(key, value);
162
+ } catch {
163
+ if (report.reported) {
164
+ return;
165
+ }
166
+ report.reported = true;
167
+ console.warn(
168
+ "<ag-ui-chat>: the browser refused a sessionStorage write — the quota is " +
169
+ "full, or storage is disabled for this context. The conversation " +
170
+ "continues, but it will not survive a page reload. Deleting a long " +
171
+ "conversation from the history drawer frees the quota.",
172
+ );
173
+ }
174
+ }
175
+
176
+ /** The storage-key root for a namespace; `""` is the root of an element with nothing to key on. */
177
+ function rootFor(namespace: string): string {
178
+ return namespace === "" ? STORAGE_ROOT : `${STORAGE_ROOT}@${namespace}`;
179
+ }
180
+
181
+ /** The drawer-index entry; `titleCustom` (private) freezes a renamed title. */
182
+ interface StoredThread {
183
+ threadId: string;
184
+ title: string;
185
+ titleCustom: boolean;
186
+ preview: string;
187
+ updatedAt: number;
188
+ }
189
+
190
+ /**
191
+ * Default {@link ClientConversationStore}: per-tab `sessionStorage`.
192
+ *
193
+ * Survives full page reloads and same-tab navigation, clears on tab close.
194
+ * Tracks multiple threads per tab: the active id under one key, message history
195
+ * and checkpoint namespaced by id, and a small index feeding the drawer with no
196
+ * server involved.
197
+ *
198
+ * An optional `namespace` scopes every key to one element, so two
199
+ * `<ag-ui-chat>` instances on the same origin keep separate active-thread
200
+ * pointers and drawer indexes instead of clobbering each other. The default
201
+ * empty namespace keeps the origin-global keys.
202
+ */
203
+ export class SessionStorageStore implements ClientConversationStore {
204
+ readonly #root: string;
205
+ readonly #writeFailure: WriteFailureReport = { reported: false };
206
+
207
+ constructor(namespace = "") {
208
+ this.#root = rootFor(namespace);
209
+ }
210
+
211
+ /**
212
+ * Move every key a store owns out of `from`'s namespace and into `to`'s.
213
+ *
214
+ * `<ag-ui-chat>` adopts an element-scoped conversation into a
215
+ * principal-scoped one the first time a `user-key` arrives, which is a host
216
+ * naming the user who was already there rather than a handover.
217
+ *
218
+ * Only this store's own suffixes move — the element's `collapsed` / `size` /
219
+ * `theme` keys share the global root and are deliberately left where they
220
+ * are. A value already present at the destination wins: the destination is
221
+ * the durable record and the source is the stray this move exists to clear.
222
+ * A refused write warns once per call.
223
+ */
224
+ static adopt(from: string, to: string): void {
225
+ const fromRoot = `${rootFor(from)}:`;
226
+ const toRoot = `${rootFor(to)}:`;
227
+ const writeFailure: WriteFailureReport = { reported: false };
228
+ for (const [key, suffix] of ownedKeys(fromRoot)) {
229
+ const value = sessionStorage.getItem(key);
230
+ const destination = toRoot + suffix;
231
+ if (value !== null && sessionStorage.getItem(destination) === null) {
232
+ writeStoredItem(destination, value, writeFailure);
233
+ }
234
+ sessionStorage.removeItem(key);
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Forget everything a store holds for `namespace`.
240
+ *
241
+ * The logout primitive: `<ag-ui-chat>` calls it when its `user-key` changes,
242
+ * and a host driving its own store can call it from its own sign-out path.
243
+ * Deliberately narrow — it removes only keys under this exact namespace whose
244
+ * suffix parses as one this store writes, so it can never reach another
245
+ * element's conversation or the host's own `sessionStorage` entries.
246
+ */
247
+ static purge(namespace: string): void {
248
+ for (const [key] of ownedKeys(`${rootFor(namespace)}:`)) {
249
+ sessionStorage.removeItem(key);
250
+ }
251
+ }
252
+
253
+ threadId(): string {
254
+ return sessionStorage.getItem(this.#key(THREAD_SUFFIX)) ?? this.newThread();
255
+ }
256
+
257
+ newThread(): string {
258
+ const id = randomUUID();
259
+ this.#write(this.#key(THREAD_SUFFIX), id);
260
+ this.#write(this.#key(MINTED_SUFFIX + id), "1");
261
+ return id;
262
+ }
263
+
264
+ isUnsent(threadId: string): boolean {
265
+ return (
266
+ sessionStorage.getItem(this.#key(MINTED_SUFFIX + threadId)) !== null &&
267
+ sessionStorage.getItem(this.#key(MESSAGES_SUFFIX + threadId)) === null
268
+ );
269
+ }
270
+
271
+ loadMessages(threadId: string): Promise<readonly Message[] | null> {
272
+ return Promise.resolve(this.#readJson<Message[]>(this.#key(MESSAGES_SUFFIX + threadId)));
273
+ }
274
+
275
+ saveMessages(threadId: string, messages: readonly Message[]): void {
276
+ this.#write(this.#key(MESSAGES_SUFFIX + threadId), JSON.stringify(messages));
277
+ sessionStorage.removeItem(this.#key(MINTED_SUFFIX + threadId));
278
+ this.#touchThread(threadId, messages);
279
+ }
280
+
281
+ loadCheckpoint(threadId: string): NavigationCheckpoint | null {
282
+ return this.#readJson<NavigationCheckpoint>(this.#key(CHECKPOINT_SUFFIX + threadId));
283
+ }
284
+
285
+ saveCheckpoint(threadId: string, checkpoint: NavigationCheckpoint | null): void {
286
+ const key = this.#key(CHECKPOINT_SUFFIX + threadId);
287
+ if (checkpoint === null) {
288
+ sessionStorage.removeItem(key);
289
+ return;
290
+ }
291
+ this.#write(key, JSON.stringify(checkpoint));
292
+ }
293
+
294
+ clear(threadId: string): void {
295
+ sessionStorage.removeItem(this.#key(MESSAGES_SUFFIX + threadId));
296
+ sessionStorage.removeItem(this.#key(CHECKPOINT_SUFFIX + threadId));
297
+ sessionStorage.removeItem(this.#key(MINTED_SUFFIX + threadId));
298
+ this.#writeThreads(this.#readThreads().filter((thread) => thread.threadId !== threadId));
299
+ // Only drop the active pointer when the active thread itself is cleared, so
300
+ // the next `threadId()` mints a fresh one. Deleting another thread from the
301
+ // drawer must not disturb the conversation on screen.
302
+ if (sessionStorage.getItem(this.#key(THREAD_SUFFIX)) === threadId) {
303
+ sessionStorage.removeItem(this.#key(THREAD_SUFFIX));
304
+ }
305
+ }
306
+
307
+ listThreads(): Promise<readonly ThreadMeta[]> {
308
+ const metas = this.#readThreads()
309
+ .sort((a, b) => b.updatedAt - a.updatedAt)
310
+ .map(({ threadId, title, updatedAt, preview }) => ({ threadId, title, updatedAt, preview }));
311
+ return Promise.resolve(metas);
312
+ }
313
+
314
+ setActiveThread(threadId: string): void {
315
+ this.#write(this.#key(THREAD_SUFFIX), threadId);
316
+ }
317
+
318
+ renameThread(threadId: string, title: string): void {
319
+ const threads = this.#readThreads();
320
+ const entry = threads.find((thread) => thread.threadId === threadId);
321
+ if (entry === undefined) {
322
+ return;
323
+ }
324
+ entry.title = title;
325
+ entry.titleCustom = true;
326
+ this.#writeThreads(threads);
327
+ }
328
+
329
+ /** Add or refresh a thread's drawer metadata from its latest messages. */
330
+ #touchThread(threadId: string, messages: readonly Message[]): void {
331
+ const threads = this.#readThreads();
332
+ const entry = threads.find((thread) => thread.threadId === threadId);
333
+ const preview = derivePreview(messages);
334
+ const updatedAt = Date.now();
335
+ if (entry === undefined) {
336
+ threads.push({
337
+ threadId,
338
+ title: deriveTitle(messages),
339
+ titleCustom: false,
340
+ preview,
341
+ updatedAt,
342
+ });
343
+ } else {
344
+ entry.preview = preview;
345
+ entry.updatedAt = updatedAt;
346
+ if (!entry.titleCustom) {
347
+ entry.title = deriveTitle(messages);
348
+ }
349
+ }
350
+ this.#writeThreads(threads);
351
+ }
352
+
353
+ #readThreads(): StoredThread[] {
354
+ return this.#readJson<StoredThread[]>(this.#key(THREADS_SUFFIX)) ?? [];
355
+ }
356
+
357
+ #writeThreads(threads: readonly StoredThread[]): void {
358
+ const key = this.#key(THREADS_SUFFIX);
359
+ if (threads.length === 0) {
360
+ sessionStorage.removeItem(key);
361
+ return;
362
+ }
363
+ this.#write(key, JSON.stringify(threads));
364
+ }
365
+
366
+ #write(key: string, value: string): void {
367
+ writeStoredItem(key, value, this.#writeFailure);
368
+ }
369
+
370
+ /** This store's fully-qualified key for a suffix (namespaced when set). */
371
+ #key(suffix: string): string {
372
+ return `${this.#root}:${suffix}`;
373
+ }
374
+
375
+ /** Parse a stored JSON value, returning `null` when absent or corrupt. */
376
+ #readJson<T>(key: string): T | null {
377
+ const raw = sessionStorage.getItem(key);
378
+ if (raw === null) {
379
+ return null;
380
+ }
381
+ try {
382
+ return JSON.parse(raw) as T;
383
+ } catch {
384
+ return null;
385
+ }
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Every `sessionStorage` key under `root` that this store wrote, as
391
+ * `[key, suffix]`.
392
+ *
393
+ * Collected into an array before the caller mutates anything: `sessionStorage`
394
+ * is enumerated by index, and removing an entry mid-loop shifts the ones after
395
+ * it out from under the cursor.
396
+ *
397
+ * The suffix test is what makes {@link SessionStorageStore.purge} safe to point
398
+ * at a namespace. It matters most for the global root, which the element's own
399
+ * `collapsed` / `size` / `theme` keys share — but it also means a namespace
400
+ * whose name happens to be a prefix of another cannot reach into it, since the
401
+ * remainder would have to parse as one of these suffixes.
402
+ */
403
+ function ownedKeys(root: string): Array<readonly [string, string]> {
404
+ const found: Array<readonly [string, string]> = [];
405
+ for (let index = 0; index < sessionStorage.length; index += 1) {
406
+ const key = sessionStorage.key(index);
407
+ if (key === null || !key.startsWith(root)) {
408
+ continue;
409
+ }
410
+ const suffix = key.slice(root.length);
411
+ if (isOwnedSuffix(suffix)) {
412
+ found.push([key, suffix]);
413
+ }
414
+ }
415
+ return found;
416
+ }
417
+
418
+ /** Whether a key suffix belongs to the store (vs the element's own keys). */
419
+ function isOwnedSuffix(suffix: string): boolean {
420
+ return (
421
+ suffix === THREAD_SUFFIX ||
422
+ suffix === THREADS_SUFFIX ||
423
+ suffix.startsWith(MESSAGES_SUFFIX) ||
424
+ suffix.startsWith(CHECKPOINT_SUFFIX) ||
425
+ suffix.startsWith(MINTED_SUFFIX)
426
+ );
427
+ }
428
+
429
+ /** The stored title: {@link threadTitleFrom}, or a placeholder for a thread with no user text. */
430
+ function deriveTitle(messages: readonly Message[]): string {
431
+ const title = threadTitleFrom(messages);
432
+ return title === "" ? DEFAULT_TITLE : title;
433
+ }
434
+
435
+ /**
436
+ * A thread's title from its first user message, collapsed and truncated, or `""`
437
+ * when no user message has text.
438
+ *
439
+ * A first message that is exactly a skill's `/token` is named rather than
440
+ * quoted: `skillTitle(token)` when it knows the skill, else the token in words
441
+ * (`/summarize_draw` reads "Summarize draw").
442
+ */
443
+ export function threadTitleFrom(
444
+ messages: readonly Message[],
445
+ skillTitle: (name: string) => string | undefined = () => undefined,
446
+ ): string {
447
+ for (const message of messages) {
448
+ if (message.role === "user") {
449
+ const text = cleanText(message.content);
450
+ if (text !== "") {
451
+ const token = SKILL_TOKEN.exec(text)?.[1];
452
+ const named = token === undefined ? text : (skillTitle(token) ?? prettifyToolName(token));
453
+ return truncate(named, TITLE_LIMIT);
454
+ }
455
+ }
456
+ }
457
+ return "";
458
+ }
459
+
460
+ /** A one-line preview: the latest message with text, collapsed + truncated. */
461
+ function derivePreview(messages: readonly Message[]): string {
462
+ for (const message of [...messages].reverse()) {
463
+ const text = cleanText(message.content);
464
+ if (text !== "") {
465
+ return truncate(text, PREVIEW_LIMIT);
466
+ }
467
+ }
468
+ return "";
469
+ }
470
+
471
+ /** Whitespace-collapsed message text, or `""` for non-string content. */
472
+ function cleanText(content: unknown): string {
473
+ return typeof content === "string" ? content.replace(/\s+/g, " ").trim() : "";
474
+ }
475
+
476
+ function truncate(text: string, limit: number): string {
477
+ return text.length <= limit ? text : `${text.slice(0, limit - 1).trimEnd()}…`;
478
+ }