@artooi/agents-web-components 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +4397 -2
- package/dist/agents-web-components.bundle.js +5708 -0
- package/dist/agents-web-components.bundle.js.map +7 -0
- package/dist/bundle.d.ts +3 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/chat.d.ts +3 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +16373 -0
- package/dist/chat.js.map +7 -0
- package/dist/chunk-ARNLFGCC.js +7715 -0
- package/dist/chunk-ARNLFGCC.js.map +7 -0
- package/dist/constants.d.ts +575 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/core/activity_registration.d.ts +19 -0
- package/dist/core/activity_registration.d.ts.map +1 -0
- package/dist/core/activity_registry.d.ts +46 -0
- package/dist/core/activity_registry.d.ts.map +1 -0
- package/dist/core/activity_renderer.d.ts +20 -0
- package/dist/core/activity_renderer.d.ts.map +1 -0
- package/dist/core/ag_ui_chat.d.ts +836 -0
- package/dist/core/ag_ui_chat.d.ts.map +1 -0
- package/dist/core/agui_client.d.ts +370 -0
- package/dist/core/agui_client.d.ts.map +1 -0
- package/dist/core/attachment.d.ts +42 -0
- package/dist/core/attachment.d.ts.map +1 -0
- package/dist/core/chat_registry.d.ts +23 -0
- package/dist/core/chat_registry.d.ts.map +1 -0
- package/dist/core/client_seed.d.ts +27 -0
- package/dist/core/client_seed.d.ts.map +1 -0
- package/dist/core/conversation_store.d.ts +195 -0
- package/dist/core/conversation_store.d.ts.map +1 -0
- package/dist/core/create_http_agent.d.ts +57 -0
- package/dist/core/create_http_agent.d.ts.map +1 -0
- package/dist/core/define_chat.d.ts +13 -0
- package/dist/core/define_chat.d.ts.map +1 -0
- package/dist/core/events/attachments_detail.d.ts +9 -0
- package/dist/core/events/attachments_detail.d.ts.map +1 -0
- package/dist/core/events/bar_height_detail.d.ts +6 -0
- package/dist/core/events/bar_height_detail.d.ts.map +1 -0
- package/dist/core/events/custom_agent_detail.d.ts +8 -0
- package/dist/core/events/custom_agent_detail.d.ts.map +1 -0
- package/dist/core/events/dock_width_detail.d.ts +8 -0
- package/dist/core/events/dock_width_detail.d.ts.map +1 -0
- package/dist/core/events/feedback_detail.d.ts +28 -0
- package/dist/core/events/feedback_detail.d.ts.map +1 -0
- package/dist/core/events/invalidate_detail.d.ts +16 -0
- package/dist/core/events/invalidate_detail.d.ts.map +1 -0
- package/dist/core/events/maximize_detail.d.ts +5 -0
- package/dist/core/events/maximize_detail.d.ts.map +1 -0
- package/dist/core/events/run_finished_detail.d.ts +36 -0
- package/dist/core/events/run_finished_detail.d.ts.map +1 -0
- package/dist/core/events/state_detail.d.ts +5 -0
- package/dist/core/events/state_detail.d.ts.map +1 -0
- package/dist/core/events/submit_detail.d.ts +8 -0
- package/dist/core/events/submit_detail.d.ts.map +1 -0
- package/dist/core/events/thread_detail.d.ts +27 -0
- package/dist/core/events/thread_detail.d.ts.map +1 -0
- package/dist/core/events/thread_title_detail.d.ts +8 -0
- package/dist/core/events/thread_title_detail.d.ts.map +1 -0
- package/dist/core/events/toggle_detail.d.ts +5 -0
- package/dist/core/events/toggle_detail.d.ts.map +1 -0
- package/dist/core/events/tool_run.d.ts +11 -0
- package/dist/core/events/tool_run.d.ts.map +1 -0
- package/dist/core/events/unread_detail.d.ts +11 -0
- package/dist/core/events/unread_detail.d.ts.map +1 -0
- package/dist/core/message_role.d.ts +4 -0
- package/dist/core/message_role.d.ts.map +1 -0
- package/dist/core/read_flag.d.ts +11 -0
- package/dist/core/read_flag.d.ts.map +1 -0
- package/dist/core/read_json_attribute.d.ts +15 -0
- package/dist/core/read_json_attribute.d.ts.map +1 -0
- package/dist/core/read_max_tool_rounds.d.ts +9 -0
- package/dist/core/read_max_tool_rounds.d.ts.map +1 -0
- package/dist/core/remote_conversation_store.d.ts +71 -0
- package/dist/core/remote_conversation_store.d.ts.map +1 -0
- package/dist/core/run_handlers.d.ts +85 -0
- package/dist/core/run_handlers.d.ts.map +1 -0
- package/dist/core/run_index.d.ts +58 -0
- package/dist/core/run_index.d.ts.map +1 -0
- package/dist/core/storage_scope.d.ts +118 -0
- package/dist/core/storage_scope.d.ts.map +1 -0
- package/dist/core/tool_outcome.d.ts +27 -0
- package/dist/core/tool_outcome.d.ts.map +1 -0
- package/dist/core/transcribe_audio.d.ts +32 -0
- package/dist/core/transcribe_audio.d.ts.map +1 -0
- package/dist/core/upload_attachment.d.ts +44 -0
- package/dist/core/upload_attachment.d.ts.map +1 -0
- package/dist/core/utils.d.ts +117 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/dom/animations.d.ts +122 -0
- package/dist/dom/animations.d.ts.map +1 -0
- package/dist/dom/dom_driver.d.ts +28 -0
- package/dist/dom/dom_driver.d.ts.map +1 -0
- package/dist/dom/highlight_overlay.d.ts +39 -0
- package/dist/dom/highlight_overlay.d.ts.map +1 -0
- package/dist/dom/native_setter.d.ts +5 -0
- package/dist/dom/native_setter.d.ts.map +1 -0
- package/dist/dom/ring_color.d.ts +16 -0
- package/dist/dom/ring_color.d.ts.map +1 -0
- package/dist/dom/utils.d.ts +3 -0
- package/dist/dom/utils.d.ts.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +223 -0
- package/dist/index.js.map +7 -0
- package/dist/skills/fill_template.d.ts +16 -0
- package/dist/skills/fill_template.d.ts.map +1 -0
- package/dist/skills/parse_skills.d.ts +8 -0
- package/dist/skills/parse_skills.d.ts.map +1 -0
- package/dist/skills/skill.d.ts +33 -0
- package/dist/skills/skill.d.ts.map +1 -0
- package/dist/skills/skill_catalog.d.ts +69 -0
- package/dist/skills/skill_catalog.d.ts.map +1 -0
- package/dist/skills/skill_name_from.d.ts +12 -0
- package/dist/skills/skill_name_from.d.ts.map +1 -0
- package/dist/tools/chat_surface_tools.d.ts +77 -0
- package/dist/tools/chat_surface_tools.d.ts.map +1 -0
- package/dist/tools/client_tool_registry.d.ts +58 -0
- package/dist/tools/client_tool_registry.d.ts.map +1 -0
- package/dist/tools/is_destructive.d.ts +14 -0
- package/dist/tools/is_destructive.d.ts.map +1 -0
- package/dist/tools/is_navigates.d.ts +9 -0
- package/dist/tools/is_navigates.d.ts.map +1 -0
- package/dist/tools/page_action_tools.d.ts +30 -0
- package/dist/tools/page_action_tools.d.ts.map +1 -0
- package/dist/tools/page_map.d.ts +16 -0
- package/dist/tools/page_map.d.ts.map +1 -0
- package/dist/tools/page_state.d.ts +27 -0
- package/dist/tools/page_state.d.ts.map +1 -0
- package/dist/tools/parse_tool_catalog.d.ts +21 -0
- package/dist/tools/parse_tool_catalog.d.ts.map +1 -0
- package/dist/tools/route_map.d.ts +37 -0
- package/dist/tools/route_map.d.ts.map +1 -0
- package/dist/tools/tool_catalog.d.ts +86 -0
- package/dist/tools/tool_catalog.d.ts.map +1 -0
- package/dist/tools/tool_dispatch.d.ts +82 -0
- package/dist/tools/tool_dispatch.d.ts.map +1 -0
- package/dist/ui/charts/chart_block.d.ts +57 -0
- package/dist/ui/charts/chart_block.d.ts.map +1 -0
- package/dist/ui/charts/chart_spec_from.d.ts +12 -0
- package/dist/ui/charts/chart_spec_from.d.ts.map +1 -0
- package/dist/ui/charts/chart_styles.d.ts +2 -0
- package/dist/ui/charts/chart_styles.d.ts.map +1 -0
- package/dist/ui/charts/chart_tool.d.ts +15 -0
- package/dist/ui/charts/chart_tool.d.ts.map +1 -0
- package/dist/ui/composer/attachment_styles.d.ts +2 -0
- package/dist/ui/composer/attachment_styles.d.ts.map +1 -0
- package/dist/ui/composer/attachment_tray.d.ts +53 -0
- package/dist/ui/composer/attachment_tray.d.ts.map +1 -0
- package/dist/ui/composer/auto_grow.d.ts +10 -0
- package/dist/ui/composer/auto_grow.d.ts.map +1 -0
- package/dist/ui/composer/build_composer.d.ts +32 -0
- package/dist/ui/composer/build_composer.d.ts.map +1 -0
- package/dist/ui/composer/composer_attachments.d.ts +57 -0
- package/dist/ui/composer/composer_attachments.d.ts.map +1 -0
- package/dist/ui/composer/composer_styles.d.ts +2 -0
- package/dist/ui/composer/composer_styles.d.ts.map +1 -0
- package/dist/ui/composer/composer_voice.d.ts +48 -0
- package/dist/ui/composer/composer_voice.d.ts.map +1 -0
- package/dist/ui/composer/skill_styles.d.ts +2 -0
- package/dist/ui/composer/skill_styles.d.ts.map +1 -0
- package/dist/ui/composer/skills_menu.d.ts +34 -0
- package/dist/ui/composer/skills_menu.d.ts.map +1 -0
- package/dist/ui/composer/voice_input.d.ts +46 -0
- package/dist/ui/composer/voice_input.d.ts.map +1 -0
- package/dist/ui/excerpts/attach_copy_buttons.d.ts +13 -0
- package/dist/ui/excerpts/attach_copy_buttons.d.ts.map +1 -0
- package/dist/ui/excerpts/copy_payload.d.ts +30 -0
- package/dist/ui/excerpts/copy_payload.d.ts.map +1 -0
- package/dist/ui/excerpts/page_quote_offer.d.ts +33 -0
- package/dist/ui/excerpts/page_quote_offer.d.ts.map +1 -0
- package/dist/ui/excerpts/place_offer.d.ts +9 -0
- package/dist/ui/excerpts/place_offer.d.ts.map +1 -0
- package/dist/ui/excerpts/quote_selection.d.ts +66 -0
- package/dist/ui/excerpts/quote_selection.d.ts.map +1 -0
- package/dist/ui/excerpts/transcript_quote_offer.d.ts +57 -0
- package/dist/ui/excerpts/transcript_quote_offer.d.ts.map +1 -0
- package/dist/ui/fill_ui_string.d.ts +32 -0
- package/dist/ui/fill_ui_string.d.ts.map +1 -0
- package/dist/ui/history/checkpoint_menu.d.ts +41 -0
- package/dist/ui/history/checkpoint_menu.d.ts.map +1 -0
- package/dist/ui/history/conversation_history.d.ts +317 -0
- package/dist/ui/history/conversation_history.d.ts.map +1 -0
- package/dist/ui/history/history_styles.d.ts +2 -0
- package/dist/ui/history/history_styles.d.ts.map +1 -0
- package/dist/ui/history/relative_time.d.ts +23 -0
- package/dist/ui/history/relative_time.d.ts.map +1 -0
- package/dist/ui/history/thread_drawer.d.ts +64 -0
- package/dist/ui/history/thread_drawer.d.ts.map +1 -0
- package/dist/ui/history/utils.d.ts +2 -0
- package/dist/ui/history/utils.d.ts.map +1 -0
- package/dist/ui/interrupts/approval_card.d.ts +64 -0
- package/dist/ui/interrupts/approval_card.d.ts.map +1 -0
- package/dist/ui/interrupts/approval_styles.d.ts +2 -0
- package/dist/ui/interrupts/approval_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/confirmation_card.d.ts +51 -0
- package/dist/ui/interrupts/confirmation_card.d.ts.map +1 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts +2 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/pending_decision.d.ts +22 -0
- package/dist/ui/interrupts/pending_decision.d.ts.map +1 -0
- package/dist/ui/interrupts/question_card.d.ts +49 -0
- package/dist/ui/interrupts/question_card.d.ts.map +1 -0
- package/dist/ui/interrupts/question_styles.d.ts +2 -0
- package/dist/ui/interrupts/question_styles.d.ts.map +1 -0
- package/dist/ui/place/place.d.ts +17 -0
- package/dist/ui/place/place.d.ts.map +1 -0
- package/dist/ui/place/place_chip.d.ts +26 -0
- package/dist/ui/place/place_chip.d.ts.map +1 -0
- package/dist/ui/place/place_from_route.d.ts +9 -0
- package/dist/ui/place/place_from_route.d.ts.map +1 -0
- package/dist/ui/place/place_styles.d.ts +2 -0
- package/dist/ui/place/place_styles.d.ts.map +1 -0
- package/dist/ui/placement/clamp_launcher.d.ts +20 -0
- package/dist/ui/placement/clamp_launcher.d.ts.map +1 -0
- package/dist/ui/placement/clamp_panel.d.ts +13 -0
- package/dist/ui/placement/clamp_panel.d.ts.map +1 -0
- package/dist/ui/placement/collapse_styles.d.ts +2 -0
- package/dist/ui/placement/collapse_styles.d.ts.map +1 -0
- package/dist/ui/placement/dock_styles.d.ts +2 -0
- package/dist/ui/placement/dock_styles.d.ts.map +1 -0
- package/dist/ui/placement/embedded_styles.d.ts +2 -0
- package/dist/ui/placement/embedded_styles.d.ts.map +1 -0
- package/dist/ui/placement/launcher_drag.d.ts +49 -0
- package/dist/ui/placement/launcher_drag.d.ts.map +1 -0
- package/dist/ui/placement/launcher_placement.d.ts +77 -0
- package/dist/ui/placement/launcher_placement.d.ts.map +1 -0
- package/dist/ui/placement/launcher_styles.d.ts +2 -0
- package/dist/ui/placement/launcher_styles.d.ts.map +1 -0
- package/dist/ui/placement/page_styles.d.ts +2 -0
- package/dist/ui/placement/page_styles.d.ts.map +1 -0
- package/dist/ui/placement/panel_drag.d.ts +40 -0
- package/dist/ui/placement/panel_drag.d.ts.map +1 -0
- package/dist/ui/placement/panel_placement.d.ts +173 -0
- package/dist/ui/placement/panel_placement.d.ts.map +1 -0
- package/dist/ui/placement/place_widget.d.ts +31 -0
- package/dist/ui/placement/place_widget.d.ts.map +1 -0
- package/dist/ui/placement/preset_styles.d.ts +2 -0
- package/dist/ui/placement/preset_styles.d.ts.map +1 -0
- package/dist/ui/placement/resize_handle.d.ts +78 -0
- package/dist/ui/placement/resize_handle.d.ts.map +1 -0
- package/dist/ui/placement/resize_styles.d.ts +2 -0
- package/dist/ui/placement/resize_styles.d.ts.map +1 -0
- package/dist/ui/placement/sidebar_styles.d.ts +2 -0
- package/dist/ui/placement/sidebar_styles.d.ts.map +1 -0
- package/dist/ui/placement/small_viewport_styles.d.ts +2 -0
- package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -0
- package/dist/ui/placement/surface_for.d.ts +93 -0
- package/dist/ui/placement/surface_for.d.ts.map +1 -0
- package/dist/ui/progress/prettify_tool_name.d.ts +11 -0
- package/dist/ui/progress/prettify_tool_name.d.ts.map +1 -0
- package/dist/ui/progress/run_announcer.d.ts +41 -0
- package/dist/ui/progress/run_announcer.d.ts.map +1 -0
- package/dist/ui/progress/run_notice.d.ts +21 -0
- package/dist/ui/progress/run_notice.d.ts.map +1 -0
- package/dist/ui/progress/run_notice_styles.d.ts +2 -0
- package/dist/ui/progress/run_notice_styles.d.ts.map +1 -0
- package/dist/ui/progress/subagent_panel.d.ts +101 -0
- package/dist/ui/progress/subagent_panel.d.ts.map +1 -0
- package/dist/ui/progress/subagent_progress.d.ts +57 -0
- package/dist/ui/progress/subagent_progress.d.ts.map +1 -0
- package/dist/ui/progress/subagent_update.d.ts +28 -0
- package/dist/ui/progress/subagent_update.d.ts.map +1 -0
- package/dist/ui/progress/thoughts_block.d.ts +57 -0
- package/dist/ui/progress/thoughts_block.d.ts.map +1 -0
- package/dist/ui/progress/thoughts_styles.d.ts +2 -0
- package/dist/ui/progress/thoughts_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_call_card.d.ts +167 -0
- package/dist/ui/progress/tool_call_card.d.ts.map +1 -0
- package/dist/ui/progress/tool_group_styles.d.ts +2 -0
- package/dist/ui/progress/tool_group_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_group.d.ts +50 -0
- package/dist/ui/progress/tool_step_group.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_styles.d.ts +2 -0
- package/dist/ui/progress/tool_step_styles.d.ts.map +1 -0
- package/dist/ui/shell/adopt_styles.d.ts +28 -0
- package/dist/ui/shell/adopt_styles.d.ts.map +1 -0
- package/dist/ui/shell/build_header.d.ts +45 -0
- package/dist/ui/shell/build_header.d.ts.map +1 -0
- package/dist/ui/shell/build_launcher.d.ts +33 -0
- package/dist/ui/shell/build_launcher.d.ts.map +1 -0
- package/dist/ui/shell/collapse_glyph.d.ts +14 -0
- package/dist/ui/shell/collapse_glyph.d.ts.map +1 -0
- package/dist/ui/shell/frame_styles.d.ts +2 -0
- package/dist/ui/shell/frame_styles.d.ts.map +1 -0
- package/dist/ui/shell/glyph_slot.d.ts +7 -0
- package/dist/ui/shell/glyph_slot.d.ts.map +1 -0
- package/dist/ui/shell/header_button.d.ts +11 -0
- package/dist/ui/shell/header_button.d.ts.map +1 -0
- package/dist/ui/shell/icon_element.d.ts +12 -0
- package/dist/ui/shell/icon_element.d.ts.map +1 -0
- package/dist/ui/shell/is_unread_badge_enabled.d.ts +10 -0
- package/dist/ui/shell/is_unread_badge_enabled.d.ts.map +1 -0
- package/dist/ui/shell/read_launcher_icon_url.d.ts +8 -0
- package/dist/ui/shell/read_launcher_icon_url.d.ts.map +1 -0
- package/dist/ui/shell/theme_styles.d.ts +2 -0
- package/dist/ui/shell/theme_styles.d.ts.map +1 -0
- package/dist/ui/shell/token_styles.d.ts +2 -0
- package/dist/ui/shell/token_styles.d.ts.map +1 -0
- package/dist/ui/styles.d.ts +2 -0
- package/dist/ui/styles.d.ts.map +1 -0
- package/dist/ui/themes/classic_styles.d.ts +2 -0
- package/dist/ui/themes/classic_styles.d.ts.map +1 -0
- package/dist/ui/themes/classic_tokens.d.ts +2 -0
- package/dist/ui/themes/classic_tokens.d.ts.map +1 -0
- package/dist/ui/themes/code_tokens.d.ts +2 -0
- package/dist/ui/themes/code_tokens.d.ts.map +1 -0
- package/dist/ui/themes/ledger_styles.d.ts +2 -0
- package/dist/ui/themes/ledger_styles.d.ts.map +1 -0
- package/dist/ui/themes/ledger_tokens.d.ts +2 -0
- package/dist/ui/themes/ledger_tokens.d.ts.map +1 -0
- package/dist/ui/themes/modern_styles.d.ts +2 -0
- package/dist/ui/themes/modern_styles.d.ts.map +1 -0
- package/dist/ui/themes/quiet_styles.d.ts +2 -0
- package/dist/ui/themes/quiet_styles.d.ts.map +1 -0
- package/dist/ui/themes/scheme_styles.d.ts +2 -0
- package/dist/ui/themes/scheme_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_styles.d.ts +2 -0
- package/dist/ui/themes/soft_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_tokens.d.ts +2 -0
- package/dist/ui/themes/soft_tokens.d.ts.map +1 -0
- package/dist/ui/themes/theme_hosts.d.ts +15 -0
- package/dist/ui/themes/theme_hosts.d.ts.map +1 -0
- package/dist/ui/transcript/answer_actions.d.ts +50 -0
- package/dist/ui/transcript/answer_actions.d.ts.map +1 -0
- package/dist/ui/transcript/answer_stream.d.ts +56 -0
- package/dist/ui/transcript/answer_stream.d.ts.map +1 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts +2 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts.map +1 -0
- package/dist/ui/transcript/attachment_chips.d.ts +21 -0
- package/dist/ui/transcript/attachment_chips.d.ts.map +1 -0
- package/dist/ui/transcript/build_transcript.d.ts +21 -0
- package/dist/ui/transcript/build_transcript.d.ts.map +1 -0
- package/dist/ui/transcript/greeting_styles.d.ts +2 -0
- package/dist/ui/transcript/greeting_styles.d.ts.map +1 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts +13 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts.map +1 -0
- package/dist/ui/transcript/message_action_styles.d.ts +2 -0
- package/dist/ui/transcript/message_action_styles.d.ts.map +1 -0
- package/dist/ui/transcript/message_actions.d.ts +74 -0
- package/dist/ui/transcript/message_actions.d.ts.map +1 -0
- package/dist/ui/transcript/message_styles.d.ts +2 -0
- package/dist/ui/transcript/message_styles.d.ts.map +1 -0
- package/dist/ui/transcript/render_markdown.d.ts +40 -0
- package/dist/ui/transcript/render_markdown.d.ts.map +1 -0
- package/dist/ui/transcript/render_or_warn.d.ts +16 -0
- package/dist/ui/transcript/render_or_warn.d.ts.map +1 -0
- package/dist/ui/transcript/reveal_words.d.ts +8 -0
- package/dist/ui/transcript/reveal_words.d.ts.map +1 -0
- package/dist/ui/transcript/starter_chips.d.ts +21 -0
- package/dist/ui/transcript/starter_chips.d.ts.map +1 -0
- package/dist/ui/transcript/stick_to_bottom.d.ts +55 -0
- package/dist/ui/transcript/stick_to_bottom.d.ts.map +1 -0
- package/dist/ui/transcript/suggestion_chips.d.ts +29 -0
- package/dist/ui/transcript/suggestion_chips.d.ts.map +1 -0
- package/dist/ui/transcript/transcript.d.ts +196 -0
- package/dist/ui/transcript/transcript.d.ts.map +1 -0
- package/dist/ui/transcript/transcript_styles.d.ts +2 -0
- package/dist/ui/transcript/transcript_styles.d.ts.map +1 -0
- package/dist/ui/ui_strings.d.ts +352 -0
- package/dist/ui/ui_strings.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +86 -3
- package/src/bundle.ts +2 -0
- package/src/chat.ts +2 -0
- package/src/constants.ts +650 -0
- package/src/core/activity_registration.ts +19 -0
- package/src/core/activity_registry.ts +133 -0
- package/src/core/activity_renderer.ts +19 -0
- package/src/core/ag_ui_chat.ts +3966 -0
- package/src/core/agui_client.ts +1028 -0
- package/src/core/attachment.ts +62 -0
- package/src/core/chat_registry.ts +53 -0
- package/src/core/client_seed.ts +27 -0
- package/src/core/conversation_store.ts +478 -0
- package/src/core/create_http_agent.ts +97 -0
- package/src/core/define_chat.ts +25 -0
- package/src/core/events/attachments_detail.ts +9 -0
- package/src/core/events/bar_height_detail.ts +5 -0
- package/src/core/events/custom_agent_detail.ts +7 -0
- package/src/core/events/dock_width_detail.ts +7 -0
- package/src/core/events/feedback_detail.ts +27 -0
- package/src/core/events/invalidate_detail.ts +15 -0
- package/src/core/events/maximize_detail.ts +4 -0
- package/src/core/events/run_finished_detail.ts +36 -0
- package/src/core/events/state_detail.ts +4 -0
- package/src/core/events/submit_detail.ts +8 -0
- package/src/core/events/thread_detail.ts +26 -0
- package/src/core/events/thread_title_detail.ts +7 -0
- package/src/core/events/toggle_detail.ts +4 -0
- package/src/core/events/tool_run.ts +10 -0
- package/src/core/events/unread_detail.ts +10 -0
- package/src/core/message_role.ts +4 -0
- package/src/core/read_flag.ts +13 -0
- package/src/core/read_json_attribute.ts +30 -0
- package/src/core/read_max_tool_rounds.ts +13 -0
- package/src/core/remote_conversation_store.ts +279 -0
- package/src/core/run_handlers.ts +524 -0
- package/src/core/run_index.ts +114 -0
- package/src/core/storage_scope.ts +291 -0
- package/src/core/tool_outcome.ts +39 -0
- package/src/core/transcribe_audio.ts +76 -0
- package/src/core/upload_attachment.ts +130 -0
- package/src/core/utils.ts +230 -0
- package/src/dom/animations.ts +341 -0
- package/src/dom/dom_driver.ts +91 -0
- package/src/dom/highlight_overlay.ts +204 -0
- package/src/dom/native_setter.ts +40 -0
- package/src/dom/ring_color.ts +206 -0
- package/src/dom/utils.ts +5 -0
- package/src/index.ts +220 -0
- package/src/skills/fill_template.ts +31 -0
- package/src/skills/parse_skills.ts +31 -0
- package/src/skills/skill.ts +32 -0
- package/src/skills/skill_catalog.ts +172 -0
- package/src/skills/skill_name_from.ts +19 -0
- package/src/tools/chat_surface_tools.ts +183 -0
- package/src/tools/client_tool_registry.ts +80 -0
- package/src/tools/is_destructive.ts +17 -0
- package/src/tools/is_navigates.ts +12 -0
- package/src/tools/page_action_tools.ts +123 -0
- package/src/tools/page_map.ts +26 -0
- package/src/tools/page_state.ts +57 -0
- package/src/tools/parse_tool_catalog.ts +41 -0
- package/src/tools/route_map.ts +132 -0
- package/src/tools/tool_catalog.ts +334 -0
- package/src/tools/tool_dispatch.ts +453 -0
- package/src/ui/charts/chart_block.ts +519 -0
- package/src/ui/charts/chart_spec_from.ts +125 -0
- package/src/ui/charts/chart_styles.ts +63 -0
- package/src/ui/charts/chart_tool.ts +72 -0
- package/src/ui/composer/attachment_styles.ts +71 -0
- package/src/ui/composer/attachment_tray.ts +295 -0
- package/src/ui/composer/auto_grow.ts +12 -0
- package/src/ui/composer/build_composer.ts +114 -0
- package/src/ui/composer/composer_attachments.ts +324 -0
- package/src/ui/composer/composer_styles.ts +177 -0
- package/src/ui/composer/composer_voice.ts +93 -0
- package/src/ui/composer/skill_styles.ts +120 -0
- package/src/ui/composer/skills_menu.ts +188 -0
- package/src/ui/composer/voice_input.ts +282 -0
- package/src/ui/excerpts/attach_copy_buttons.ts +73 -0
- package/src/ui/excerpts/copy_payload.ts +156 -0
- package/src/ui/excerpts/page_quote_offer.ts +203 -0
- package/src/ui/excerpts/place_offer.ts +24 -0
- package/src/ui/excerpts/quote_selection.ts +345 -0
- package/src/ui/excerpts/transcript_quote_offer.ts +175 -0
- package/src/ui/fill_ui_string.ts +41 -0
- package/src/ui/history/checkpoint_menu.ts +300 -0
- package/src/ui/history/conversation_history.ts +1169 -0
- package/src/ui/history/history_styles.ts +492 -0
- package/src/ui/history/relative_time.ts +50 -0
- package/src/ui/history/thread_drawer.ts +471 -0
- package/src/ui/history/utils.ts +11 -0
- package/src/ui/interrupts/approval_card.ts +202 -0
- package/src/ui/interrupts/approval_styles.ts +52 -0
- package/src/ui/interrupts/confirmation_card.ts +138 -0
- package/src/ui/interrupts/confirmation_styles.ts +114 -0
- package/src/ui/interrupts/pending_decision.ts +33 -0
- package/src/ui/interrupts/question_card.ts +213 -0
- package/src/ui/interrupts/question_styles.ts +73 -0
- package/src/ui/place/place.ts +16 -0
- package/src/ui/place/place_chip.ts +146 -0
- package/src/ui/place/place_from_route.ts +27 -0
- package/src/ui/place/place_styles.ts +108 -0
- package/src/ui/placement/clamp_launcher.ts +38 -0
- package/src/ui/placement/clamp_panel.ts +30 -0
- package/src/ui/placement/collapse_styles.ts +472 -0
- package/src/ui/placement/dock_styles.ts +116 -0
- package/src/ui/placement/embedded_styles.ts +14 -0
- package/src/ui/placement/launcher_drag.ts +206 -0
- package/src/ui/placement/launcher_placement.ts +133 -0
- package/src/ui/placement/launcher_styles.ts +189 -0
- package/src/ui/placement/page_styles.ts +47 -0
- package/src/ui/placement/panel_drag.ts +138 -0
- package/src/ui/placement/panel_placement.ts +1975 -0
- package/src/ui/placement/place_widget.ts +64 -0
- package/src/ui/placement/preset_styles.ts +49 -0
- package/src/ui/placement/resize_handle.ts +229 -0
- package/src/ui/placement/resize_styles.ts +201 -0
- package/src/ui/placement/sidebar_styles.ts +113 -0
- package/src/ui/placement/small_viewport_styles.ts +70 -0
- package/src/ui/placement/surface_for.ts +183 -0
- package/src/ui/progress/prettify_tool_name.ts +16 -0
- package/src/ui/progress/run_announcer.ts +67 -0
- package/src/ui/progress/run_notice.ts +61 -0
- package/src/ui/progress/run_notice_styles.ts +52 -0
- package/src/ui/progress/subagent_panel.ts +227 -0
- package/src/ui/progress/subagent_progress.ts +200 -0
- package/src/ui/progress/subagent_update.ts +89 -0
- package/src/ui/progress/thoughts_block.ts +165 -0
- package/src/ui/progress/thoughts_styles.ts +74 -0
- package/src/ui/progress/tool_call_card.ts +429 -0
- package/src/ui/progress/tool_group_styles.ts +313 -0
- package/src/ui/progress/tool_step_group.ts +317 -0
- package/src/ui/progress/tool_step_styles.ts +486 -0
- package/src/ui/shell/adopt_styles.ts +34 -0
- package/src/ui/shell/build_header.ts +121 -0
- package/src/ui/shell/build_launcher.ts +79 -0
- package/src/ui/shell/collapse_glyph.ts +42 -0
- package/src/ui/shell/frame_styles.ts +147 -0
- package/src/ui/shell/glyph_slot.ts +12 -0
- package/src/ui/shell/header_button.ts +22 -0
- package/src/ui/shell/icon_element.ts +33 -0
- package/src/ui/shell/is_unread_badge_enabled.ts +11 -0
- package/src/ui/shell/read_launcher_icon_url.ts +9 -0
- package/src/ui/shell/theme_styles.ts +11 -0
- package/src/ui/shell/token_styles.ts +480 -0
- package/src/ui/styles.ts +110 -0
- package/src/ui/themes/classic_styles.ts +32 -0
- package/src/ui/themes/classic_tokens.ts +51 -0
- package/src/ui/themes/code_tokens.ts +21 -0
- package/src/ui/themes/ledger_styles.ts +169 -0
- package/src/ui/themes/ledger_tokens.ts +33 -0
- package/src/ui/themes/modern_styles.ts +80 -0
- package/src/ui/themes/quiet_styles.ts +118 -0
- package/src/ui/themes/scheme_styles.ts +26 -0
- package/src/ui/themes/soft_styles.ts +149 -0
- package/src/ui/themes/soft_tokens.ts +29 -0
- package/src/ui/themes/theme_hosts.ts +14 -0
- package/src/ui/transcript/answer_actions.ts +165 -0
- package/src/ui/transcript/answer_stream.ts +123 -0
- package/src/ui/transcript/attachment_chip_styles.ts +116 -0
- package/src/ui/transcript/attachment_chips.ts +82 -0
- package/src/ui/transcript/build_transcript.ts +67 -0
- package/src/ui/transcript/greeting_styles.ts +171 -0
- package/src/ui/transcript/groups_tool_steps.ts +16 -0
- package/src/ui/transcript/message_action_styles.ts +155 -0
- package/src/ui/transcript/message_actions.ts +234 -0
- package/src/ui/transcript/message_styles.ts +262 -0
- package/src/ui/transcript/render_markdown.ts +181 -0
- package/src/ui/transcript/render_or_warn.ts +22 -0
- package/src/ui/transcript/reveal_words.ts +41 -0
- package/src/ui/transcript/starter_chips.ts +42 -0
- package/src/ui/transcript/stick_to_bottom.ts +126 -0
- package/src/ui/transcript/suggestion_chips.ts +73 -0
- package/src/ui/transcript/transcript.ts +555 -0
- package/src/ui/transcript/transcript_styles.ts +153 -0
- package/src/ui/ui_strings.ts +550 -0
- 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
|
+
}
|