@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
package/dist/chat.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/skills/fill_template.ts", "../src/skills/parse_skills.ts", "../src/skills/skill_catalog.ts", "../src/tools/tool_catalog.ts", "../src/skills/skill_name_from.ts", "../src/tools/tool_dispatch.ts", "../src/ui/composer/auto_grow.ts", "../src/ui/shell/glyph_slot.ts", "../src/ui/composer/build_composer.ts", "../src/ui/composer/attachment_tray.ts", "../src/ui/transcript/attachment_chips.ts", "../src/ui/composer/composer_attachments.ts", "../src/ui/composer/voice_input.ts", "../src/ui/composer/composer_voice.ts", "../src/ui/composer/skills_menu.ts", "../src/ui/excerpts/transcript_quote_offer.ts", "../src/ui/history/conversation_history.ts", "../src/ui/history/thread_drawer.ts", "../src/ui/interrupts/pending_decision.ts", "../src/ui/place/place_chip.ts", "../src/ui/place/place_from_route.ts", "../src/ui/placement/clamp_launcher.ts", "../src/ui/placement/clamp_panel.ts", "../src/ui/placement/launcher_drag.ts", "../src/ui/placement/place_widget.ts", "../src/ui/placement/launcher_placement.ts", "../src/ui/placement/panel_drag.ts", "../src/ui/placement/resize_handle.ts", "../src/ui/placement/surface_for.ts", "../src/ui/placement/panel_placement.ts", "../src/ui/progress/run_announcer.ts", "../src/ui/progress/run_notice.ts", "../src/ui/progress/subagent_panel.ts", "../src/ui/progress/subagent_update.ts", "../src/ui/progress/subagent_progress.ts", "../src/ui/charts/chart_styles.ts", "../src/ui/composer/attachment_styles.ts", "../src/ui/composer/composer_styles.ts", "../src/ui/composer/skill_styles.ts", "../src/ui/history/history_styles.ts", "../src/ui/interrupts/approval_styles.ts", "../src/ui/interrupts/confirmation_styles.ts", "../src/ui/interrupts/question_styles.ts", "../src/ui/place/place_styles.ts", "../src/ui/placement/collapse_styles.ts", "../src/ui/placement/dock_styles.ts", "../src/ui/placement/embedded_styles.ts", "../src/ui/placement/launcher_styles.ts", "../src/ui/placement/page_styles.ts", "../src/ui/placement/preset_styles.ts", "../src/ui/placement/resize_styles.ts", "../src/ui/placement/sidebar_styles.ts", "../src/ui/placement/small_viewport_styles.ts", "../src/ui/progress/run_notice_styles.ts", "../src/ui/progress/thoughts_styles.ts", "../src/ui/progress/tool_group_styles.ts", "../src/ui/progress/tool_step_styles.ts", "../src/ui/shell/frame_styles.ts", "../src/ui/shell/theme_styles.ts", "../src/ui/shell/token_styles.ts", "../src/ui/themes/classic_styles.ts", "../src/ui/themes/classic_tokens.ts", "../src/ui/themes/code_tokens.ts", "../src/ui/themes/ledger_styles.ts", "../src/ui/themes/ledger_tokens.ts", "../src/ui/themes/theme_hosts.ts", "../src/ui/themes/modern_styles.ts", "../src/ui/themes/quiet_styles.ts", "../src/ui/themes/scheme_styles.ts", "../src/ui/themes/soft_styles.ts", "../src/ui/themes/soft_tokens.ts", "../src/ui/transcript/attachment_chip_styles.ts", "../src/ui/transcript/greeting_styles.ts", "../src/ui/transcript/message_action_styles.ts", "../src/ui/transcript/message_styles.ts", "../src/ui/transcript/transcript_styles.ts", "../src/ui/styles.ts", "../src/ui/shell/adopt_styles.ts", "../src/ui/shell/header_button.ts", "../src/ui/shell/icon_element.ts", "../src/ui/shell/build_header.ts", "../src/ui/shell/build_launcher.ts", "../src/ui/shell/collapse_glyph.ts", "../src/ui/shell/is_unread_badge_enabled.ts", "../src/ui/shell/read_launcher_icon_url.ts", "../src/ui/excerpts/copy_payload.ts", "../src/ui/transcript/answer_actions.ts", "../src/ui/transcript/answer_stream.ts", "../src/ui/transcript/build_transcript.ts", "../src/ui/transcript/starter_chips.ts", "../src/ui/excerpts/attach_copy_buttons.ts", "../src/ui/progress/thoughts_block.ts", "../src/ui/progress/tool_step_group.ts", "../src/ui/transcript/groups_tool_steps.ts", "../src/ui/transcript/render_or_warn.ts", "../src/ui/transcript/reveal_words.ts", "../src/ui/transcript/stick_to_bottom.ts", "../src/ui/transcript/transcript.ts", "../src/core/activity_registry.ts", "../src/core/read_flag.ts", "../src/core/read_json_attribute.ts", "../src/core/read_max_tool_rounds.ts", "../src/core/run_handlers.ts", "../src/core/storage_scope.ts", "../src/core/ag_ui_chat.ts", "../src/core/define_chat.ts"],
|
|
4
|
+
"sourcesContent": ["/** Result of {@link fillTemplate}: the filled text plus any unresolved keys. */\nexport interface TemplateResult {\n /** The prompt with resolved `{placeholder}`s substituted. */\n readonly text: string;\n /** Placeholder names with no value available (deduped, in first-seen order). */\n readonly missing: readonly string[];\n}\n\nconst PLACEHOLDER_RE = /\\{([a-zA-Z_][a-zA-Z0-9_]*)\\}/g;\n\n/**\n * Substitute `{name}` placeholders in `template` from `values`.\n *\n * A placeholder whose value is missing, `null`, or an empty string is left\n * verbatim and reported in `missing`, so the caller can block the send rather\n * than dispatch a half-filled prompt.\n */\nexport function fillTemplate(template: string, values: Record<string, unknown>): TemplateResult {\n const missing: string[] = [];\n const text = template.replace(PLACEHOLDER_RE, (token, key: string) => {\n const value = values[key];\n if (value === undefined || value === null || value === \"\") {\n if (!missing.includes(key)) {\n missing.push(key);\n }\n return token;\n }\n return String(value);\n });\n return { text, missing };\n}\n", "import type { Skill } from \"./skill.js\";\n\n/**\n * Whether `value` has the required string fields of a {@link Skill}.\n *\n * `prompt` must stay optional: a server-resolved skill omits it, and requiring\n * it would silently drop exactly the skills kept off the client.\n */\nfunction isSkill(value: unknown): value is Skill {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const record = value as Record<string, unknown>;\n return (\n typeof record[\"name\"] === \"string\" &&\n typeof record[\"title\"] === \"string\" &&\n (record[\"prompt\"] === undefined || typeof record[\"prompt\"] === \"string\")\n );\n}\n\n/**\n * Parse an untrusted value (parsed JSON from `data-skills` or a skills\n * endpoint) into a list of {@link Skill}s, dropping anything malformed. Never\n * throws \u2014 a bad payload yields an empty list.\n */\nexport function parseSkills(value: unknown): Skill[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter(isSkill);\n}\n", "import type { SkillsMenu } from \"../ui/composer/skills_menu.js\";\nimport { fillUiString } from \"../ui/fill_ui_string.js\";\nimport type { UiStrings } from \"../ui/ui_strings.js\";\nimport { fillTemplate } from \"./fill_template.js\";\nimport { parseSkills } from \"./parse_skills.js\";\nimport type { Skill } from \"./skill.js\";\n\n/** What the skill catalog needs from the element that owns it. */\nexport interface SkillCatalogHost {\n /** The custom element, whose `data-skills-url` names the backend catalog. */\n readonly element: HTMLElement;\n /** The chips row and the slash palette the merged catalog is shown in. */\n readonly menu: SkillsMenu;\n /** The composer a picked skill's prompt is written into. */\n readonly input: HTMLTextAreaElement;\n /** The hint above the composer, saying what a skill still needs. */\n readonly hint: HTMLElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** The host's `skillContext`, read at the moment of the pick. */\n readonly context: () => Record<string, unknown>;\n /** Read an opt-in flag attribute. */\n readonly flag: (name: string) => boolean;\n /** Parse a JSON-valued attribute, warning when it will not parse. */\n readonly readJsonAttribute: (name: string) => unknown;\n /** The fetch options every request the element makes carries. */\n readonly fetchInit: (url: string) => RequestInit | undefined;\n /** The element's public `sendMessage`. */\n readonly send: (content: string) => void;\n /** Send whatever the composer holds, as the Send button does. */\n readonly submit: () => void;\n /** Resize the composer to what it now holds. */\n readonly autoGrow: () => void;\n}\n\n/**\n * The element's skills: the three catalogs a skill can come from, merged into\n * the chips and the slash palette, and what picking one does to the composer.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class SkillCatalog {\n readonly #host: SkillCatalogHost;\n // Skill catalog by source; merged backend \u2192 embed \u2192 client (later wins).\n #backendSkills: readonly Skill[] = [];\n #embedSkills: readonly Skill[] = [];\n #clientSkills: readonly Skill[] = [];\n readonly #merged = new Map<string, Skill>();\n\n constructor(host: SkillCatalogHost) {\n this.#host = host;\n }\n\n /** The replacement behind `AgUiChat.setSkills`, whose doc is the contract. */\n setClientSkills(skills: readonly Skill[]): void {\n this.#clientSkills = skills;\n this.#recompute();\n }\n\n /**\n * Wire the skill surfaces: opt-in flags and the embedded catalog. The backend\n * catalog is fetched from the element's startup, a microtask later, so it\n * carries the host's transport configuration.\n */\n init(): void {\n this.#host.menu.enableChips(this.#host.flag(\"data-prompt-chips\"));\n this.#host.menu.enableSlash(this.#host.flag(\"data-slash-commands\"));\n this.#embedSkills = this.#readEmbedded();\n this.#recompute();\n }\n\n /** Fetch the backend skills catalog from `data-skills-url`, if set. */\n async fetch(): Promise<void> {\n const url = this.#host.element.getAttribute(\"data-skills-url\");\n if (url === null) {\n return;\n }\n try {\n const response = await fetch(url, this.#host.fetchInit(url));\n this.#backendSkills = parseSkills(await response.json());\n this.#recompute();\n } catch {\n // Network/parse failure: skills just stay as the embedded/client set.\n }\n }\n\n /**\n * Act on a picked skill.\n *\n * A skill with no `prompt` is server-resolved: picking it sends the bare\n * `/name` token for the agent to expand, so the wording never reaches the\n * browser. Prefer that shape \u2014 a skill often states a project's internal\n * workflow most plainly, and a catalog endpoint is a plain GET.\n *\n * A skill carrying a `prompt` has the client fill its `{placeholder}`s from\n * the page instead, which is right for placeholders only the page can supply.\n *\n * Either way a pick sends; `sendImmediately: false` opts into pre-filling the\n * composer instead.\n */\n apply(skill: Skill): void {\n const { input, hint } = this.#host;\n if (skill.prompt === undefined) {\n hint.hidden = true;\n this.#host.send(`/${skill.name}`);\n return;\n }\n const { text, missing } = fillTemplate(skill.prompt, this.#host.context());\n if (missing.length > 0) {\n // Hand the user something to work with rather than only a refusal. The\n // partially-filled template goes into the composer with its unresolved\n // `{placeholder}`s intact and the first one selected, so the next\n // keystroke replaces it. A hint alone would leave what the user typed to\n // open the palette (a lone \"/\") sitting there, saying nothing about what\n // the skill wanted or how to give it.\n hint.textContent = fillUiString(this.#host.strings().skillNeeds, {\n title: skill.title,\n fields: missing.join(\", \"),\n });\n hint.hidden = false;\n input.value = text;\n this.#host.autoGrow();\n input.focus();\n this.#selectFirstPlaceholder(text);\n return;\n }\n hint.hidden = true;\n input.value = text;\n this.#host.autoGrow();\n if (skill.sendImmediately === false) {\n input.focus();\n return;\n }\n this.#host.submit();\n }\n\n /** Parse the inline `data-skills` JSON catalog (empty when absent/malformed). */\n #readEmbedded(): readonly Skill[] {\n // `parseSkills` drops anything that is not a well-formed skill, `null`\n // included, so the absent and unparseable cases need no branch here.\n return parseSkills(this.#host.readJsonAttribute(\"data-skills\"));\n }\n\n /** The title of the skill named `name` in the merged catalog, if it has one. */\n title(name: string): string | undefined {\n return this.#merged.get(name)?.title;\n }\n\n /** Merge the three sources (backend \u2192 embed \u2192 client; later wins by name). */\n #recompute(): void {\n this.#merged.clear();\n for (const skill of [...this.#backendSkills, ...this.#embedSkills, ...this.#clientSkills]) {\n this.#merged.set(skill.name, skill);\n }\n this.#host.menu.setSkills([...this.#merged.values()]);\n }\n\n /**\n * Put the caret on the first unresolved placeholder, selected.\n *\n * Typing then replaces it, which is the shortest path from \"this skill needs\n * a topic\" to a sendable prompt.\n */\n #selectFirstPlaceholder(text: string): void {\n // The first surviving brace *is* the first unresolved placeholder \u2014 a\n // resolved one was substituted away \u2014 so this needs no search through the\n // missing keys and no not-found branch to defend.\n const start = text.indexOf(\"{\");\n this.#host.input.setSelectionRange(start, text.indexOf(\"}\", start) + 1);\n }\n}\n", "import type { Tool } from \"@ag-ui/core\";\nimport { READ_PAGE_TOOL, X_SUMMARY_KEY } from \"../constants.js\";\nimport { commaTokens } from \"../core/utils.js\";\nimport type { PendingDecision } from \"../ui/interrupts/pending_decision.js\";\nimport {\n type QuestionRenderer,\n type QuestionRequest,\n requestQuestion,\n} from \"../ui/interrupts/question_card.js\";\nimport type { UiStrings } from \"../ui/ui_strings.js\";\nimport { type ChatSurface, createChatSurfaceTools } from \"./chat_surface_tools.js\";\nimport { type ClientTool, ClientToolRegistry } from \"./client_tool_registry.js\";\nimport { createPageActionTools, PAGE_ACTIONS } from \"./page_action_tools.js\";\nimport type { PageMap } from \"./page_map.js\";\nimport { createPageStateTools, type PageState } from \"./page_state.js\";\nimport { parseToolCatalog, type ToolCatalogEntry } from \"./parse_tool_catalog.js\";\nimport { createRouteTools, type RouteMap } from \"./route_map.js\";\n\n/** What the tool catalog needs from the element that owns it. */\nexport interface ToolCatalogHost {\n /** The custom element: its tool attributes, and the surface the chat tools drive. */\n readonly element: HTMLElement & ChatSurface;\n /** The element's `routeMap`, read per call. */\n readonly routeMap: () => RouteMap;\n /** The element's `navigate`, read per call. */\n readonly navigate: () => ((path: string) => void) | null;\n /** The element's `getPageMap`, read per call. */\n readonly getPageMap: () => (() => PageMap) | null;\n /** Whether the user withheld the place, which withholds the page with it. */\n readonly pageWithheld: () => boolean;\n /** The element's `resolvePageTarget`, called per target. */\n readonly resolvePageTarget: (target: string) => HTMLElement | null;\n /** The element's `getTools`, which a host may have replaced. */\n readonly getTools: () => Tool[];\n /** The element's `askUser` flag. */\n readonly askUser: () => boolean;\n /** The element's `askUserRenderer`. */\n readonly askUserRenderer: () => QuestionRenderer | null;\n /** The decision a run is suspended on, which a Stop abandons. */\n readonly decision: PendingDecision;\n /**\n * Mark the card of ``callId`` as asking the user, or no longer. The call id is\n * absent for a handler run outside a tool call, which has no card to mark.\n */\n readonly setAsking: (callId: string | undefined, asking: boolean) => void;\n /** The current answer group, opening one if none is open. */\n readonly ensureGroup: () => HTMLDivElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Remove the pending indicator if shown. */\n readonly hidePending: () => void;\n /** Update the empty state after the transcript changed. */\n readonly updateEmptyState: () => void;\n /** Keep the transcript at its foot, if the reader is there. */\n readonly follow: () => void;\n /** The fetch options every request the element makes carries. */\n readonly fetchInit: (url: string) => RequestInit | undefined;\n}\n\n/**\n * The frontend tools the agent is offered: the host's registered tools, the\n * built-in ones the element's configuration switches on, what the current round\n * advertised, and the server's catalog of labels for the tools it runs itself.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ToolCatalog {\n readonly #host: ToolCatalogHost;\n /** The `data-tools-url` catalog by tool name: the base layer behind `toolSummaries`, filled once on connect. */\n #toolCatalog: Record<string, ToolCatalogEntry> = {};\n /**\n * The tool names the current round handed the agent, snapshotted as the catalog went out.\n *\n * The registry is mount-wide but `getTools` is per-run, so a call naming a tool this run\n * withheld must not reach a handler that is merely still registered. Not re-asked at\n * dispatch: the provider is a function and may answer differently. Empty until the first\n * round advertises, which always precedes the calls that round produces.\n */\n #advertisedTools: ReadonlySet<string> = new Set();\n readonly #toolRegistry = new ClientToolRegistry();\n\n constructor(host: ToolCatalogHost) {\n this.#host = host;\n }\n\n /** The registration behind `AgUiChat.registerTool`, whose doc is the contract. */\n register(tool: ClientTool): void {\n this.#toolRegistry.register(tool);\n }\n\n /** The binding behind `AgUiChat.registerPageState`, whose doc is the contract. */\n registerPageState(binding: PageState): void {\n for (const tool of createPageStateTools(binding)) {\n this.#toolRegistry.register(tool);\n }\n }\n\n /** Whether a tool of this name is registered, built-ins aside. */\n has(name: string): boolean {\n return this.#toolRegistry.has(name);\n }\n\n /** The catalog behind the default `AgUiChat.getTools`, whose doc is the contract. */\n defaultTools(): Tool[] {\n return [\n ...this.#builtinTools().map((t) => ({\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n })),\n ...this.#toolRegistry.tools(),\n ];\n }\n\n /**\n * The catalog for the round about to start, remembering what it offered.\n *\n * Every path to a frontend tool goes through here first \u2014 the client asks\n * for `RunAgentInput.tools` at the top of each round \u2014 so this is the one\n * place that can know what the agent was actually told about.\n */\n advertise(): Tool[] {\n const tools = this.#host.getTools();\n this.#advertisedTools = new Set(tools.map((tool) => tool.name));\n return tools;\n }\n\n /** Whether the current round offered a tool of this name. */\n wasAdvertised(name: string): boolean {\n return this.#advertisedTools.has(name);\n }\n\n /** Resolve a tool by name: built-in tools first, then the registry. */\n resolve(name: string): ClientTool | null {\n const builtin = this.#builtinTools().find((t) => t.name === name);\n if (builtin !== undefined) {\n return builtin;\n }\n return this.#toolRegistry.has(name) ? this.#toolRegistry.get(name) : null;\n }\n\n /** The server catalog's label for a tool, if it sent one. */\n summary(name: string): string | undefined {\n return this.#toolCatalog[name]?.summary;\n }\n\n /** Fetch the server tool-label catalog from `data-tools-url`, if set. */\n async fetchCatalog(): Promise<void> {\n const url = this.#host.element.getAttribute(\"data-tools-url\");\n if (url === null) {\n return;\n }\n try {\n const response = await fetch(url, this.#host.fetchInit(url));\n this.#toolCatalog = parseToolCatalog(await response.json());\n } catch {\n // Network/parse failure: cards fall back to toolSummaries / raw names.\n }\n }\n\n /** The built-in `route.*` tools, present only when a route map is set. */\n #routeTools(): ClientTool[] {\n if (this.#host.routeMap().length === 0) {\n return [];\n }\n return createRouteTools(\n () => this.#host.routeMap(),\n () => this.#host.navigate(),\n );\n }\n\n /**\n * The built-in `read_page` tool, present only when a `getPageMap`\n * provider is set and the user has not withheld the place. A *pull* the\n * agent can call mid-turn to see the page after it has acted (the\n * auto-injected context is a send-time snapshot).\n */\n #pageTools(): ClientTool[] {\n const getPageMap = this.#host.getPageMap();\n if (getPageMap === null || this.#host.pageWithheld()) {\n return [];\n }\n return [\n {\n name: READ_PAGE_TOOL,\n description:\n \"Read the current page's structure (fields, buttons, route). Call after \" +\n \"acting to observe the result within the same turn.\",\n parameters: {\n type: \"object\",\n properties: {},\n required: [],\n [X_SUMMARY_KEY]: \"Read the page\",\n },\n handler: () => getPageMap(),\n },\n ];\n }\n\n /**\n * Opt-in page-action tools (`scroll_to` / `drag_and_drop`), enabled per token\n * via the `data-page-actions` attribute (e.g. `\"scroll,drag\"`). Targets resolve\n * through `resolvePageTarget` so a host controls the agent's interaction\n * surface; absent attribute \u21D2 no tools registered.\n */\n #pageActionTools(): ClientTool[] {\n const attr = this.#host.element.getAttribute(\"data-page-actions\");\n if (attr === null) {\n return [];\n }\n const enabled = new Set(commaTokens(attr));\n return [\n ...createPageActionTools(enabled, (target) => this.#host.resolvePageTarget(target)),\n ...(enabled.has(PAGE_ACTIONS.CHAT) ? createChatSurfaceTools(this.#host.element) : []),\n ];\n }\n\n /** All built-in (route + page + page-action + ask_user) frontend tools. */\n #builtinTools(): ClientTool[] {\n return [\n ...this.#routeTools(),\n ...this.#pageTools(),\n ...this.#pageActionTools(),\n ...this.#askUserTool(),\n ];\n }\n\n /**\n * The built-in `ask_user` frontend tool, or `[]` when `askUser` is off.\n *\n * The agent calls it, the client executes it locally through the normal\n * frontend-tool path by rendering a {@link requestQuestion} card, and the\n * answer flows back as the tool result. No new protocol.\n */\n #askUserTool(): ClientTool[] {\n if (!this.#host.askUser()) {\n return [];\n }\n return [\n {\n name: \"ask_user\",\n description:\n \"Ask the user a question and wait for their answer. Provide `options` for a \" +\n \"multiple-choice prompt; set `allow_custom` to also accept a free-text answer.\",\n parameters: {\n type: \"object\",\n properties: {\n question: { type: \"string\", description: \"The question to ask the user.\" },\n options: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Preset choices offered as radio buttons.\",\n },\n allow_custom: {\n type: \"boolean\",\n description: \"Allow a free-text answer in addition to any options.\",\n },\n },\n required: [\"question\"],\n },\n handler: (args, callId) => this.#askUser(args, callId),\n },\n ];\n }\n\n /** Render the `ask_user` question card and resolve with the user's answer. */\n async #askUser(args: Record<string, unknown>, callId: string | undefined): Promise<string> {\n const question = typeof args[\"question\"] === \"string\" ? args[\"question\"] : \"\";\n const request: QuestionRequest = { question };\n const rawOptions = args[\"options\"];\n if (Array.isArray(rawOptions)) {\n request.options = rawOptions.filter((option): option is string => typeof option === \"string\");\n }\n if (args[\"allow_custom\"] === true) {\n request.allowCustom = true;\n }\n // A Stop aborts the signal, resolving the card with an empty answer.\n const signal = this.#host.decision.open();\n this.#host.hidePending();\n const builtIn = (): Promise<string> =>\n requestQuestion(this.#host.ensureGroup(), request, {\n signal,\n strings: this.#host.strings(),\n });\n const renderer = this.#host.askUserRenderer();\n let answer: string;\n // Asking until answered, stopped or failed, so the step row does not read as running.\n this.#host.setAsking(callId, true);\n try {\n if (renderer === null) {\n answer = await builtIn();\n } else {\n // Called on the element, as `this.askUserRenderer(...)` always was.\n // Awaited here, not in a helper, to keep the microtask count of an answering renderer.\n try {\n answer = await renderer.call(this.#host.element, request, { signal });\n } catch (error) {\n answer = await this.#afterRendererFailed(error, signal, callId, builtIn);\n }\n }\n } finally {\n this.#host.setAsking(callId, false);\n }\n this.#host.decision.close();\n this.#host.updateEmptyState();\n this.#host.follow();\n return answer;\n }\n\n /**\n * Answer an `ask_user` call whose host renderer failed: the built-in card asks instead.\n *\n * A renderer is presentation, not policy, so its failure must neither reach the agent as\n * the tool result nor leave the pending decision open. A rejection after a Stop is the\n * signal working: it resolves empty and says nothing.\n */\n #afterRendererFailed(\n error: unknown,\n signal: AbortSignal,\n callId: string | undefined,\n builtIn: () => Promise<string>,\n ): Promise<string> {\n if (signal.aborted) {\n return Promise.resolve(\"\");\n }\n // Named by call id: the model can ask the same question twice in a turn.\n console.warn(\n `ag-ui-chat: askUserRenderer failed for tool call ${callId}, so the built-in question card asks instead`,\n error,\n );\n return builtIn();\n }\n}\n", "import { LOAD_CAPABILITY_TOOL } from \"../constants.js\";\nimport type { AgUiToolCall } from \"../core/agui_client.js\";\n\n/**\n * The skill name a `load_capability` call activated, or `null` when the call is\n * something else.\n *\n * Every deferred capability loads through this one tool, so the id is a skill\n * name only when the project wired agent skills; another project's capability\n * id surfaces here too. Acceptable for a muted notice, and better than a\n * parallel signal \u2014 the id is exactly what the model selected.\n */\nexport function skillNameFrom(call: AgUiToolCall): string | null {\n if (call.name !== LOAD_CAPABILITY_TOOL) {\n return null;\n }\n const id = (call.args as { id?: unknown } | null | undefined)?.id;\n return typeof id === \"string\" && id !== \"\" ? id : null;\n}\n", "import type { Context, Interrupt } from \"@ag-ui/core\";\nimport { READ_PAGE_TOOL, TOOL_CALL_STATUS, TOOL_OUTCOME, X_CONFIRM_KEY } from \"../constants.js\";\nimport type { AgUiToolCall, InterruptResponse, ToolExecution } from \"../core/agui_client.js\";\nimport type { ClientConversationStore } from \"../core/conversation_store.js\";\nimport { skillNameFrom } from \"../skills/skill_name_from.js\";\nimport { fillUiString } from \"../ui/fill_ui_string.js\";\nimport {\n type ApprovalRenderer,\n type ApprovalRequest,\n requestApproval,\n} from \"../ui/interrupts/approval_card.js\";\nimport {\n type ConfirmationRequest,\n requestConfirmation,\n} from \"../ui/interrupts/confirmation_card.js\";\nimport type { PendingDecision } from \"../ui/interrupts/pending_decision.js\";\nimport type { ToolCallCard } from \"../ui/progress/tool_call_card.js\";\nimport type { Transcript } from \"../ui/transcript/transcript.js\";\nimport type { UiStrings } from \"../ui/ui_strings.js\";\nimport type { ClientTool } from \"./client_tool_registry.js\";\nimport { isDestructive } from \"./is_destructive.js\";\nimport { isNavigates } from \"./is_navigates.js\";\nimport type { ToolCatalog } from \"./tool_catalog.js\";\n\n/** What tool dispatch needs from the element that owns it. */\nexport interface ToolDispatchHost {\n /** The custom element, which a host's predicate and renderer are called on. */\n readonly element: HTMLElement;\n /** The transcript the cards and prompts are drawn in. */\n readonly transcript: Transcript;\n /** The tools this round advertised, and their implementations. */\n readonly tools: ToolCatalog;\n /** The decision a run is suspended on, which a Stop abandons. */\n readonly decision: PendingDecision;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Say one short thing to a screen reader. */\n readonly announce: (message: string) => void;\n /** The element's `autoConfirm`. */\n readonly autoConfirm: () => boolean;\n /** The element's `confirmPredicate`. */\n readonly confirmPredicate: () =>\n | ((toolName: string, args: Record<string, unknown>) => boolean | Promise<boolean>)\n | null;\n /** The element's `navigate`. */\n readonly navigate: () => ((path: string) => void) | null;\n /** The element's `approveWithEdits`. */\n readonly approveWithEdits: () => boolean;\n /** The element's `approvalRenderer`. */\n readonly approvalRenderer: () => ApprovalRenderer | null;\n /** The element's `getContext`, which a host may have replaced. */\n readonly getContext: () => Context[];\n /** The element's `conversationStore`, read per use. */\n readonly conversationStore: () => ClientConversationStore;\n /** The active thread's id. */\n readonly threadId: () => string;\n /** An identity replaced on every handover to another principal; only compared. */\n readonly tenure: () => object;\n /** An identity replaced whenever the transcript is cleared for another conversation; only compared. */\n readonly conversation: () => object;\n}\n\n/**\n * Running the frontend tool calls a round produced, and answering the server's\n * interrupts: the page each round's context described, the confirmation rules,\n * and the tools the user waived confirmation for.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ToolDispatch {\n readonly #host: ToolDispatchHost;\n /** Tool names the user waived confirmation for; never persisted, since that would be a permanent grant. */\n readonly #sessionApproved = new Set<string>();\n // The page the current round's context describes; `null` until the first round.\n #contextHref: string | null = null;\n\n constructor(host: ToolDispatchHost) {\n this.#host = host;\n }\n\n /** Forget every waiver: a logout is not a remount, so the next principal must not inherit one. */\n forgetWaivers(): void {\n this.#sessionApproved.clear();\n }\n\n /** Build a round's context, recording its page; the client calls this at the top of every tool round. */\n buildContext(): Context[] {\n this.#contextHref = window.location.href;\n return this.#host.getContext();\n }\n\n /**\n * Execute one frontend tool call the round produced, against its own card:\n * refused when the page moved under the round, asked about when a rule gates\n * it, and settled with what the handler returned or threw.\n *\n * Every await is a place the run can end, so each is followed by a check. A handover\n * leaves the call no transcript or store, so it draws and writes nothing; any other\n * reset (New chat, a drawer switch, `reload()`) still settles it but shows no pending\n * indicator in the new conversation.\n */\n async execute(call: AgUiToolCall): Promise<ToolExecution | null> {\n // A skill load is already a notice on the stream; it must not acquire a card here.\n if (skillNameFrom(call) !== null) {\n return null;\n }\n // Fixed at dispatch: read after the handler, they would be whoever is current by then.\n const tenure = this.#host.tenure();\n const conversation = this.#host.conversation();\n const threadId = this.#host.threadId();\n const card = this.#host.transcript.cardFor(call);\n this.#host.transcript.forgetCard(call.id);\n // A tool that renders into the transcript places itself against its card, no longer reachable by id.\n this.#host.transcript.setCardElement(call.id, card.element);\n this.#host.transcript.holdRunning(call.id, card);\n // A tool this round did not advertise is treated as an unknown name, so a hallucinated\n // or steered call cannot reach a handler that is merely registered mount-wide.\n const tool = this.#host.tools.wasAdvertised(call.name)\n ? this.#host.tools.resolve(call.name)\n : null;\n if (tool === null) {\n // A server tool's result arrives via `onToolResult` and already settled the card; with\n // none, neither side ran the call, so say it did not finish. No pending indicator:\n // no client round follows, so it would hang.\n if (!this.#host.transcript.isServerSettled(call.id)) {\n card.settle(TOOL_CALL_STATUS.INTERRUPTED, this.#host.strings().callNotFinished);\n }\n return null;\n }\n // The page moved under this round: a same-named control would match silently on the new\n // page. Precedes the confirmation prompt so no one approves a refused action. Navigating\n // tools and read_page (the recovery) are exempt; the refusal names read_page, so it\n // applies only when this round offered it.\n if (\n this.#host.tools.wasAdvertised(READ_PAGE_TOOL) &&\n call.name !== READ_PAGE_TOOL &&\n !isNavigates(tool.parameters) &&\n this.#pageMoved()\n ) {\n const message = this.#host.strings().pageMoved;\n card.settle(TOOL_CALL_STATUS.ERROR, message);\n this.#host.transcript.showPending();\n // Returned so a reload settles this card the same way; the card's status lives only in the DOM.\n return { content: `Error: ${message}`, error: message, outcome: TOOL_OUTCOME.FAILED };\n }\n // The run is suspended on the host's predicate (it may ask a server) as on a card, so a\n // Stop or handover aborts the wait.\n const asking = this.#host.decision.open();\n const rule = await this.#confirmationRule(call, tool);\n this.#host.decision.close();\n if (asking.aborted) {\n return this.#abandoned(card);\n }\n if (rule === \"unanswered\") {\n // A refusal, not a recorded decision: no person was asked.\n const message = this.#host.strings().confirmCheckFailed;\n card.settle(TOOL_CALL_STATUS.DECLINED, message);\n this.#host.transcript.showPending();\n return { content: message, outcome: TOOL_OUTCOME.DENIED };\n }\n if (rule !== null) {\n const request: ConfirmationRequest = { toolName: call.name, args: call.args };\n const confirmText = tool.parameters[X_CONFIRM_KEY];\n if (typeof confirmText === \"string\") {\n request.message = confirmText;\n }\n // Into the turn's answer group: appending to the message list put the prompt after later streamed content.\n // A Stop while the card is open aborts the signal, declining it.\n const signal = this.#host.decision.open();\n // Asking for as long as the prompt is open, so a step row reads \"waiting for you\".\n card.setAsking(true);\n let accepted: boolean;\n try {\n const decision = requestConfirmation(this.#host.transcript.ensureGroup(), request, {\n signal,\n strings: this.#host.strings(),\n // Only where it can be honoured: see `#confirmationRule`.\n ...(rule === \"destructive\"\n ? { onAlwaysAllow: () => this.#sessionApproved.add(call.name) }\n : {}),\n });\n this.#host.transcript.updateEmptyState();\n this.#host.transcript.follow();\n accepted = await decision;\n } finally {\n card.setAsking(false);\n }\n this.#host.decision.close();\n // A handover declines the card, but the transcript is the next principal's by now.\n if (this.#host.tenure() !== tenure) {\n return null;\n }\n card.recordDecision(accepted ? \"approved\" : \"declined\");\n if (!accepted) {\n const message = this.#host.strings().declinedAction;\n card.settle(TOOL_CALL_STATUS.DECLINED, message);\n // New chat or a drawer switch declines it too: skip only the drawing, not the refusal.\n if (this.#host.conversation() === conversation) {\n this.#host.transcript.showPending();\n }\n // The outcome annotation lets a reload show a refused action as denied.\n return { content: message, outcome: TOOL_OUTCOME.DENIED };\n }\n // Confirm and Stop in the same task: not declined, but the run is over, so it does not run\n // (the server-side gate treats approve-then-Stop the same way).\n if (signal.aborted) {\n return this.#abandoned(card);\n }\n }\n // With a host `navigate()` (SPA) a navigating tool routes in-page and the loop continues.\n const navigates = isNavigates(tool.parameters) && this.#host.navigate() === null;\n if (navigates) {\n // Checkpoint before the reload; the result is supplied on the next mount via the resume path.\n this.#host.conversationStore().saveCheckpoint(threadId, { toolCallId: call.id });\n }\n try {\n const result = await tool.handler(call.args, call.id);\n // A Stop keeps the result (the action happened); a handover leaves it no one to reach.\n if (this.#host.tenure() !== tenure) {\n return null;\n }\n // Drawn from the arguments, so live and replay render the same.\n if (tool.render !== undefined) {\n this.#host.transcript.renderToolOutput(tool.render, call);\n }\n if (navigates) {\n card.settle(TOOL_CALL_STATUS.DONE, this.#host.strings().navigating);\n return { content: \"\", halt: true };\n }\n const content = JSON.stringify(result ?? null);\n card.settle(TOOL_CALL_STATUS.DONE, content);\n // A reset that is not a handover keeps the result but shows no run waiting there.\n if (this.#host.conversation() === conversation) {\n this.#host.transcript.showPending();\n }\n return { content };\n } catch (error) {\n // Also guards a write: after a handover the store is the next principal's.\n if (this.#host.tenure() !== tenure) {\n return null;\n }\n if (navigates) {\n // The navigation never happened; drop the checkpoint from the thread it was written to.\n this.#host.conversationStore().saveCheckpoint(threadId, null);\n }\n // Verbatim, on the card and in the result replayed to the model: a real reason lets it recover.\n const message = error instanceof Error ? error.message : String(error);\n card.settle(TOOL_CALL_STATUS.ERROR, message);\n if (this.#host.conversation() === conversation) {\n this.#host.transcript.showPending();\n }\n return { content: `Error: ${message}`, error: message, outcome: TOOL_OUTCOME.FAILED };\n }\n }\n\n /**\n * Render an approval card per server-side-tool interrupt and collect the\n * user's decisions (approve \u2192 run it, deny \u2192 decline it).\n *\n * One card per gated call, in that call's own tool card, all at once: the prompt is\n * identical for every call of a tool, so position tells them apart, and serial asking\n * hides that more are coming. Each is marked `deferred` for the wait, else it reads\n * \"running...\". A Stop aborts the shared decision, denying every open card. An approved\n * tool runs on the resume run into the same card; a denied one settles here.\n */\n async resolveInterrupts(\n interrupts: readonly Interrupt[],\n ): Promise<Record<string, InterruptResponse>> {\n const signal = this.#host.decision.open();\n // The transcript is not a live region, so a screen reader needs this to know the run awaits a person.\n this.#host.announce(\n fillUiString(this.#host.strings().announceAwaitingDecision, { count: interrupts.length }),\n );\n this.#host.transcript.hidePending();\n const answered = await Promise.all(\n interrupts.map(async (interrupt) => {\n const card =\n interrupt.toolCallId !== undefined\n ? this.#host.transcript.card(interrupt.toolCallId)\n : undefined;\n const request: ApprovalRequest = {};\n const phrase = confirmPhrase(interrupt) ?? interrupt.message;\n if (phrase !== undefined) {\n request.message = phrase;\n }\n const toolName = card?.element.getAttribute(\"data-tool-name\");\n if (toolName !== null && toolName !== undefined) {\n request.toolName = toolName;\n }\n // Only where honoured: the agent accepts `editedArgs` and we hold the call's arguments.\n let editedArgs: Record<string, unknown> | undefined;\n const editable = this.#host.approveWithEdits() && card !== undefined;\n if (editable) {\n request.args = card.args;\n }\n card?.mark(TOOL_CALL_STATUS.DEFERRED);\n // Before either renderer: a folded step group has no box to focus in.\n if (card !== undefined) {\n this.#host.transcript.revealStep(card);\n }\n // Falls back to the answer group when the interrupt names no call we hold.\n const builtIn = (): Promise<boolean> =>\n requestApproval(card?.approvalSlot ?? this.#host.transcript.ensureGroup(), request, {\n signal,\n strings: this.#host.strings(),\n ...(editable\n ? {\n onEdit: (args: Record<string, unknown>) => {\n editedArgs = args;\n },\n }\n : {}),\n });\n const renderer = this.#host.approvalRenderer();\n let approved: boolean;\n if (renderer === null) {\n approved = await builtIn();\n } else {\n // Awaited here, not in a helper, to keep the microtask count of an answering renderer.\n try {\n approved = await renderer.call(this.#host.element, request, { signal });\n } catch (error) {\n approved = await this.#afterRendererFailed(error, signal, interrupt.id, builtIn);\n }\n }\n // The same annotation as the client-side gate, so both read alike.\n card?.recordDecision(approved ? \"approved\" : \"declined\");\n if (approved) {\n card?.mark(TOOL_CALL_STATUS.PENDING);\n } else {\n // No TOOL_CALL_RESULT will stream for a denied tool.\n card?.settle(TOOL_CALL_STATUS.DECLINED, this.#host.strings().declinedAction);\n }\n return { id: interrupt.id, approved, editedArgs };\n }),\n );\n this.#host.transcript.updateEmptyState();\n this.#host.transcript.follow();\n this.#host.decision.close();\n const responses: Record<string, InterruptResponse> = {};\n for (const { id, approved, editedArgs } of answered) {\n // `editedArgs` rides only when changed, so \"approved as proposed\" differs from \"approved, but like this\".\n responses[id] = approved\n ? {\n status: \"resolved\",\n payload: editedArgs === undefined ? { approved: true } : { approved: true, editedArgs },\n }\n : { status: \"cancelled\" };\n }\n return responses;\n }\n\n /**\n * Answer an interrupt whose host renderer failed: the built-in card asks instead.\n *\n * A renderer is presentation, not a guard; uncaught, its failure would reject the whole\n * batch. A rejection after a Stop is the signal working: it resolves as not approved,\n * silently.\n */\n #afterRendererFailed(\n error: unknown,\n signal: AbortSignal,\n interruptId: string,\n builtIn: () => Promise<boolean>,\n ): Promise<boolean> {\n if (signal.aborted) {\n return Promise.resolve(false);\n }\n // Named by interrupt id: a batch can gate several calls of one tool.\n console.warn(\n `ag-ui-chat: approvalRenderer failed for interrupt ${interruptId}, so the built-in approval card asks instead`,\n error,\n );\n return builtIn();\n }\n\n /**\n * Which rule gates `call`, or `null` when it runs straight through, or\n * `\"unanswered\"` when the host's predicate threw instead of deciding.\n *\n * The rule decides whether the prompt may be waived for the session: only the default\n * `x-destructive` gate is, since `confirmPredicate` is authoritative.\n */\n async #confirmationRule(call: AgUiToolCall, tool: ClientTool): Promise<ConfirmationRule | null> {\n if (this.#host.autoConfirm()) {\n return null;\n }\n const predicate = this.#host.confirmPredicate();\n if (predicate !== null) {\n try {\n return (await predicate.call(this.#host.element, call.name, call.args)) === true\n ? \"predicate\"\n : null;\n } catch (error) {\n // Fails closed: a guard that cannot answer has not said the call is safe. The message\n // goes to the console, not the endpoint, since it was never written for the model.\n console.warn(\n `ag-ui-chat: confirmPredicate failed for tool ${call.name}, so the call was refused`,\n error,\n );\n return \"unanswered\";\n }\n }\n if (this.#sessionApproved.has(call.name)) {\n return null;\n }\n return isDestructive(tool.parameters) ? \"destructive\" : null;\n }\n\n /**\n * Settle a call whose run ended while it waited, and give the loop nothing.\n *\n * Dispatch took the card out of the end-of-run sweep, so nothing else settles it. `null`\n * because a stopped run has no next round; the client answers the call as not finished\n * on the next request, in the card's words.\n */\n #abandoned(card: ToolCallCard): null {\n card.settle(TOOL_CALL_STATUS.INTERRUPTED, this.#host.strings().callNotFinished);\n return null;\n }\n\n /**\n * Whether the page moved since the current round's context was built.\n *\n * `null` means no round has built context yet (nothing to compare), which is\n * not a move.\n */\n #pageMoved(): boolean {\n return this.#contextHref !== null && this.#contextHref !== window.location.href;\n }\n}\n\n/**\n * A server-authored question for a gated call, read off the interrupt's metadata under\n * `x-confirm`, as a client-side confirmation reads it from the schema. Narrowed because\n * `metadata` is untyped on the wire and a non-string would render as \"[object Object]\".\n */\nfunction confirmPhrase(interrupt: Interrupt): string | undefined {\n const phrase = interrupt.metadata?.[X_CONFIRM_KEY];\n return typeof phrase === \"string\" && phrase.trim() !== \"\" ? phrase : undefined;\n}\n\n/**\n * Why a client tool call is gated behind the confirmation card, or refused\n * before one is drawn.\n *\n * Only `\"destructive\"` -- the default `x-destructive` gate -- may be waived for\n * the session. `confirmPredicate` is documented as authoritative, so a call it\n * gates keeps asking. `\"unanswered\"` is a predicate that threw instead of\n * answering, and the call it was asked about is refused without a card.\n */\ntype ConfirmationRule = \"destructive\" | \"predicate\" | \"unanswered\";\n", "/**\n * Size the field to its content: one row when empty, growing with what is\n * typed until the CSS ceiling takes over and it scrolls.\n *\n * Resetting to `auto` first is what makes it shrink again \u2014 `scrollHeight`\n * never reports less than the current height, so measuring without the reset\n * would ratchet the composer taller and never back down.\n */\nexport function autoGrow(input: HTMLTextAreaElement): void {\n input.style.height = \"auto\";\n input.style.height = `${input.scrollHeight}px`;\n}\n", "/**\n * A `<slot>` a host can project its own mark into, falling back to one of the\n * built-in glyphs. The markup is an author-written constant, never user or\n * server data, so it is assigned directly rather than sanitised.\n */\nexport function glyphSlot(slotName: string, className: string, markup: string): HTMLSlotElement {\n const slot = document.createElement(\"slot\");\n slot.name = slotName;\n slot.className = className;\n slot.innerHTML = markup;\n return slot;\n}\n", "import { ICON_ATTACH, ICON_SEND, ICON_STOP } from \"../../constants.js\";\nimport { glyphSlot } from \"../shell/glyph_slot.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\n\n/** The composer's parts, owned by the element, and what they call back into. */\nexport interface ComposerOptions {\n readonly input: HTMLTextAreaElement;\n readonly send: HTMLButtonElement;\n readonly attachButton: HTMLButtonElement;\n readonly fileInput: HTMLInputElement;\n readonly voiceSlot: HTMLElement;\n /** The place chip; sits in the tool row between the voice slot and Send. */\n readonly place: HTMLElement;\n /** The line saying what the composer still needs; sits above the input. */\n readonly hint: HTMLElement;\n /** The queued-message row; sits above the input beside the tray. */\n readonly queuedRow: HTMLElement;\n /** Where the attachment tray mounts; sits above the input. */\n readonly attachSlot: HTMLElement;\n readonly strings: UiStrings;\n readonly signal: AbortSignal;\n readonly onKeydown: (event: KeyboardEvent) => void;\n readonly onInput: () => void;\n /** Send while idle, Stop while a run is in flight: the element decides. */\n readonly onSend: () => void;\n readonly onFilesPicked: () => void;\n}\n\n/**\n * Build the composer row -- the field, and the tool row under it with the\n * attach and voice controls, the place chip and Send -- and ready the composer surfaces the\n * element mounts above it: the hint, the queued row and the attachment slot.\n * Returns the row; the element places it and the surfaces.\n */\nexport function buildComposer(options: ComposerOptions): HTMLElement {\n const { input, send, attachButton, fileInput, strings, signal } = options;\n\n const queued = options.queuedRow;\n queued.className = \"queued\";\n queued.setAttribute(\"part\", \"queued\");\n queued.setAttribute(\"role\", \"group\");\n queued.setAttribute(\"aria-label\", strings.queued);\n queued.hidden = true;\n\n const inputRow = document.createElement(\"div\");\n inputRow.className = \"input-row\";\n inputRow.setAttribute(\"part\", \"composer\");\n\n // One bordered surface holds the field and the tool row under it, so the\n // icon buttons stop competing with the field for weight.\n const composer = document.createElement(\"div\");\n composer.className = \"composer\";\n composer.setAttribute(\"part\", \"composer-surface\");\n\n const tools = document.createElement(\"div\");\n tools.className = \"composer-tools\";\n tools.setAttribute(\"part\", \"composer-tools\");\n\n input.className = \"input\";\n input.setAttribute(\"part\", \"input\");\n input.setAttribute(\"aria-label\", strings.message);\n input.rows = 1;\n input.placeholder = strings.inputPlaceholder;\n input.addEventListener(\"keydown\", options.onKeydown, { signal });\n input.addEventListener(\"input\", options.onInput, { signal });\n\n // Icon-only, with both glyphs mounted at once and CSS showing the one the\n // state calls for \u2014 swapping a single glyph would leave a host that slotted\n // its own Send mark holding a stop icon mid-run.\n send.className = \"send\";\n send.type = \"button\";\n send.setAttribute(\"part\", \"send\");\n send.replaceChildren(\n glyphSlot(\"icon-send\", \"send-send\", ICON_SEND),\n glyphSlot(\"icon-stop\", \"send-stop\", ICON_STOP),\n );\n send.title = strings.send;\n send.setAttribute(\"aria-label\", strings.send);\n send.dataset[\"state\"] = \"idle\";\n send.addEventListener(\"click\", options.onSend, { signal });\n\n const hint = options.hint;\n hint.className = \"skill-hint\";\n hint.setAttribute(\"part\", \"skill-hint\");\n hint.hidden = true;\n\n // File-upload affordance: a paperclip button (hidden until\n // `data-attachments-url` is wired) opening a hidden multi-file input.\n // Drag-and-drop covers the whole shell (wired by ComposerAttachments).\n attachButton.className = \"attach-btn\";\n attachButton.type = \"button\";\n attachButton.setAttribute(\"part\", \"attach-button\");\n attachButton.replaceChildren(glyphSlot(\"icon-attach\", \"attach-glyph\", ICON_ATTACH));\n attachButton.title = strings.attachFiles;\n attachButton.setAttribute(\"aria-label\", strings.attachFiles);\n attachButton.hidden = true;\n attachButton.addEventListener(\"click\", () => fileInput.click(), { signal });\n\n fileInput.className = \"attach-input\";\n fileInput.type = \"file\";\n fileInput.multiple = true;\n fileInput.hidden = true;\n fileInput.addEventListener(\"change\", options.onFilesPicked, { signal });\n\n options.attachSlot.className = \"attachment-slot\";\n\n // Mic button mount point (kept empty until ComposerVoice mounts the control).\n options.voiceSlot.className = \"voice-slot\";\n\n tools.append(attachButton, options.voiceSlot, options.place, send);\n composer.append(input, tools);\n inputRow.append(composer, fileInput);\n return inputRow;\n}\n", "import { randomUUID } from \"@ag-ui/client\";\nimport { ATTACHMENT_STATUS } from \"../../constants.js\";\nimport type { AttachmentRef } from \"../../core/attachment.js\";\nimport type { UploadHandler } from \"../../core/upload_attachment.js\";\nimport { commaTokens } from \"../../core/utils.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport { formatBytes, iconFor } from \"../transcript/attachment_chips.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\n\n/** Status of a pending tray chip. */\ntype AttachmentStatus = (typeof ATTACHMENT_STATUS)[keyof typeof ATTACHMENT_STATUS];\n\n/** Config the host ({@link AgUiChat}) hands the tray. */\nexport interface AttachmentTrayConfig {\n /** Upload one file, reporting `0..1` progress; resolves to a durable ref. */\n readonly upload: UploadHandler;\n /** Client-side size cap in bytes (`0` = no cap). The server stays authoritative. */\n readonly maxBytes: number;\n /** Client-side accept list (`<input accept>` syntax; `\"\"` = any). */\n readonly accept: string;\n /** Fired when the set of attachments changes (add / settle / remove). */\n readonly onChange?: () => void;\n /** Localized strings; defaults to the English {@link DEFAULT_UI_STRINGS}. */\n readonly strings?: UiStrings;\n}\n\n/** One pending file in the tray, from pick to ready/error. */\ninterface TrayItem {\n readonly localId: string;\n readonly file: File;\n status: AttachmentStatus;\n progress: number;\n ref: AttachmentRef | null;\n error: string;\n /** Aborts the in-flight upload when the chip is removed / the tray cleared. */\n controller: AbortController | null;\n}\n\n/**\n * The composer's pending-attachments tray: a chip per picked file with a\n * progress bar while it uploads, settling to a ready chip holding the durable\n * ref or an error chip with retry. A stateful view like {@link ThreadDrawer}:\n * the host appends {@link element}, calls {@link add} on pick or drop, reads\n * {@link readyRefs} on send, and clears it.\n *\n * Client-side size and type guards reject a bad file into an error chip without\n * uploading, for instant feedback, but the server stays the authority.\n */\nexport class AttachmentTray {\n /** The tray root; append above the input row. Hidden while empty. */\n readonly element: HTMLDivElement;\n\n readonly #config: AttachmentTrayConfig;\n readonly #strings: UiStrings;\n #items: TrayItem[] = [];\n\n constructor(config: AttachmentTrayConfig) {\n this.#config = config;\n this.#strings = config.strings ?? DEFAULT_UI_STRINGS;\n this.element = document.createElement(\"div\");\n this.element.className = \"attachment-tray\";\n this.element.setAttribute(\"part\", \"attachment-tray\");\n this.element.hidden = true;\n }\n\n /** Queue a file: reject oversize/disallowed into an error chip, else upload. */\n add(file: File): void {\n const item: TrayItem = {\n localId: randomUUID(),\n file,\n status: ATTACHMENT_STATUS.UPLOADING,\n progress: 0,\n ref: null,\n error: \"\",\n controller: null,\n };\n this.#items.push(item);\n const rejection = this.#reject(file);\n if (rejection !== null) {\n item.status = ATTACHMENT_STATUS.ERROR;\n item.error = rejection;\n this.#render();\n this.#config.onChange?.();\n return;\n }\n this.#render();\n this.#config.onChange?.();\n this.#upload(item);\n }\n\n /** The durable refs of every chip that finished uploading. */\n readyRefs(): readonly AttachmentRef[] {\n const refs: AttachmentRef[] = [];\n for (const item of this.#items) {\n if (item.ref !== null) {\n refs.push(item.ref);\n }\n }\n return refs;\n }\n\n /** Whether any chip is still uploading (a send would drop nothing if false). */\n hasPending(): boolean {\n return this.#items.some((item) => item.status === ATTACHMENT_STATUS.UPLOADING);\n }\n\n /** How many chips are still uploading \u2014 the count a send-time notice names. */\n pendingCount(): number {\n return this.#items.filter((item) => item.status === ATTACHMENT_STATUS.UPLOADING).length;\n }\n\n /** Whether the tray holds no chips. */\n isEmpty(): boolean {\n return this.#items.length === 0;\n }\n\n /** Drop the settled (ready / error) chips, leaving any still uploading. */\n clearReady(): void {\n this.#items = this.#items.filter((item) => item.status === ATTACHMENT_STATUS.UPLOADING);\n this.#render();\n }\n\n /** Drop every chip (a reset / new-chat), aborting any in-flight upload. */\n clear(): void {\n for (const item of this.#items) {\n item.controller?.abort();\n }\n this.#items = [];\n this.#render();\n }\n\n /**\n * Abort every in-flight upload without touching the rendered chips \u2014 the\n * teardown path when the host element is removed mid-upload, so a cancelled\n * transfer doesn't orphan a server-side file.\n */\n dispose(): void {\n for (const item of this.#items) {\n item.controller?.abort();\n }\n }\n\n /** The size/type rejection reason for a file, or `null` when accepted. */\n #reject(file: File): string | null {\n if (this.#config.maxBytes > 0 && file.size > this.#config.maxBytes) {\n return fillUiString(this.#strings.tooLarge, { size: formatBytes(this.#config.maxBytes) });\n }\n if (!accepts(this.#config.accept, file)) {\n return this.#strings.fileTypeNotAllowed;\n }\n return null;\n }\n\n #upload(item: TrayItem): void {\n // Re-apply the client guard on every attempt, not just the first `add` \u2014 an\n // ERROR chip always renders retry, so without this a size/type-rejected file\n // would upload in full on \u21BB.\n const rejection = this.#reject(item.file);\n if (rejection !== null) {\n item.status = ATTACHMENT_STATUS.ERROR;\n item.error = rejection;\n this.#render();\n this.#config.onChange?.();\n return;\n }\n item.status = ATTACHMENT_STATUS.UPLOADING;\n item.progress = 0;\n item.error = \"\";\n const controller = new AbortController();\n item.controller = controller;\n this.#render();\n this.#config\n .upload(\n item.file,\n (fraction) => {\n item.progress = fraction;\n this.#render();\n },\n controller.signal,\n )\n .then((ref) => {\n item.status = ATTACHMENT_STATUS.READY;\n item.ref = ref;\n })\n .catch((error: unknown) => {\n item.status = ATTACHMENT_STATUS.ERROR;\n item.error = error instanceof Error ? error.message : this.#strings.uploadFailed;\n })\n .finally(() => {\n item.controller = null;\n this.#render();\n this.#config.onChange?.();\n });\n }\n\n #remove(item: TrayItem): void {\n // Abort an in-flight upload so removing its chip doesn't orphan the file.\n item.controller?.abort();\n this.#items = this.#items.filter((other) => other !== item);\n this.#render();\n this.#config.onChange?.();\n }\n\n #render(): void {\n this.element.replaceChildren();\n this.element.hidden = this.#items.length === 0;\n for (const item of this.#items) {\n this.element.appendChild(this.#renderChip(item));\n }\n }\n\n #renderChip(item: TrayItem): HTMLDivElement {\n const chip = document.createElement(\"div\");\n chip.className = `attachment-chip attachment-chip--${item.status}`;\n chip.setAttribute(\"part\", \"attachment-chip\");\n\n const icon = document.createElement(\"span\");\n icon.className = \"attachment-chip-icon\";\n icon.setAttribute(\"part\", \"attachment-chip-icon\");\n // Author-written glyph markup, selected by MIME family \u2014 see iconFor.\n icon.innerHTML = iconFor(item.file.type);\n icon.setAttribute(\"aria-hidden\", \"true\");\n\n const name = document.createElement(\"span\");\n name.className = \"attachment-chip-name\";\n name.setAttribute(\"part\", \"attachment-chip-name\");\n name.textContent = item.file.name;\n name.title = item.file.name;\n\n const meta = document.createElement(\"span\");\n meta.className = \"attachment-chip-size\";\n meta.setAttribute(\"part\", \"attachment-chip-size\");\n meta.textContent =\n item.status === ATTACHMENT_STATUS.ERROR ? item.error : formatBytes(item.file.size);\n\n chip.append(icon, name, meta);\n\n if (item.status === ATTACHMENT_STATUS.UPLOADING) {\n const bar = document.createElement(\"div\");\n bar.className = \"attachment-chip-bar\";\n bar.setAttribute(\"part\", \"attachment-chip-bar\");\n const fill = document.createElement(\"div\");\n fill.className = \"attachment-chip-bar-fill\";\n fill.setAttribute(\"part\", \"attachment-chip-bar-fill\");\n fill.style.width = `${Math.round(item.progress * 100)}%`;\n bar.appendChild(fill);\n chip.appendChild(bar);\n }\n\n if (item.status === ATTACHMENT_STATUS.ERROR) {\n const retry = document.createElement(\"button\");\n retry.type = \"button\";\n retry.className = \"attachment-chip-retry\";\n retry.setAttribute(\"part\", \"attachment-chip-retry\");\n retry.title = this.#strings.retry;\n retry.setAttribute(\"aria-label\", this.#strings.retryUpload);\n retry.textContent = \"\u21BB\";\n retry.addEventListener(\"click\", () => this.#upload(item));\n chip.appendChild(retry);\n }\n\n const remove = document.createElement(\"button\");\n remove.type = \"button\";\n remove.className = \"attachment-chip-remove\";\n remove.setAttribute(\"part\", \"attachment-chip-remove\");\n remove.title = this.#strings.remove;\n remove.setAttribute(\"aria-label\", this.#strings.removeAttachment);\n remove.textContent = \"\u2715\";\n remove.addEventListener(\"click\", () => this.#remove(item));\n chip.appendChild(remove);\n\n return chip;\n }\n}\n\n/** Whether `file` matches an `<input accept>` list (`\"\"` accepts anything). */\nfunction accepts(accept: string, file: File): boolean {\n // Lower-cased after the shared split rather than before the filter: no\n // non-empty token lower-cases to an empty one, so the order cannot matter.\n const tokens = commaTokens(accept).map((token) => token.toLowerCase());\n if (tokens.length === 0) {\n return true;\n }\n const mime = file.type.toLowerCase();\n const name = file.name.toLowerCase();\n return tokens.some((token) => {\n if (token.startsWith(\".\")) {\n return name.endsWith(token);\n }\n if (token.endsWith(\"/*\")) {\n return mime.startsWith(token.slice(0, -1));\n }\n return mime === token;\n });\n}\n", "import { ICON_FILE, ICON_FILE_IMAGE, ICON_FILE_PDF, ICON_FILE_TEXT } from \"../../constants.js\";\nimport type { AttachmentRef } from \"../../core/attachment.js\";\n\n/**\n * Render the read-only attachment chips on a sent user message bubble and on\n * restored history \u2014 one chip per ref with a type icon, filename, and human\n * size. Static: no progress and no remove, both of which live in the composer\n * tray.\n */\nexport function renderAttachmentChips(refs: readonly AttachmentRef[]): HTMLDivElement {\n const list = document.createElement(\"div\");\n list.className = \"attachment-chips\";\n list.setAttribute(\"part\", \"attachment-chips\");\n for (const ref of refs) {\n list.appendChild(renderChip(ref));\n }\n return list;\n}\n\nfunction renderChip(ref: AttachmentRef): HTMLDivElement {\n const chip = document.createElement(\"div\");\n chip.className = \"attachment-chip attachment-chip--ready\";\n chip.setAttribute(\"part\", \"attachment-chip\");\n\n const icon = document.createElement(\"span\");\n icon.className = \"attachment-chip-icon\";\n icon.setAttribute(\"part\", \"attachment-chip-icon\");\n icon.innerHTML = iconFor(ref.mime);\n icon.setAttribute(\"aria-hidden\", \"true\");\n\n const name = document.createElement(\"span\");\n name.className = \"attachment-chip-name\";\n name.setAttribute(\"part\", \"attachment-chip-name\");\n name.textContent = ref.name;\n name.title = ref.name;\n\n const size = document.createElement(\"span\");\n size.className = \"attachment-chip-size\";\n size.setAttribute(\"part\", \"attachment-chip-size\");\n size.textContent = formatBytes(ref.size);\n\n chip.append(icon, name, size);\n return chip;\n}\n\n/**\n * A coarse type mark for a chip \u2014 image, PDF, text document, or generic file \u2014\n * as inline SVG markup rather than a character, so it matches the composer's\n * SVG buttons in weight and takes the glyph size and `currentColor`, which\n * emoji do not.\n *\n * The MIME string only selects among author-written constants and is never\n * interpolated into one, so the result is safe to assign as markup.\n */\nexport function iconFor(mime: string): string {\n if (mime.startsWith(\"image/\")) {\n return ICON_FILE_IMAGE;\n }\n if (mime === \"application/pdf\") {\n return ICON_FILE_PDF;\n }\n if (mime.startsWith(\"text/\")) {\n return ICON_FILE_TEXT;\n }\n return ICON_FILE;\n}\n\n/** A compact human-readable byte size (e.g. `1.2 MB`). */\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`;\n }\n const units = [\"KB\", \"MB\", \"GB\"];\n let value = bytes / 1024;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n const rounded = value < 10 ? Math.round(value * 10) / 10 : Math.round(value);\n return `${rounded} ${units[unit]}`;\n}\n", "import {\n ATTACHMENT_EVENT,\n DEFAULT_ATTACHMENT_MAX_BYTES,\n PASTE_ATTACH_CHARS,\n} from \"../../constants.js\";\nimport type { AttachmentsDetail } from \"../../core/events/attachments_detail.js\";\nimport { type UploadHandler, uploadAttachment } from \"../../core/upload_attachment.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { AttachmentTray } from \"./attachment_tray.js\";\n\n/** What the composer's attachments need from the element that owns them. */\nexport interface ComposerAttachmentsHost {\n /** The custom element: its upload attributes, and where the event is dispatched. */\n readonly element: HTMLElement;\n /** The chat shell, which a file can be dropped or pasted anywhere on. */\n readonly chat: HTMLElement;\n /** Where the tray mounts, above the composer. */\n readonly slot: HTMLElement;\n /** The hidden multi-file input the paperclip opens. */\n readonly fileInput: HTMLInputElement;\n /** The paperclip, revealed once uploads are possible. */\n readonly button: HTMLButtonElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** The host's `uploadHandler`, read when the tray is wired. */\n readonly uploadHandler: () => UploadHandler | null;\n /** The headers a request to `url` carries. */\n readonly headersFor: (url: string) => Record<string, string>;\n /** The cookie policy every request carries, when one is configured. */\n readonly credentialsOption: () => { credentials?: RequestCredentials };\n}\n\n/**\n * Files handed to the composer: the tray they upload through, and the four\n * ways into it -- the picker, a drop, a paste, and a host's `attachFile`.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ComposerAttachments {\n readonly #host: ComposerAttachmentsHost;\n /** Upload tray; created on connect only when `data-attachments-url` is set. */\n #tray: AttachmentTray | null = null;\n\n constructor(host: ComposerAttachmentsHost) {\n this.#host = host;\n }\n\n /** The tray, once uploads are wired; `null` while the chat is text-only. */\n get tray(): AttachmentTray | null {\n return this.#tray;\n }\n\n /**\n * Enable the composer's file-upload tray when uploads are possible \u2014 either a\n * custom `uploadHandler` is set or `data-attachments-url` provides the\n * built-in multipart endpoint: reveal the \uD83D\uDCCE button, wire the hidden file\n * input + drag-and-drop, and mount the tray. With neither, the affordance\n * stays hidden and the chat degrades to text-only.\n *\n * Called on every connect, so it starts by taking down the tray the last\n * connection mounted: that one was disposed when the element left, and the\n * attributes that decide whether there is a tray at all may have changed\n * since. The shell outlives a connection, so its listeners go under `signal`.\n */\n wire(signal: AbortSignal): void {\n this.#tray?.element.remove();\n this.#tray = null;\n const url = this.#host.element.getAttribute(\"data-attachments-url\");\n const upload = this.#host.uploadHandler() ?? this.#defaultUploadHandler(url);\n if (upload === null) {\n return;\n }\n const accept = this.#host.element.getAttribute(\"data-attachment-accept\") ?? \"\";\n // Bound to the local rather than the field: the hook can only fire from a\n // tray that exists, so passing it removes a null check no caller can reach.\n const tray: AttachmentTray = new AttachmentTray({\n upload,\n maxBytes: this.#maxBytes(),\n accept,\n strings: this.#host.strings(),\n // The tray's change hook, surfaced to the host as an event. A host\n // driving its own composer could otherwise not tell a settled upload from\n // one still in flight, which is the state sendMessage() has to be called\n // with knowledge of.\n onChange: () => this.#dispatch(tray),\n });\n this.#tray = tray;\n this.#host.slot.appendChild(this.#tray.element);\n this.#host.fileInput.accept = accept;\n this.#host.button.hidden = false;\n this.#enableDragAndDrop(signal);\n this.#enablePaste(tray, signal);\n }\n\n /** The queueing behind `AgUiChat.attachFile`, whose doc is the contract. */\n attach(file: File): boolean {\n if (this.#tray === null) {\n return false;\n }\n this.#tray.add(file);\n return true;\n }\n\n /** Queue every file from the picker into the tray, then reset the input. */\n onFilesPicked(): void {\n const input = this.#host.fileInput;\n const files = input.files;\n if (files !== null) {\n for (const file of Array.from(files)) {\n this.#tray?.add(file);\n }\n }\n // Reset so re-picking the same file fires `change` again.\n input.value = \"\";\n }\n\n /** The built-in multipart upload handler for `data-attachments-url`, or `null`. */\n #defaultUploadHandler(url: string | null): UploadHandler | null {\n if (url === null) {\n return null;\n }\n // Forward the tray's abort signal so removing a chip (or tearing the\n // element down) cancels the XHR.\n return (file, onProgress, signal) =>\n uploadAttachment(file, {\n url,\n headers: this.#host.headersFor(url),\n ...this.#host.credentialsOption(),\n onProgress,\n signal,\n });\n }\n\n /** The client-side upload size cap from `data-attachment-max-bytes`. */\n #maxBytes(): number {\n const attr = this.#host.element.getAttribute(\"data-attachment-max-bytes\");\n if (attr === null) {\n return DEFAULT_ATTACHMENT_MAX_BYTES;\n }\n const parsed = Number.parseInt(attr, 10);\n return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_ATTACHMENT_MAX_BYTES;\n }\n\n /** Accept files dropped anywhere on the chat shell into the tray. */\n #enableDragAndDrop(signal: AbortSignal): void {\n const chat = this.#host.chat;\n chat.addEventListener(\n \"dragover\",\n (event) => {\n event.preventDefault();\n chat.classList.add(\"chat--dragover\");\n },\n { signal },\n );\n chat.addEventListener(\n \"dragleave\",\n () => {\n chat.classList.remove(\"chat--dragover\");\n },\n { signal },\n );\n chat.addEventListener(\n \"drop\",\n (event) => {\n event.preventDefault();\n chat.classList.remove(\"chat--dragover\");\n const files = event.dataTransfer?.files;\n if (files !== undefined) {\n for (const file of Array.from(files)) {\n this.#tray?.add(file);\n }\n }\n },\n { signal },\n );\n }\n\n /**\n * Turn a very long text paste into an attachment instead of a wall of text.\n *\n * A composer capped at `40vh` is not where forty thousand characters go: the\n * user cannot read what they pasted, cannot edit around it, and sends one\n * enormous turn. As a file it stays whole, the model still receives it, and\n * the box is left for the question about it.\n *\n * Only where the host has configured uploads -- and structurally so, rather\n * than by a check here: the paste listener is wired inside the attachment\n * setup, so with no tray there is no listener at all and an ordinary paste is\n * untouched. Quietly dropping a paste for being long would be far worse than\n * an awkward composer. The tray is passed rather than read off the field for\n * the same reason its `onChange` hook is: it can only be called from one that\n * exists, so taking it as an argument removes a null check no caller can\n * reach.\n *\n * Nothing is lost by removing the chip: the text is still on the clipboard,\n * so pasting again brings it back. That is why this needs no undo of its own.\n */\n #pasteLongTextAsFile(event: ClipboardEvent, clipboard: DataTransfer, tray: AttachmentTray): void {\n const threshold = this.#pasteAttachThreshold();\n const text = clipboard.getData(\"text/plain\");\n if (threshold === null || text.length < threshold) {\n return;\n }\n event.preventDefault();\n tray.add(new File([text], `pasted-${pasteStamp()}.txt`, { type: \"text/plain\" }));\n }\n\n /**\n * How long a pasted string has to be before it becomes a file, or `null` to\n * leave every paste in the composer.\n *\n * One attribute with three answers rather than three attributes: absent is\n * the default, `off` refuses, and a number states the threshold. A value that\n * is neither says so, because a typo silently meaning \"off\" is the failure\n * this whole release keeps finding.\n */\n #pasteAttachThreshold(): number | null {\n const raw = this.#host.element.getAttribute(\"data-paste-attach\");\n if (raw === null) {\n return PASTE_ATTACH_CHARS;\n }\n if (raw === \"off\") {\n return null;\n }\n const stated = Number.parseInt(raw, 10);\n if (Number.isNaN(stated) || stated <= 0) {\n console.warn(\n `<ag-ui-chat>: data-paste-attach=\"${raw}\" is neither \"off\" nor a positive ` +\n `number of characters, so the default of ${PASTE_ATTACH_CHARS} is used.`,\n );\n return PASTE_ATTACH_CHARS;\n }\n return stated;\n }\n\n /**\n * Accept files pasted into the composer.\n *\n * The whole tray already exists behind this: a paste is one more way to hand\n * it a `File`, alongside the picker and a drop.\n *\n * Two rules keep it from stealing a paste that was never about files.\n * `clipboardData.files` is empty for text, so ordinary pasting is untouched.\n * And the default is only prevented when the clipboard carries **no text**:\n * copying a rich selection that happens to contain an image puts both on the\n * clipboard, and swallowing the words someone meant to paste in order to\n * attach a picture they did not is the worse of the two failures.\n */\n #enablePaste(tray: AttachmentTray, signal: AbortSignal): void {\n this.#host.chat.addEventListener(\n \"paste\",\n (event: ClipboardEvent) => {\n // Nullish rather than a null check: the property is typed as nullable,\n // and an engine that fires a plain Event for a paste leaves it absent\n // instead, which is not the same value and is the same situation.\n const clipboard = event.clipboardData ?? null;\n if (clipboard === null) {\n return;\n }\n const files = Array.from(clipboard.files);\n if (files.length === 0) {\n this.#pasteLongTextAsFile(event, clipboard, tray);\n return;\n }\n if (clipboard.getData(\"text/plain\") === \"\") {\n event.preventDefault();\n }\n for (const file of files) {\n this.#tray?.add(named(file));\n }\n },\n { signal },\n );\n }\n\n /** Tell the host what the tray now holds \u2014 see {@link ATTACHMENT_EVENT}. */\n #dispatch(tray: AttachmentTray): void {\n this.#host.element.dispatchEvent(\n new CustomEvent<AttachmentsDetail>(ATTACHMENT_EVENT, {\n detail: { attachments: tray.readyRefs(), pending: tray.pendingCount() },\n bubbles: true,\n composed: true,\n }),\n );\n }\n}\n\n/**\n * The moment of a paste, as a string a filename can carry.\n *\n * ISO 8601 with its colons and the decimal point replaced, because both are\n * reserved in a filename on at least one platform a download lands on. Shared\n * by the two paste paths, so a pasted image and a long text pasted as a file\n * are named the same way.\n */\nfunction pasteStamp(): string {\n return new Date().toISOString().replace(/[:.]/g, \"-\");\n}\n\n/**\n * A pasted file, guaranteed to have a name.\n *\n * A file dropped or picked always carries one; a pasted one need not. Some\n * engines hand over a blob with an empty name, which travels all the way to\n * the upload as an empty `filename` and lands on the server as a file nobody\n * can identify -- while the chip in the tray shows an empty label. A file that\n * already has a name keeps it, including the generic one Chrome gives a pasted\n * screenshot: it is at least what the file is, and the chip shows the size\n * beside it.\n */\nfunction named(file: File): File {\n if (file.name !== \"\") {\n return file;\n }\n // The subtype is the extension for every clipboard image type worth naming.\n // A type with no slash in it falls back to the whole string, and an absent\n // one leaves a bare stamp rather than a name ending in a dot.\n const subtype = file.type.split(\"/\")[1] ?? file.type;\n const stamp = pasteStamp();\n return new File([file], subtype === \"\" ? `pasted-${stamp}` : `pasted-${stamp}.${subtype}`, {\n type: file.type,\n });\n}\n", "import { ICON_VOICE } from \"../../constants.js\";\nimport type { TranscribeHandler } from \"../../core/transcribe_audio.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\n\n/** Lifecycle of the mic button, reflected on its `data-state` for CSS. */\ntype VoiceState = \"idle\" | \"recording\" | \"transcribing\";\n\n/**\n * How long one recording may run before it stops itself.\n *\n * Two minutes is a ceiling, not a target: dictating into a chat composer is a\n * sentence or two, and two minutes of speech is roughly 350 words \u2014 longer than\n * any message this control is for. What it bounds is the case that has no end\n * at all, a mic left live in a forgotten tab: about a megabyte of accumulated\n * Opus, a recording indicator the user is no longer watching, and eventually a\n * multipart upload no client-side check sizes.\n *\n * Hitting it stops and transcribes; the audio is never discarded, because a cap\n * the user was not told about must not cost them the words they already spoke.\n */\nconst MAX_RECORDING_MS = 120_000;\n\n/** Construction options for {@link VoiceInput}. */\nexport interface VoiceInputOptions {\n /** Turns a recorded clip into text (the built-in or a custom transport). */\n readonly transcribe: TranscribeHandler;\n /** Called with the transcript when a recording transcribes successfully. */\n readonly onText: (text: string) => void;\n /** UI string table (labels/tooltips). */\n readonly strings?: UiStrings;\n}\n\n/**\n * The composer's voice-input control: a mic button that records via\n * `MediaRecorder`, then POSTs the clip through a {@link TranscribeHandler} and\n * hands the transcript back via `onText`.\n *\n * Click to start recording, which prompts for mic permission, and again to stop\n * and transcribe. The button reflects its `idle` / `recording` / `transcribing`\n * state on `data-state` for theming and is exposed as `part=\"voice-button\"`; a\n * capture or transcription failure returns it to idle and surfaces the message\n * on its tooltip.\n *\n * Pure DOM. The host mounts {@link element} in the input row.\n */\nexport class VoiceInput {\n /** The mic button; mount this in the composer. */\n readonly element: HTMLButtonElement;\n\n readonly #transcribe: TranscribeHandler;\n readonly #onText: (text: string) => void;\n readonly #strings: UiStrings;\n #state: VoiceState = \"idle\";\n #recorder: MediaRecorder | null = null;\n #stream: MediaStream | null = null;\n #chunks: Blob[] = [];\n #capTimer: ReturnType<typeof setTimeout> | null = null;\n #hitCap = false;\n #disposed = false;\n /** Identifies the newest start; an older one that settles is stale. */\n #startToken: object = {};\n\n constructor(options: VoiceInputOptions) {\n this.#transcribe = options.transcribe;\n this.#onText = options.onText;\n this.#strings = options.strings ?? DEFAULT_UI_STRINGS;\n\n this.element = document.createElement(\"button\");\n this.element.type = \"button\";\n this.element.className = \"voice-btn\";\n this.element.setAttribute(\"part\", \"voice-button\");\n // The mic glyph, in a slot so a host can project its own mark. Author-written\n // constant markup, never user or server data.\n const glyph = document.createElement(\"slot\");\n glyph.name = \"icon-voice\";\n glyph.innerHTML = ICON_VOICE;\n this.element.append(glyph);\n this.#setState(\"idle\");\n this.element.addEventListener(\"click\", () => {\n void this.toggle();\n });\n }\n\n /** Start recording when idle, stop (and transcribe) when recording. */\n async toggle(): Promise<void> {\n if (this.#state === \"recording\") {\n this.#stop();\n return;\n }\n if (this.#state === \"transcribing\") {\n return;\n }\n await this.#start();\n }\n\n async #start(): Promise<void> {\n // The button reads idle for the whole of the permission prompt, so a second\n // click during it is a second start. The latest click wins: this token is\n // replaced by every start, and whichever one settles while it is not the\n // newest is stale. It is a token and not an in-flight flag on purpose:\n // getUserMedia may never settle (a dismissed prompt), and a flag waiting\n // for it would leave the button dead until reload.\n const token = {};\n this.#startToken = token;\n let stream: MediaStream | null;\n try {\n stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n } catch {\n stream = null;\n }\n if (token !== this.#startToken || this.#disposed) {\n // Superseded by a later click, or the prompt outlived the control: the\n // element left, or user-key changed, while it was open. Whatever this\n // call was granted is released and nothing shared is touched: #stream,\n // #recorder and the cap timer belong to the newer start, and recording\n // now on a disposed control would light the browser's indicator for a\n // button nobody can see or stop (dispose has already run, so nothing\n // else would ever release these tracks). A refusal is dropped the same\n // way, so a click nobody is waiting on draws no error over the newer one.\n for (const track of stream?.getTracks() ?? []) {\n track.stop();\n }\n return;\n }\n if (stream === null) {\n this.#fail(this.#strings.transcriptionFailed);\n return;\n }\n this.#stream = stream;\n this.#chunks = [];\n this.#hitCap = false;\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorder(stream);\n recorder.addEventListener(\"dataavailable\", (event) => {\n this.#chunks.push(event.data);\n });\n recorder.addEventListener(\"stop\", () => {\n void this.#finish(recorder.mimeType);\n });\n this.#recorder = recorder;\n recorder.start();\n } catch {\n // A granted stream the browser will not record: one whose tracks have\n // already ended (Chromium throws NotSupportedError from start), a device\n // that went away between the grant and the start, or no MediaRecorder at\n // all. It is a refused mic by another route, so it ends the same way: the\n // tracks are released (the stream is already stored, and nothing else\n // would stop it), the button shows the failure, and nothing reaches the\n // click handler, which discards the promise. A recorder whose start threw\n // can still report \"recording\" and still holds its listeners, but #fail\n // clears #recorder, so neither #stop nor dispose can reach it and its stop\n // listener never runs #finish.\n this.#fail(this.#strings.transcriptionFailed);\n return;\n }\n // Nothing else ends a recording: `MediaRecorder` runs until it is told to\n // stop, so without this the only exits are a second click and `dispose()`.\n this.#capTimer = setTimeout(() => {\n this.#hitCap = true;\n this.#stop();\n }, MAX_RECORDING_MS);\n this.#setState(\"recording\");\n }\n\n #stop(): void {\n this.#clearCap();\n // ``stop`` flushes a final ``dataavailable`` then fires ``stop`` \u2192 #finish.\n this.#recorder?.stop();\n }\n\n /** Drop the cap timer; recording is over, by whichever route. */\n #clearCap(): void {\n if (this.#capTimer !== null) {\n clearTimeout(this.#capTimer);\n this.#capTimer = null;\n }\n }\n\n /**\n * Tear the control down, for a host element removed mid-recording or handed\n * to the next principal. Stops any live `MediaRecorder`, releases the mic\n * tracks so the browser's recording indicator clears, and suppresses the\n * pending transcription \u2014 a disconnected control must not fire `onText` into\n * a detached element.\n *\n * Disposal is final: nothing un-disposes an instance, and the host's next\n * wiring builds a new one. So the disposed flag alone tells a continuation\n * that outlived the control from a live one, and a clip already posted when this runs is\n * dropped whenever its answer arrives.\n */\n dispose(): void {\n this.#disposed = true;\n this.#clearCap();\n if (this.#recorder !== null && this.#recorder.state !== \"inactive\") {\n this.#recorder.stop();\n }\n this.#recorder = null;\n this.#releaseStream();\n }\n\n async #finish(mimeType: string): Promise<void> {\n if (this.#disposed) {\n return;\n }\n this.#releaseStream();\n this.#setState(\"transcribing\");\n const audio = new Blob(this.#chunks, { type: mimeType || \"audio/webm\" });\n try {\n const text = await this.#transcribe(audio);\n if (this.#disposed) {\n // Disposed while the clip was in flight. The check above ran before the\n // await and cannot see this: on a change of user-key the host disposes\n // and wires a fresh mic over the same composer, so delivering now\n // would put the previous principal's words in the next one's box.\n // The button is left as it was, too: it is no longer this control's\n // to change.\n return;\n }\n this.#setState(\"idle\");\n if (this.#hitCap) {\n // #setState has just reset the tooltip to the idle label, so this goes\n // after it. It says why the mic went quiet on its own \u2014 the transcript\n // below is the proof nothing was thrown away.\n this.element.title = fillUiString(this.#strings.recordingLimit, {\n n: MAX_RECORDING_MS / 60_000,\n });\n }\n if (text !== \"\") {\n this.#onText(text);\n }\n } catch (error) {\n this.#fail(error instanceof Error ? error.message : this.#strings.transcriptionFailed);\n } finally {\n this.#recorder = null;\n }\n }\n\n /** Stop the mic tracks so the browser's recording indicator clears. */\n #releaseStream(): void {\n for (const track of this.#stream?.getTracks() ?? []) {\n track.stop();\n }\n this.#stream = null;\n }\n\n #fail(message: string): void {\n // A transcription that fails can settle after dispose. (A refused prompt\n // cannot reach here that way: #start drops a stale or disposed refusal\n // before it calls this.) A disposed control has nothing to release and no\n // tooltip to draw.\n if (this.#disposed) {\n return;\n }\n this.#releaseStream();\n this.#recorder = null;\n this.#setState(\"idle\");\n this.element.title = message;\n }\n\n #setState(state: VoiceState): void {\n this.#state = state;\n this.element.dataset[\"state\"] = state;\n const label = this.#labelFor(state);\n this.element.title = label;\n this.element.setAttribute(\"aria-label\", label);\n this.element.setAttribute(\"aria-pressed\", String(state === \"recording\"));\n // The control is inert while a clip transcribes (no second recording yet).\n this.element.disabled = state === \"transcribing\";\n }\n\n #labelFor(state: VoiceState): string {\n if (state === \"recording\") {\n return this.#strings.stopRecording;\n }\n if (state === \"transcribing\") {\n return this.#strings.transcribing;\n }\n return this.#strings.recordVoice;\n }\n}\n", "import { type TranscribeHandler, transcribeAudio } from \"../../core/transcribe_audio.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { VoiceInput } from \"./voice_input.js\";\n\n/** What the composer's mic needs from the element that owns it. */\nexport interface ComposerVoiceHost {\n /** The custom element, whose `data-transcribe-url` names the built-in endpoint. */\n readonly element: HTMLElement;\n /** Where the mic button mounts, in the composer's tool row. */\n readonly slot: HTMLElement;\n /** The composer a transcript is written into. */\n readonly input: HTMLTextAreaElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** The host's `transcribeHandler`, read when the mic is wired. */\n readonly transcribeHandler: () => TranscribeHandler | null;\n /** The headers a request to `url` carries. */\n readonly headersFor: (url: string) => Record<string, string>;\n /** The cookie policy every request carries, when one is configured. */\n readonly credentialsOption: () => { credentials?: RequestCredentials };\n /** React to the composer's value changing, as typing does. */\n readonly onInput: () => void;\n}\n\n/**\n * The composer's mic: mounted when transcription is possible, and what a\n * transcript does to the composer.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ComposerVoice {\n readonly #host: ComposerVoiceHost;\n /** Voice-input control; created on connect when transcription is available. */\n #voice: VoiceInput | null = null;\n\n constructor(host: ComposerVoiceHost) {\n this.#host = host;\n }\n\n /**\n * Reveal the composer's \uD83C\uDFA4 mic button when transcription is possible \u2014 either\n * a custom `transcribeHandler` is set or `data-transcribe-url` provides the\n * built-in POST endpoint. The control records via `MediaRecorder` and drops\n * the transcript into the composer; with neither configured the mic stays\n * hidden and the chat is text-only.\n *\n * Called on every connect, so it starts by taking down the mic the last\n * connection mounted, which was released when the element left.\n */\n wire(): void {\n this.#voice?.element.remove();\n this.#voice = null;\n const url = this.#host.element.getAttribute(\"data-transcribe-url\");\n const transcribe = this.#host.transcribeHandler() ?? this.#defaultTranscribeHandler(url);\n if (transcribe === null) {\n return;\n }\n this.#voice = new VoiceInput({\n transcribe,\n onText: (text) => this.#insertText(text),\n strings: this.#host.strings(),\n });\n this.#host.slot.appendChild(this.#voice.element);\n }\n\n /** Release the mic, so the browser's recording indicator clears. */\n dispose(): void {\n this.#voice?.dispose();\n }\n\n /** The built-in transcription handler for `data-transcribe-url`, or `null`. */\n #defaultTranscribeHandler(url: string | null): TranscribeHandler | null {\n if (url === null) {\n return null;\n }\n return (audio) =>\n transcribeAudio(audio, {\n url,\n headers: this.#host.headersFor(url),\n ...this.#host.credentialsOption(),\n });\n }\n\n /** Drop a voice transcript into the composer (appended to any typed text). */\n #insertText(text: string): void {\n const input = this.#host.input;\n const current = input.value.trim();\n input.value = current === \"\" ? text : `${current} ${text}`;\n this.#host.onInput();\n input.focus();\n }\n}\n", "import type { Skill } from \"../../skills/skill.js\";\n\n/**\n * The two skill surfaces over a single catalog: a chips row (the `chip: true`\n * subset) and a slash-command palette (all skills, filtered). Both opt-in.\n * Pure DOM; the host appends {@link chips} and {@link palette}, feeds input via\n * {@link onInput} / {@link onKeydown}, and acts on {@link onPick}.\n */\nexport class SkillsMenu {\n /** Chips row \u2014 append above the input. Hidden unless chips are enabled and present. */\n readonly chips: HTMLDivElement;\n /** The `/`-command dropdown \u2014 append in the input area. Hidden until opened. */\n readonly palette: HTMLDivElement;\n\n readonly #onPick: (skill: Skill) => void;\n #skills: readonly Skill[] = [];\n #chipsEnabled = false;\n #slashEnabled = false;\n #filtered: Skill[] = [];\n #activeIndex = 0;\n\n constructor(onPick: (skill: Skill) => void) {\n this.#onPick = onPick;\n this.chips = document.createElement(\"div\");\n this.chips.className = \"skill-chips\";\n this.chips.setAttribute(\"part\", \"skill-chips\");\n this.chips.hidden = true;\n this.palette = document.createElement(\"div\");\n this.palette.className = \"skill-palette\";\n this.palette.setAttribute(\"part\", \"skill-palette\");\n this.palette.setAttribute(\"role\", \"listbox\");\n this.palette.hidden = true;\n }\n\n /** Replace the catalog (both surfaces re-derive from it). */\n setSkills(skills: readonly Skill[]): void {\n this.#skills = skills;\n this.#renderChips();\n }\n\n enableChips(enabled: boolean): void {\n this.#chipsEnabled = enabled;\n this.#renderChips();\n }\n\n enableSlash(enabled: boolean): void {\n this.#slashEnabled = enabled;\n }\n\n /** Whether the palette is currently open. */\n isOpen(): boolean {\n return !this.palette.hidden;\n }\n\n /**\n * React to an input value change: open + filter the palette when slash mode\n * is on and the value starts with `/`, otherwise close it.\n */\n onInput(value: string): void {\n if (this.#slashEnabled && value.startsWith(\"/\")) {\n this.#open(value.slice(1));\n } else {\n this.close();\n }\n }\n\n /**\n * Handle a keydown while the palette is open. Returns ``true`` when consumed\n * (the host should `preventDefault` and skip its own handling).\n */\n onKeydown(event: KeyboardEvent): boolean {\n if (!this.isOpen()) {\n return false;\n }\n if (event.key === \"ArrowDown\") {\n this.#move(1);\n return true;\n }\n if (event.key === \"ArrowUp\") {\n this.#move(-1);\n return true;\n }\n if (event.key === \"Escape\") {\n this.close();\n return true;\n }\n if (event.key === \"Enter\") {\n // `slice(i, i+1)` yields a 0-or-1 element array; forEach gives a\n // definite Skill (no indexed-access `| undefined`).\n this.#filtered.slice(this.#activeIndex, this.#activeIndex + 1).forEach((skill) => {\n this.#pick(skill);\n });\n return true;\n }\n return false;\n }\n\n /** Close the palette. */\n close(): void {\n this.palette.hidden = true;\n this.palette.replaceChildren();\n }\n\n #open(query: string): void {\n const needle = query.trim().toLowerCase();\n const matches = this.#skills.filter(\n (skill) =>\n skill.name.toLowerCase().includes(needle) || skill.title.toLowerCase().includes(needle),\n );\n if (matches.length === 0) {\n this.close();\n return;\n }\n this.#filtered = matches;\n this.#activeIndex = 0;\n this.#renderPalette();\n this.palette.hidden = false;\n }\n\n #move(delta: number): void {\n const count = this.#filtered.length;\n this.#activeIndex = (this.#activeIndex + delta + count) % count;\n this.#renderPalette();\n }\n\n #pick(skill: Skill): void {\n this.close();\n this.#onPick(skill);\n }\n\n #renderChips(): void {\n this.chips.replaceChildren();\n const chipSkills = this.#chipsEnabled\n ? this.#skills.filter((skill) => skill.chip === true)\n : [];\n this.chips.hidden = chipSkills.length === 0;\n for (const skill of chipSkills) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = \"skill-chip\";\n button.setAttribute(\"part\", \"skill-chip\");\n button.textContent = skill.title;\n // The chip stays a label \u2014 it is a one-click affordance, not something to\n // memorise \u2014 but naming the command it stands for makes the two\n // discoverable as the same thing.\n button.title = `/${skill.name}`;\n button.addEventListener(\"click\", () => this.#pick(skill));\n this.chips.appendChild(button);\n }\n }\n\n #renderPalette(): void {\n this.palette.replaceChildren();\n this.#filtered.forEach((skill, index) => {\n const item = document.createElement(\"button\");\n item.type = \"button\";\n item.className = \"skill-item\";\n item.setAttribute(\"part\", \"skill-item\");\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"aria-selected\", index === this.#activeIndex ? \"true\" : \"false\");\n\n const title = document.createElement(\"span\");\n title.className = \"skill-item-title\";\n title.setAttribute(\"part\", \"skill-item-title\");\n\n // The token leads, because it is the thing the user has to type. A row\n // showing only the label taught the label and not the command, so the\n // palette could not be used to learn its own vocabulary.\n const token = document.createElement(\"code\");\n token.className = \"skill-item-token\";\n token.setAttribute(\"part\", \"skill-item-token\");\n token.textContent = `/${skill.name}`;\n title.append(token, document.createTextNode(` ${skill.title}`));\n item.appendChild(title);\n\n if (skill.description !== undefined) {\n const desc = document.createElement(\"span\");\n desc.className = \"skill-item-desc\";\n desc.setAttribute(\"part\", \"skill-item-desc\");\n desc.textContent = skill.description;\n item.appendChild(desc);\n }\n\n item.addEventListener(\"click\", () => this.#pick(skill));\n this.palette.appendChild(item);\n });\n }\n}\n", "import type { UiStrings } from \"../ui_strings.js\";\nimport { attachQuoteOffer, type PageQuoteOffer } from \"./page_quote_offer.js\";\nimport { placeOffer } from \"./place_offer.js\";\nimport { asQuote, quotableSelection } from \"./quote_selection.js\";\n\n/** What the quote offer needs from the element that owns it. */\nexport interface TranscriptQuoteHost {\n /** The custom element: its opt-out attribute, and what a page offer excludes. */\n readonly element: HTMLElement;\n /** The shadow root a transcript selection is read through. */\n readonly root: ShadowRoot;\n /** The transcript, whose selections are offered. */\n readonly messages: HTMLElement;\n /** The transcript's positioning box, which the offer floats inside. */\n readonly messagesWrap: HTMLElement;\n /** The composer a quotation is written into. */\n readonly input: HTMLTextAreaElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Resize the composer to what it now holds. */\n readonly autoGrow: () => void;\n /** The element's public `quote`, so a host that replaced it is the one called. */\n readonly quote: (text: string) => void;\n}\n\n/**\n * Quoting a selection into the composer: the offer floated beside a selection\n * in the transcript, the same offer over the host page, and the quotation\n * itself.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class TranscriptQuoteOffer {\n /**\n * Offer to quote the current selection, floated beside it.\n *\n * Shares the transcript's positioning box with the jump button for the same\n * reason: it is positioned against the transcript, and must not scroll away\n * with the words it is pointing at.\n */\n readonly button: HTMLButtonElement = document.createElement(\"button\");\n\n readonly #host: TranscriptQuoteHost;\n /** What {@link button} would quote, while it is showing. */\n #quoting = \"\";\n /** The host-page offer, while one is attached; see {@link offerInPage}. */\n #pageQuote: PageQuoteOffer | null = null;\n\n constructor(host: TranscriptQuoteHost) {\n this.#host = host;\n }\n\n /** The quotation behind `AgUiChat.quote`, whose doc is the contract. */\n insert(text: string): void {\n const quoted = asQuote(text);\n if (quoted === \"\") {\n return;\n }\n const input = this.#host.input;\n // Appended after whatever is already typed, on a fresh paragraph: a second\n // quotation is a second thing being asked about, not a replacement for the\n // first. Trailing blank lines are dropped so repeated quoting does not\n // accumulate gaps.\n const current = input.value.replace(/\\s+$/, \"\");\n input.value = current === \"\" ? quoted : `${current}\\n\\n${quoted}`;\n this.#host.autoGrow();\n input.focus();\n const end = input.value.length;\n input.setSelectionRange(end, end);\n }\n\n /** The offer behind `AgUiChat.offerQuoteInPage`, whose doc is the contract. */\n offerInPage(within: HTMLElement): () => void {\n this.#pageQuote?.detach();\n const offer = attachQuoteOffer({\n within,\n label: this.#host.strings().quoteSelection,\n exclude: this.#host.element,\n onQuote: (text) => this.#host.quote(text),\n });\n this.#pageQuote = offer;\n return () => {\n offer.detach();\n if (this.#pageQuote === offer) {\n this.#pageQuote = null;\n }\n };\n }\n\n /**\n * Take the host-page offer down. It listens on the host's document, not on\n * anything of ours, so nothing else would ever take it down.\n */\n detachPageOffer(): void {\n this.#pageQuote?.detach();\n this.#pageQuote = null;\n }\n\n /**\n * Build the offer and listen for settled selections in the transcript.\n *\n * The button and the transcript outlive a connection, so the listeners go\n * under `signal`, which the element aborts when it leaves the document.\n */\n mount(signal: AbortSignal): void {\n const button = this.button;\n button.className = \"quote-selection\";\n button.type = \"button\";\n button.setAttribute(\"part\", \"quote-selection\");\n button.textContent = this.#host.strings().quoteSelection;\n button.hidden = true;\n // `mousedown` rather than `click`: pressing anywhere else collapses the\n // selection first, and by the time a click lands there is nothing left to\n // quote. Preventing the default keeps the selection alive long enough to\n // read it.\n button.addEventListener(\n \"mousedown\",\n (event) => {\n event.preventDefault();\n },\n { signal },\n );\n button.addEventListener(\n \"click\",\n () => {\n this.#host.quote(this.#quoting);\n window.getSelection()?.removeAllRanges();\n this.#hide();\n },\n { signal },\n );\n\n // A settled selection, by either input. `mouseup` rather than\n // `selectionchange` so the offer does not chase the pointer mid-drag; the\n // second half of the same gesture, `mousedown`, retires the previous offer\n // before the new selection exists.\n const messages = this.#host.messages;\n messages.addEventListener(\"mouseup\", (event) => this.#onSelectionSettled(event), { signal });\n messages.addEventListener(\"keyup\", () => this.#onSelectionSettled(), { signal });\n messages.addEventListener(\"mousedown\", () => this.#hide(), { signal });\n }\n\n /** Whether the transcript offers to quote what the user selects. */\n #enabled(): boolean {\n return this.#host.element.getAttribute(\"data-quote-selection\") !== \"false\";\n }\n\n /**\n * Offer to quote the settled selection, or retire the offer.\n *\n * `event` is passed for its coordinates and only those: they say which line\n * of a selection spanning several messages the offer should hang from. A\n * keyboard selection has none, and the first line is used instead.\n */\n #onSelectionSettled(event?: MouseEvent): void {\n if (!this.#enabled()) {\n return;\n }\n const near = event === undefined ? undefined : { x: event.clientX, y: event.clientY };\n const selected = quotableSelection(this.#host.messages, [this.#host.root], near);\n if (selected === null) {\n this.#hide();\n return;\n }\n this.#quoting = selected.text;\n placeOffer(this.button, selected.rect, this.#host.messagesWrap.getBoundingClientRect());\n }\n\n /** Retire the offer, and forget what it was pointing at. */\n #hide(): void {\n this.button.hidden = true;\n this.#quoting = \"\";\n }\n}\n", "import { randomUUID } from \"@ag-ui/client\";\nimport { contentToText, type Message } from \"@ag-ui/core\";\nimport { MESSAGE_ROLE, TOOL_CALL_STATUS, TOOL_OUTCOME } from \"../../constants.js\";\nimport type { ActivityRegistry } from \"../../core/activity_registry.js\";\nimport type { AgUiClient } from \"../../core/agui_client.js\";\nimport { messageAttachments } from \"../../core/attachment.js\";\nimport type { ClientSeed } from \"../../core/client_seed.js\";\nimport type {\n ClientConversationStore,\n NavigationCheckpoint,\n ThreadMeta,\n} from \"../../core/conversation_store.js\";\nimport type { ThreadDetail } from \"../../core/events/thread_detail.js\";\nimport type { MessageRole } from \"../../core/message_role.js\";\nimport { RunIndex } from \"../../core/run_index.js\";\nimport { toolStatusFromOutcome } from \"../../core/tool_outcome.js\";\nimport { answerUnansweredCalls, metadataOrTopLevel, mintThread } from \"../../core/utils.js\";\nimport type { ToolCatalog } from \"../../tools/tool_catalog.js\";\nimport type { AnswerActions } from \"../transcript/answer_actions.js\";\nimport { renderAttachmentChips } from \"../transcript/attachment_chips.js\";\nimport type { Transcript } from \"../transcript/transcript.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport type { CheckpointMenu, CheckpointVerb } from \"./checkpoint_menu.js\";\nimport type { RelativeTimeFormatter } from \"./relative_time.js\";\nimport type { ThreadDrawer } from \"./thread_drawer.js\";\n\n/** What conversation history needs from the element that owns it. */\nexport interface ConversationHistoryHost {\n /**\n * The custom element: the attributes history reads and stamps, and the\n * `this` a host's `agentFactory` and `navigationResult` are called with.\n */\n readonly element: HTMLElement;\n /** The conversation list, which the element builds and renders. */\n readonly drawer: ThreadDrawer;\n /** The checkpoint panel, which the element builds and renders. */\n readonly checkpoints: CheckpointMenu;\n /** The transcript a restored conversation is replayed into. */\n readonly transcript: Transcript;\n /** The action row under each finished answer. */\n readonly actions: AnswerActions;\n /** The activity renderers, which redraw a restored activity. */\n readonly activities: ActivityRegistry;\n /** The frontend tools, whose renderers a restored call is redrawn with. */\n readonly tools: ToolCatalog;\n /** The composer, whose text a continuation sends. */\n readonly input: HTMLTextAreaElement;\n /** The one-line hint above the composer. */\n readonly hint: HTMLDivElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** The element's `conversationStore`, read per use. */\n readonly conversationStore: () => ClientConversationStore;\n /** The element's `formatRelativeTime`. */\n readonly formatRelativeTime: () => RelativeTimeFormatter | null;\n /** The element's `navigationResult`. */\n readonly navigationResult: () => (checkpoint: NavigationCheckpoint) => unknown;\n /** The request headers, having first reported the destination if it is foreign. */\n readonly headersFor: (url: string) => Record<string, string>;\n /** The configured cookie policy as `fetch` spells it. */\n readonly requestCredentials: () => RequestCredentials | undefined;\n /** The element's `appendMessage`, which a restored bubble opens through. */\n readonly appendMessage: (role: MessageRole, content: string) => HTMLDivElement;\n /**\n * Draw a turn the user sent and dispatch the submit event, as the element's\n * own send does before it starts a run.\n */\n readonly announceTurn: (content: string) => void;\n /**\n * Record a turn taken from the composer for arrow-key recall, as the\n * element's own send records one.\n */\n readonly recordTurn: (content: string) => void;\n /** Resize the composer to its content. */\n readonly autoGrow: () => void;\n /**\n * A continuation has ended, whether or not it ever ran.\n *\n * The composer parks a turn typed while one is in flight, and learns a run\n * has settled from its own events -- which never arrive for a continuation\n * that failed before starting one. Without this, such a turn stayed parked\n * with nothing left to release it.\n */\n readonly continuationEnded: () => void;\n /** The conversation's own client, or `null` until one is built. */\n readonly client: () => AgUiClient | null;\n /** The conversation's own client, built on first use. */\n readonly ensureClient: () => AgUiClient;\n /**\n * A client from the same construction as the conversation's own, differing\n * only in what `seed` says. A continuation's comes from here so that nothing\n * added to one can be missing from the other.\n */\n readonly buildClient: (seed: ClientSeed) => AgUiClient;\n /**\n * Forget the conversation's own client, so the next one is built from\n * {@link ConversationHistory.restored}. Nothing is cancelled: this is for a\n * client that is not running.\n */\n readonly releaseClient: () => void;\n /**\n * Whether an interaction is in flight, which the composer owns: from the\n * moment a send or a retry is taken, or a restore starts loading, not only\n * once its run has started.\n */\n readonly running: () => boolean;\n /**\n * Hold the composer as a send holds it from the moment it is taken: the\n * built-in Send parks its turn, a Retry and a pick refuse. Let go of when the\n * run starts, by a Stop, or by {@link RunHold.release}.\n *\n * A host's send refuses too, unless `restored` is given: then the hold is a\n * restore's with no run to resume, and a host's send waits for `restored` to\n * settle and sends after it, with the conversation drawn. `restored` settles\n * once that restore has ended, or has been stopped, and never rejects.\n */\n readonly holdRun: (restored: Promise<void> | null) => RunHold;\n /** Stop the in-flight run. */\n readonly cancelRun: () => void;\n /** Drop the in-memory run and transcript, leaving the thread untouched. */\n readonly resetState: () => void;\n /** Swap the composer between Send and Stop, which the composer owns. */\n readonly setRunning: (running: boolean) => void;\n /**\n * Say the conversation on screen changed, once its transcript is replaced.\n * The element fills in the thread it replaced, which it last reported.\n */\n readonly threadChanged: (threadId: string, reason: ThreadDetail[\"reason\"]) => void;\n /** Hear the rows the conversation list was just given, for the title on screen. */\n readonly threadsListed: (threads: readonly ThreadMeta[]) => void;\n /** A thread was deleted, so whatever the element kept about it goes too. */\n readonly threadDeleted: (threadId: string) => void;\n}\n\n/**\n * A hold {@link ConversationHistoryHost.holdRun} took.\n *\n * It says nothing about whether the restore that took it was stopped. A\n * restore asks its generation that, because a host's send that waited on a\n * restore with no run to resume takes the hold over from it, and a restore\n * stopped by a newer one finds that one's hold in its place -- see\n * {@link ConversationHistory.rehydrate}.\n */\ninterface RunHold {\n /**\n * Let go, if nothing else has, and send what the composer parked behind it,\n * because no run is going to settle and send it.\n */\n readonly release: () => void;\n}\n\n/**\n * The conversation a restore set out to restore: which restore, by its\n * generation, and the store and thread it reads.\n */\ninterface RestoreClaim {\n readonly generation: number;\n readonly store: ClientConversationStore;\n readonly threadId: string;\n}\n\n/**\n * Which conversation is on screen, and how one gets there: restoring it from\n * the store, switching to another from the conversation list, and continuing\n * a run from the checkpoint panel.\n *\n * The one writer of the active thread's id and of the messages a restore\n * seeded the next client with. The element reads both when it builds its\n * client, and asks for a transition -- adopt the store's thread, mint a new\n * one -- rather than writing either. Clearing the run, the transcript and the\n * composer around a transition stays the element's, because it spans every\n * part of it; history calls back for that.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ConversationHistory {\n readonly #host: ConversationHistoryHost;\n /** The active thread's id. Empty until the element connects. */\n #threadId = \"\";\n /**\n * The conversation as last written for the next client the element builds to\n * start from: what the last restore replayed, or what a checkpoint\n * continuation last saved after it. Emptied with the rest of the in-memory run.\n */\n #restored: readonly Message[] = [];\n /**\n * Counts the conversations cleared away, so a continuation can tell whether\n * the one it continued is still on screen when it saves.\n */\n #cleared = 0;\n /**\n * Which restore may draw: bumped by every rehydrate, and by every clear of\n * the conversation on screen. A restore whose generation is stale draws\n * nothing more and resumes nothing: a newer one has started, or New chat, a\n * thread switch or a `user-key` handover has cleared what it was restoring.\n */\n #generation = 0;\n /**\n * The conversation the latest restore claimed, written by every restore as\n * it starts; `null` before the first. It speaks for the restore now current\n * only while its generation is the current one, because clearing the\n * conversation moves that on. See `#forgetStopped` for the one reader.\n */\n #claim: RestoreClaim | null = null;\n /** Built lazily from `data-runs-url`; `null` when the host didn't opt in. */\n #runIndex: RunIndex | null = null;\n /**\n * The checkpoint continuation in flight, so stopping the conversation's run\n * reaches it. `null` when none is running.\n */\n #continuation: AgUiClient | null = null;\n /**\n * Settles what a host's send waits on while the restore now current, one\n * with no run to resume, loads and replays; `null` when no such restore is\n * under way. Called when that restore ends, and as soon as it is stopped by\n * anything that moves the generation, so a send waiting on a conversation\n * that is no longer on screen hears so at once rather than when an\n * abandoned load answers.\n *\n * Also what tells a pick refused for a load from one refused for a run.\n */\n #loading: (() => void) | null = null;\n /** The thread switch under way and the promise that settles it, or `null`. */\n #switching: { readonly threadId: string; readonly done: Promise<void> } | null = null;\n\n constructor(host: ConversationHistoryHost) {\n this.#host = host;\n }\n\n /** The active thread's id. */\n get threadId(): string {\n return this.#threadId;\n }\n\n /** The conversation as last written, for seeding the next client. */\n get restored(): readonly Message[] {\n return this.#restored;\n }\n\n /** The checkpoint continuation in flight, or `null` when none is running. */\n get continuation(): AgUiClient | null {\n return this.#continuation;\n }\n\n /** Point at the thread the store says is active. */\n adoptActiveThread(): void {\n this.#threadId = this.#host.conversationStore().threadId();\n }\n\n /** Make a freshly minted thread the active one. */\n startThread(): void {\n this.#threadId = mintThread(this.#host.conversationStore());\n }\n\n /**\n * Stop the checkpoint continuation in flight, if there is one.\n *\n * A continuation runs on a client of its own, which the element never held,\n * so Stop cancelled the conversation's client and left this one streaming:\n * the button read Stop and did nothing, and New chat, a thread switch or\n * removing the element carried on drawing the resumed answer into whatever\n * came next. The element calls this wherever it stops its own run.\n */\n stopContinuation(): void {\n this.#continuation?.cancel();\n this.#continuation = null;\n }\n\n /** Forget the messages the last restore seeded, with the rest of the run. */\n forgetRestored(): void {\n this.#restored = [];\n // The element clears the conversation through here, so a continuation\n // still saving afterwards learns the conversation is no longer this one.\n this.#cleared += 1;\n // A restore still loading or replaying must stop too, or New chat during a\n // slow load would draw the conversation being left into the new one and hand\n // it to the new chat's client as its history.\n this.#generation += 1;\n // A host's send waiting on that restore is addressed to the conversation\n // just cleared. The element's Stop has let go of it already; this wakes it\n // to find so, rather than leaving it waiting on a load nobody wants -- for\n // good, if that load never answers. The drop tests in\n // `ag_ui_chat_send_during_restore.test.ts` hang without it.\n this.#endWait();\n }\n\n /** Settle what waits on the restore now loading, if anything does, and forget it. */\n #endWait(): void {\n const end = this.#loading;\n this.#loading = null;\n end?.();\n }\n\n /** Delete the active thread if nothing was ever sent in it. */\n reapUnsent(): void {\n // A thread nothing was ever sent in has nothing to come back to, and the\n // drawer never listed it \u2014 so reap it here rather than strand one record\n // per press of a button whose whole use is being pressed again.\n if (this.#host.conversationStore().isUnsent?.(this.#threadId) === true) {\n this.#host.conversationStore().clear(this.#threadId);\n }\n }\n\n /** The run index, built once from `data-runs-url`; `null` when unset. */\n runs(): RunIndex | null {\n const url = this.#host.element.getAttribute(\"data-runs-url\");\n if (url === null || url === \"\") {\n return null;\n }\n if (this.#runIndex === null) {\n this.#runIndex = new RunIndex(\n url,\n () => this.#host.headersFor(url),\n () => this.#host.requestCredentials(),\n );\n }\n return this.#runIndex;\n }\n\n /** Open the conversation list, dismissing the checkpoint panel. */\n openThreads(): void {\n // Two overlapping surfaces, so opening one dismisses the other. Clicking away\n // already covers the built-in buttons, but a host driving its own chrome\n // through these methods raises no pointer event \u2014 and the drawer would then\n // open *underneath* a popover still floating over it.\n this.#host.checkpoints.close();\n void this.refreshDrawer();\n this.#host.drawer.open();\n }\n\n /** Open the checkpoint panel, dismissing the conversation list. */\n openCheckpoints(): void {\n // The other half of the pair \u2014 see `openThreads`.\n this.#host.drawer.close();\n void this.#refreshCheckpoints();\n this.#host.checkpoints.open();\n }\n\n /**\n * Switch the active conversation to an existing thread and replay it.\n *\n * A call for the thread a switch is already loading is handed that switch's\n * own promise, so it settles when the thread is drawn rather than at once,\n * before the replay.\n *\n * A store that rejects the load leaves the element on the thread it was on:\n * the switch has already cleared the transcript, so it points back at the\n * old thread and draws it again, saying nothing, and then rejects with the\n * store's error. Left as it was, the element named a thread it was not\n * showing and never reported it.\n */\n switchThread(threadId: string): Promise<void> {\n if (threadId === this.#threadId) {\n return this.#switching?.threadId === threadId ? this.#switching.done : Promise.resolve();\n }\n const previous = this.#threadId;\n const done = this.#switchTo(threadId, previous).finally(() => {\n if (this.#switching === entry) {\n this.#switching = null;\n }\n });\n const entry = { threadId, done };\n this.#switching = entry;\n return done;\n }\n\n async #switchTo(threadId: string, previous: string): Promise<void> {\n this.#host.cancelRun();\n this.#host.resetState();\n this.#host.conversationStore().setActiveThread(threadId);\n this.#threadId = threadId;\n this.#host.setRunning(false);\n try {\n await this.rehydrate(\"switch\");\n } catch (error) {\n // Only while this switch is still the one on screen: a newer switch, a\n // new chat or a delete has moved the thread on, and undoing that would\n // put the old one back over it.\n if (this.#threadId === threadId) {\n this.#threadId = previous;\n this.#host.conversationStore().setActiveThread(previous);\n // Drawn again without a word: the thread on screen is the one the last\n // event reported, so there is nothing to tell a host. A store that\n // cannot answer for it either leaves the screen as it is.\n await this.rehydrate(null).catch(() => undefined);\n }\n throw error;\n }\n }\n\n /** Rename a thread, then reload the list that shows its title. */\n renameThread(threadId: string, title: string): void {\n this.#host.conversationStore().renameThread(threadId, title);\n void this.refreshDrawer();\n }\n\n /** Delete a thread; if it was the active one, fall back to a fresh chat. */\n deleteThread(threadId: string): void {\n const wasActive = threadId === this.#threadId;\n if (wasActive) {\n this.#host.cancelRun();\n }\n this.#host.conversationStore().clear(threadId);\n this.#host.threadDeleted(threadId);\n if (wasActive) {\n this.#host.resetState();\n this.adoptActiveThread();\n this.#host.setRunning(false);\n // No replay to wait for: the thread that took its place is a fresh one.\n this.#host.threadChanged(this.#threadId, \"delete\");\n }\n void this.refreshDrawer();\n }\n\n /** Reload the drawer's thread list, marking the active thread. */\n async refreshDrawer(): Promise<void> {\n this.#host.drawer.setRelativeTimeFormatter(this.#host.formatRelativeTime());\n const threads = await this.#host.conversationStore().listThreads();\n this.#host.drawer.setThreads(threads, this.#threadId);\n this.#host.threadsListed(threads);\n }\n\n /** Load the checkpoint panel with the runs that can actually be continued. */\n async #refreshCheckpoints(): Promise<void> {\n const index = this.runs();\n // Pushed at render rather than at connect: `formatRelativeTime` is a\n // property, so a host may set it long after the element mounted.\n this.#host.checkpoints.setRelativeTimeFormatter(this.#host.formatRelativeTime());\n this.#host.checkpoints.setRuns(index === null ? [] : await index.continuable());\n }\n\n /**\n * Continue `runId` as a **new** run, seeded server-side from its snapshot.\n *\n * Uses a short-lived agent pointed at the resume / fork endpoint and seeded\n * with no history, because those endpoints supply the prior turns from the\n * snapshot and re-sending them would duplicate. A separate agent makes that\n * structural and mints the fresh `run_id` the endpoints also require.\n *\n * Built by the same construction as the conversation's own client, so the\n * continuation streams into the same transcript the user is looking at and\n * runs under the same state, tools and bounds. It is the run in flight while\n * it lasts: {@link stopContinuation} is how the element's Stop reaches it.\n *\n * What it adds joins the conversation. Its saves write the conversation on\n * screen ahead of its exchange, and each one hands that whole list to the\n * next client the element builds, so the next ordinary message is sent with\n * the exchange it follows. The conversation's own client never held it, and\n * was sending without it.\n */\n async continueRun(runId: string, verb: CheckpointVerb): Promise<void> {\n const index = this.runs();\n if (index === null) {\n // Unreachable from the built-in control: the header button is only\n // rendered when `runs()` is configured, so a row to pick cannot exist\n // without one. A host calling `openCheckpoints()` regardless gets the\n // documented empty panel, which has no rows either. Typed, not silent.\n return;\n }\n if (this.#host.running() || this.#continuation !== null) {\n // Refused rather than started beside it. The panel opens and its rows\n // take a pick while a run streams, and a second run would draw its answer\n // into the turn still arriving; a second continuation would also replace\n // the one Stop reaches, leaving the first streaming where nothing could\n // end it. Nor is the earlier run cancelled for it: a pick in a panel is not\n // a Stop, and what is streaming may be the answer the user is waiting on.\n //\n // Both checks, because they see different things. `running` is the\n // composer's own state: it spans every round of an interaction, from the\n // moment a send or a retry is taken rather than from its run's first\n // event, which is a microtask behind it. A continuation is not the\n // composer's, and is recorded here the moment it starts.\n //\n // Said at the composer, as an empty composer is below, because the row\n // closed the panel before this ran. The typed turn stays where it is --\n // it is what the user wants sent once the run is done -- and the caret\n // goes back to it, where Escape stops the run.\n //\n // A restore with no run to resume holds the composer too, and there is\n // no answer to wait for and nothing Escape can stop, so it says the\n // conversation is still loading instead. A restore that will resume a\n // run keeps the running wording: what it is loading is that run.\n const strings = this.#host.strings();\n this.#refuse(\n this.#loading === null ? strings.continueWhileRunning : strings.continueWhileLoading,\n );\n return;\n }\n const content = this.#host.input.value.trim();\n if (content === \"\") {\n // A continuation sends *only* the next turn -- the snapshot supplies\n // everything before it -- so with an empty composer there is nothing to\n // send. Returning here was the same failure the endpoint guard above had:\n // the row's button closes the panel before this runs, so the widget\n // visibly reacted and then did nothing, which reads as a resume that was\n // attempted and lost rather than one that never started.\n //\n // Said at the composer rather than in the transcript, because that is\n // where the fix goes and because the hint clears itself on the first\n // keystroke -- a transcript notice for a recoverable slip would outlive\n // the slip. Focus follows for the same reason applying a skill moves it when\n // a template is short of a field.\n this.#refuse(this.#host.strings().continueNeedsTurn);\n return;\n }\n // Typed in the composer and sent by a press, so it is recallable as any\n // other turn is. Recorded as it leaves the box, where the element's own\n // send records one, rather than once it is sent: the box is empty from\n // here, and a continuation that fails before its run starts has still\n // taken the turn out of it.\n this.#host.recordTurn(content);\n this.#host.input.value = \"\";\n this.#host.autoGrow();\n const cleared = this.#cleared;\n const client = this.#host.buildClient({\n endpoint: verb === \"resume\" ? index.resumeUrl(runId) : index.forkUrl(runId),\n // The seed the endpoints assume: nothing. The snapshot is the history.\n initialMessages: [],\n // What its saves write ahead of the exchange: the conversation on screen,\n // in the form the store holds it. From the conversation's own client when\n // there is one, because that client keeps how each call ended beside its\n // messages rather than on them; otherwise what the last restore or\n // continuation wrote, which is already in that form.\n //\n // All of it, even where this forks an earlier run and the server's\n // snapshot stops there: what is saved is what the screen shows.\n follows: this.#host.client()?.messages ?? this.#restored,\n onSaved: (conversation) => {\n // A continuation stopped by New chat or a thread switch saves once its\n // request closes, into its own thread; the conversation now on screen\n // is not the one it continued.\n if (cleared !== this.#cleared) {\n return;\n }\n // The conversation's own client holds the conversation without this\n // exchange, and would send it that way. Released rather than patched:\n // the next client is built from this list exactly as a reload builds\n // one from the store, outcomes included.\n //\n // Nothing can run on the released client in between, because the\n // composer refuses to start one while a continuation is in flight --\n // it parks the turn instead. It said here that only a script in the\n // same task could, which was wrong by a whole request: `running` does\n // not turn on until the continuation's first event, and a person who\n // typed in that window got a second run against the snapshot\n // `follows` had already frozen, so whichever saved last dropped the\n // other's turn.\n this.#restored = conversation;\n this.#host.releaseClient();\n },\n });\n this.#continuation = client;\n try {\n // Drawn and announced as the element's own send does, because this is\n // the same act sent somewhere else. Without the bubble the answer arrived\n // under no question, while the save below wrote the turn, so a reload\n // showed what the live transcript never had.\n //\n // The submit event fires too. A host listens to it as \"the user sent\n // something\", which a continued turn is: typed in the composer and sent\n // by a press. Only the endpoint differs, and the host chose that when it\n // configured the panel; leaving it out would make a host's own record of\n // the conversation miss exactly the turns this panel exists to add.\n //\n // Only once the continuation is recorded, because a listener runs here:\n // a host's own send from it is refused as overlapping the run in flight,\n // as it would be from any later moment of this one.\n this.#host.announceTurn(content);\n // A listener can also have stopped it: New chat, a thread switch, or\n // moving the element all reach the stop. That cancelled a client whose\n // run had not begun, and a run resets its own cancellation when it\n // starts, so sending now would start one that nothing holds and nothing\n // can stop -- in a conversation the user has already left, with its\n // tools still driving the page.\n if (this.#continuation !== client) {\n return;\n }\n await client.send(content);\n } finally {\n // Only if it is still the one in flight: stopping forgets it at once, and\n // a continuation started after that one is not this one to forget.\n //\n // In a finally because the send can fail before its run ever starts. The\n // first save goes through the host's `conversationStore` synchronously\n // inside it, and a store is the host's to replace: the built-in one\n // swallows a write the browser refused, a server-backed one need not. A\n // throw there left this pointing at a client that would never run, so\n // every later pick was refused with no Stop to clear it -- the composer's\n // button is Send until a run reports a start -- and `#liveClient` went on\n // handing that dead client the shared state a host wrote.\n if (this.#continuation === client) {\n this.#continuation = null;\n this.#host.continuationEnded();\n }\n }\n }\n\n /**\n * Say at the composer why a picked run did not continue, and put the caret\n * there. The hint clears itself on the next keystroke.\n */\n #refuse(reason: string): void {\n this.#host.hint.textContent = reason;\n this.#host.hint.hidden = false;\n this.#host.input.focus();\n }\n\n /**\n * Restore the conversation from the store on mount, then \u2014 if a navigating\n * tool reloaded the page mid-run \u2014 resume the loop by supplying that tool's\n * result from the page we landed on.\n *\n * Any other call the stored run left unanswered is answered on the way in, as\n * not finished, because no run is left to answer it.\n *\n * **What the store holds after a reload mid-run.** The run loop persists a\n * round when its stream ends, which is *before* it asks about a gated call,\n * runs a frontend tool, or collects a server-side approval. A reload in that\n * window leaves the round's calls stored with no result, and the request that\n * would have produced one died with the page.\n *\n * **Why not finished, and not declined.** Stop declines an open card because\n * pressing it is a person answering the question. A reload answers nothing, and\n * the stored shape is the same whether the round waited on a person or on a\n * handler the reload killed, so declined would be unproven for the first and\n * false for the second. A marker saved while a card is open could tell them\n * apart, but every host store would have to round-trip it, and a store that\n * dropped it would fall back to this wording anyway -- which is true of both.\n *\n * The answers come from the same helper the client runs before each request,\n * so a restored card and the result the next request carries cannot disagree.\n * Giving them to the replay, rather than leaving the client to add them, is\n * what settles each card from its result. The checkpointed call is excluded,\n * because the resume path answers it from the page the reload landed on; that\n * exclusion is held by \"resumes with the landed page's result, and its card says\n * so\" in `ag_ui_chat_reload_mid_run.test.ts`.\n *\n * **Every restore holds the composer from before the load.** Until the\n * store answers, the conversation's client can only be seeded from nothing.\n * With a remote store that is a real request, and a send, a Retry or a pick\n * in it was refused by nothing: each built the conversation's client before\n * the conversation had loaded, so a send went out carrying none of it, its\n * first save replaced the stored one, and the replay then drew the stored\n * conversation under the new turn. The client stayed cached without it, so\n * every later turn went out without it too. So the composer is held as a\n * send holds it: what was typed parks and goes out after the replay, and a\n * Retry and a pick are refused -- a Retry has nothing on screen to retry, and\n * after the load it would re-ask the previous visit's last question.\n *\n * **A host's send waits for a restore with no run to resume.** It is\n * usually a prompt fired as the element mounts, which no host could time\n * against a load nothing announces, and refusing it would lose the turn.\n * So it waits for this restore to end, taking the hold over as it does,\n * and then sends with the conversation drawn above it; what the built-in\n * Send parked goes out after its run. Stopped while it waits, it is dropped,\n * as a send stopped by its own submit listener is.\n *\n * **A restore that resumes refuses a host's send instead.** The resume is a\n * run, and the restore ends by starting it, so a send that waited would only\n * reach that run and be refused there. The resume gives way to nothing: what\n * was typed parks behind the resumed run and goes out after its answer.\n *\n * The other way round, the resume standing down for the send, was rejected.\n * The send that got in first had already gone out without the conversation,\n * so standing down kept that loss, and it also dropped the run the navigation\n * was part of, which the user asked for before the reload: the agent stopped\n * halfway through the task, with the navigating call never answered.\n *\n * **A restore stops where it was stopped, held or not.** New chat, a thread\n * switch, a `user-key` handover, a newer restore or the element leaving the\n * page can each come while the store answers, and from host code the restore\n * runs itself: the activity and tool renderers each replayed message draws\n * through, and `navigationResult`. From then on it draws nothing more and\n * resumes nothing. The hold cannot say so, because a host's send that\n * waited may hold it by then. So the restore asks its generation, which clearing\n * the conversation moves on as a newer restore does, and asks it after the\n * load, after each replayed message -- as a Retry asks after each one -- and\n * once more before the resume. Stopped by anything but the element leaving\n * the page, it also forgets the checkpoint it loaded, since that was a Stop\n * for the run it would have resumed -- unless what replaced it is a restore\n * of the same conversation, still current, which answers for that run\n * instead; see `#forgetStopped`.\n *\n * `reason` is what the thread event this restore ends with reports as why\n * the conversation changed. A restore that is stopped reports nothing, and\n * neither does one given `null`, which draws the thread already reported.\n */\n async rehydrate(reason: ThreadDetail[\"reason\"] | null): Promise<void> {\n // Claimed before awaiting, and checked by `#restoring` wherever the restore\n // has waited or run host code. With a slow remote store, picking thread B\n // then C interleaved both replays into one transcript, and New chat drew\n // the conversation being left into the new one.\n this.#generation += 1;\n const generation = this.#generation;\n // Read before the load rather than after it, because a checkpoint means\n // this restore ends by starting a run, and the window a send could start a\n // second one in is the load, not the resume -- see \"A restore that resumes\"\n // above. The store's checkpoint is synchronous and the built-in remote store\n // keeps it in this tab, so nothing the load fetches can change it. And\n // before the replay, which has to know the one unanswered call a reload was\n // *expected* by, so as not to settle it as abandoned.\n //\n // The thread and the store are taken once, here, because a restore that is\n // stopped forgets its checkpoint where it read it: by then the active\n // thread can be a new chat's, and the store scoped to the next principal.\n const threadId = this.#threadId;\n const store = this.#host.conversationStore();\n // Claimed with the generation, store and thread just taken, whether or not\n // there is a checkpoint: a restore of the same conversation that finds none\n // has found it resumed or forgotten already, so an older one has nothing\n // left there to forget. Claiming only with a checkpoint would differ only\n // where one was written after this restore started, which an older restore\n // should not wipe either, so no test tells the two apart. See\n // `#claimedByCurrent`.\n this.#claim = { generation, store, threadId };\n const checkpoint = store.loadCheckpoint(threadId);\n // What a host's send waits on, for a restore with no run to resume, and\n // the hold either kind takes. Taken before the load for the same reason\n // the checkpoint is read before it: the load is the window.\n //\n // No earlier wait is left to settle here: every restore but the first\n // follows a clear of the conversation on screen -- a reload, a thread\n // switch, a handover, the element coming back -- and `forgetRestored`\n // settled and forgot it then. So a restore that will resume finds none.\n const restored =\n checkpoint === null\n ? new Promise<void>((resolve) => {\n this.#loading = resolve;\n })\n : null;\n const waiting = this.#loading;\n const hold = this.#host.holdRun(restored);\n try {\n // Held while the store answers. A remote store answers after first paint,\n // and a conversation it is still fetching is more likely to have messages\n // than not, so without this the page would paint the greeting and a centred\n // composer and then drop the composer the moment they land. The built-in\n // store answers in a microtask, before paint, so for it this never reaches\n // the screen. Released in `finally` so a store that rejects cannot leave the\n // layout held for good, and only by the restore that is still current.\n this.#host.element.setAttribute(\"data-restoring\", \"\");\n let messages: readonly Message[] | null;\n try {\n messages = await store.loadMessages(threadId);\n } finally {\n if (generation === this.#generation) {\n this.#host.element.removeAttribute(\"data-restoring\");\n }\n }\n // Stopped while the store answered. Going on drew the conversation being\n // left into the chat that replaced it, and resumed its run there, on a\n // client seeded from what the restore had just drawn.\n if (!this.#restoring(generation)) {\n this.#forgetStopped(store, threadId, checkpoint);\n return;\n }\n if (messages !== null) {\n const unfinished = this.#host.strings().callNotFinished;\n const restored = answerUnansweredCalls(\n messages,\n // The shape the store holds for a call the client answered the same\n // way: its tool message, with the outcome in its metadata.\n (toolCallId) => ({\n id: randomUUID(),\n role: \"tool\",\n content: unfinished,\n toolCallId,\n metadata: { outcome: TOOL_OUTCOME.INTERRUPTED },\n }),\n new Set(checkpoint === null ? [] : [checkpoint.toolCallId]),\n );\n this.#restored = restored;\n for (const message of restored) {\n this.replay(message);\n // A replay draws through the host's activity and tool renderers,\n // which can stop the restore as well as anything outside it can.\n // Checked after each one, as a Retry checks, so the rest of the\n // conversation being left is not drawn into the chat that replaced it,\n // and after the last, so its run is not resumed there.\n if (!this.#restoring(generation)) {\n this.#forgetStopped(store, threadId, checkpoint);\n return;\n }\n }\n }\n if (checkpoint === null) {\n this.#noticeIfRunUnfinished(messages);\n }\n // Said once the transcript is the restored one, and only by a restore\n // still current: one that was stopped returned above, so two quick\n // switches report the second alone. Before a resume, because the resume\n // is a run, and waiting for it reported the change a whole answer late.\n if (reason !== null) {\n this.#host.threadChanged(threadId, reason);\n }\n if (checkpoint !== null) {\n // A listener is host code, and can stop the restore as a replayed\n // renderer can. Resuming then answered the call into the conversation\n // that replaced it, and left the checkpoint for a later visit to resume.\n if (!this.#restoring(generation)) {\n this.#forgetStopped(store, threadId, checkpoint);\n return;\n }\n await this.#resumeFrom(checkpoint, generation);\n }\n } finally {\n // The resumed run starting has let go of the hold already, as a send's\n // does, and a request that then fails still started one: the client\n // reports a run before it sends. Still held here only if none started --\n // the store rejected the load, or the store or the host threw on the way\n // to the resume -- and then this is what sends a turn the composer parked\n // meanwhile, since no run is going to settle and send it.\n //\n // A host's send that waited on this restore has taken the hold over, so\n // the release does nothing and the send goes first; what was parked goes\n // out after its run. Woken only after the replay, here, rather than when\n // the store answers, or its turn would be drawn above the conversation.\n // Only this restore's wait: one that was stopped was woken by what\n // stopped it, and the wait now current, if any, is a newer restore's.\n // Waking that one here sent its turn before its conversation was drawn,\n // which \"drops the waiting send on a drawer switch, and a send then\n // carries the picked thread\" in `ag_ui_chat_send_during_restore.test.ts`\n // holds.\n hold.release();\n if (this.#loading === waiting) {\n this.#endWait();\n }\n }\n }\n\n /**\n * Whether the restore that claimed `generation` may go on: nothing has\n * replaced or cleared the conversation it is restoring, and the element is\n * still on the page.\n *\n * On the page, because leaving it is the one stop that clears nothing: the\n * element is not reset until it connects again, and connecting restores the\n * conversation afresh. A restore with nothing to resume went on regardless,\n * drawing into a node that had gone and running the host's renderers for it.\n * One that resumes learnt it from the Stop letting go of its hold; nothing\n * asks the hold that now, so this is what keeps the resume's request in.\n *\n * One `&&`, so coverage cannot tell whether either half is held. Removing the\n * generation fails \"draws nothing into a new chat started while it loads\" in\n * `conversation_history.test.ts`, and \"drops a stale thread replay when a\n * newer switch started\" in `ag_ui_chat.test.ts`; removing the connection\n * fails \"draws nothing into an element that left the page while it loads\".\n */\n #restoring(generation: number): boolean {\n return generation === this.#generation && this.#host.element.isConnected;\n }\n\n /**\n * Forget the checkpoint a stopped restore loaded, when what stopped it also\n * stopped the run it was about to resume.\n *\n * New chat, a thread switch, a `user-key` handover and a newer restore all\n * move the generation, and each is a Stop for that run. Left in the store,\n * the checkpoint outlived the Stop: coming back to the conversation later\n * resumed the navigating call with whatever page was current by then.\n * Forgotten, the call is answered as not finished there, as any stopped call\n * is.\n *\n * Not while the restore now current claimed the same conversation, which it\n * has in two cases. It is this restore, when only the element left the page,\n * which moves no generation: a move or a framework re-render is not a\n * farewell, and the restore connecting starts has to find the checkpoint to\n * resume from. Or it is a newer restore of the same thread in the same store\n * -- `reload()`, switching away and back, or the element connecting again --\n * which read the checkpoint as it started, or found it gone, and answers for\n * it from then on: its resume clears it, and when it is stopped in turn this\n * same rule decides.\n *\n * A newer restore's case does not forget it: if the element leaves the page\n * while the newer one loads, that one stands down keeping the checkpoint for\n * the reconnect, and a store that no longer held it would leave no run to resume.\n *\n * Written to the store and the thread it was read from. After a handover\n * that is the previous principal's: the built-in store's clear is a removal\n * from a namespace the handover has already purged, so it changes nothing,\n * and nothing reaches the next principal's. A host's store is the same object\n * either side of a handover; one the host replaced is held by \"still refuses\n * a send for the newer restore once the older has stood down\".\n *\n * Two conditions. Clearing with no checkpoint fails \"draws nothing into a new\n * chat started while it loads\", which runs no store code for one. Clearing\n * what the current restore claimed fails \"resumes nothing once the element\n * leaves the page while the store answers\", where the claim is this\n * restore's own and the re-inserted element resumes, and \"resumes once the\n * element is back when the host reloads and it then leaves the page\", where\n * it is the reload's. The claim's own three are named on `#claimedByCurrent`.\n */\n #forgetStopped(\n store: ClientConversationStore,\n threadId: string,\n checkpoint: NavigationCheckpoint | null,\n ): void {\n if (checkpoint !== null && !this.#claimedByCurrent(store, threadId)) {\n store.saveCheckpoint(threadId, null);\n }\n }\n\n /**\n * Whether the restore now current claimed the conversation a stopped restore\n * read its checkpoint from: the same thread, in the same store.\n *\n * A claim from an earlier generation speaks for nobody: the conversation was\n * cleared after it was made, so whatever it would have resumed was stopped,\n * and that holds of a stopped restore's own claim as much as of any other.\n * The store is compared as an object, because a store the host assigned\n * since is a different record of the conversation, and the one the\n * checkpoint was read from still has to forget it.\n *\n * As an object, a store the element builds for itself -- the built-in one\n * under a namespace, and the remote one `data-threads-url` wraps around it\n * -- is a different one after a reconnect, which builds it afresh over the\n * same storage, so a restore from before the reconnect forgets the\n * checkpoint there once it answers. The reconnect's own restore read it as\n * it started and resumes from that copy, as a newer restore always did here;\n * what that copy cannot survive is the element leaving again before the\n * load answers.\n *\n * One `&&` of three, so coverage cannot tell whether any is held. Dropping\n * the generation fails \"forgets the checkpoint when New chat stops the\n * resume, so the call ends as not finished\", where the claim is the stopped\n * restore's own; dropping the store fails \"still refuses a send for the newer\n * restore once the older has stood down\", whose host replaces the store\n * between the two; dropping the thread fails \"forgets the checkpoint of a\n * thread switched away from, though the next has one of its own\".\n */\n #claimedByCurrent(store: ClientConversationStore, threadId: string): boolean {\n const claim = this.#claim;\n return (\n claim?.generation === this.#generation && claim.store === store && claim.threadId === threadId\n );\n }\n\n /**\n * Notice a previous run that never produced a response.\n *\n * {@link AgUiClient.send} persists the user's message before starting the\n * run, so a transcript ending on that user message means nothing came back.\n * The transcript's shape alone detects it, needing no store method and no\n * `pagehide` listener \u2014 neither of which fires on a crash or force-quit.\n *\n * An agent-initiated reload is not this case: a navigating tool leaves a\n * checkpoint and resumes, so the caller returns early on one.\n *\n * Deliberately a notice, never a resume. AG-UI has no resume-an-aborted-run\n * primitive, and re-sending the accumulated messages is semantically a new\n * run, so any server-side tool already executed would run a second time.\n */\n #noticeIfRunUnfinished(messages: readonly Message[] | null): void {\n const last = messages?.at(-1);\n if (last === undefined || last.role !== MESSAGE_ROLE.USER) {\n return;\n }\n this.#host.transcript.appendNotice(\"\u26A0\", this.#host.strings().runInterrupted, \"interrupted\");\n }\n\n /**\n * Replay a restored message: text bubbles *and* tool activity. An assistant\n * turn may carry `toolCalls` (rendered as cards) and/or text; a `tool` turn\n * carries a result that settles the matching card. So a refreshed page shows\n * the full transcript \u2014 tool calls and their results \u2014 not just the prose.\n */\n replay(message: Message): void {\n const text = typeof message.content === \"string\" ? message.content : \"\";\n if (message.role === MESSAGE_ROLE.USER) {\n const attachments = messageAttachments(message);\n if (text !== \"\" || attachments.length > 0) {\n const bubble = this.#host.appendMessage(MESSAGE_ROLE.USER, text);\n if (attachments.length > 0) {\n bubble.appendChild(renderAttachmentChips(attachments));\n }\n }\n return;\n }\n if (message.role === MESSAGE_ROLE.ASSISTANT) {\n if (text !== \"\") {\n // Restored history must appear statically \u2014 entrance animations\n // (fade / word) are for freshly-arriving messages. On reload the whole\n // transcript mounts at once, so animating every bubble's text in\n // parallel looks wrong. Mark it so the fade CSS skips it, and don't\n // wrap words.\n const restoredBubble = this.#host.appendMessage(MESSAGE_ROLE.ASSISTANT, text);\n restoredBubble.classList.add(\"message--restored\");\n // The stored id, which is the streamed one wherever the store kept\n // it. A Retry re-renders the turns it keeps through here too, so a\n // kept answer stays the message it was. No run id: a stored message\n // does not carry one.\n //\n // Narrowed rather than trusted, like the fields below: a host store or\n // a `data-threads-url` server can return a message with no id, and a\n // rating that names nothing is a pair of buttons that lead nowhere.\n // Such an answer keeps its copy and loses only the rating.\n const id: unknown = message.id;\n this.#host.actions.attach(\n restoredBubble,\n typeof id === \"string\" && id !== \"\" ? { messageId: id } : { rateable: false },\n );\n }\n // Narrowed rather than trusted, for the same reason `messageAttachments`\n // narrows the neighbouring field: anything that throws in this loop aborts\n // the replay at this message, and every later turn silently disappears from\n // the transcript. See `restoredToolCalls`.\n for (const call of restoredToolCalls(message.toolCalls)) {\n const restored = {\n id: call.id,\n name: call.function.name,\n args: this.#parseArgs(call.function.arguments),\n };\n // Restored history goes through the same interception as the live\n // stream \u2014 otherwise a reload resurrects the raw `load_capability`\n // card the live path deliberately replaced.\n if (this.#host.transcript.noticeIfSkillLoad(restored)) {\n continue;\n }\n this.#host.transcript.setCardElement(\n restored.id,\n this.#host.transcript.cardFor(restored).element,\n );\n // Only `render` is replayed, never `handler`. A restored transcript\n // redraws what the call drew; it must not re-run what the call *did*.\n // Only the renderer is handed over, never the tool. The guarantee that\n // a reload cannot re-run a tool's *effect* is worth more than a comment\n // saying so: this signature cannot reach `handler`, so a later\n // maintainer adding a \"no render? fall back to the handler\" convenience\n // here has to change the type first, which is exactly the moment the\n // question should be asked.\n const render = this.#host.tools.resolve(restored.name)?.render;\n if (render !== undefined) {\n this.#host.transcript.renderToolOutput(render, restored);\n }\n }\n return;\n }\n if (message.role === \"activity\") {\n // The client materialises a pushed activity as a message of its own, so a\n // chart's data is in the transcript already and survives a reload. Only\n // the drawing had to be put back.\n const activity = message as unknown as { activityType?: unknown; content?: unknown };\n if (typeof activity.activityType === \"string\") {\n this.#host.activities.draw(message.id, activity.activityType, activity.content);\n }\n return;\n }\n if (message.role === \"tool\") {\n const card = this.#host.transcript.card(message.toolCallId);\n if (card !== undefined) {\n // The outcome in the message's metadata -- folded there from a server's\n // result by `@ag-ui/client`, or written there by `AgUiClient` for a\n // result it made itself -- read back through the same mapping the live\n // path uses, so a card that said \"declined\" before the reload still\n // says it after. History stored by an earlier release has it at the\n // top level instead, which is read when the metadata has none. Narrowed\n // off `unknown` rather than trusted, like every other field read out of\n // the store: metadata is open by key, a host store may not round-trip\n // it, and history written before outcomes existed has none. All three\n // land on DONE, which is what this line did unconditionally.\n card.settle(\n toolStatusFromOutcome(metadataOrTopLevel(message, \"outcome\")),\n // Flattened exactly as the live path flattens it, so a reload shows\n // the card the user watched settle.\n contentToText(message.content),\n );\n }\n }\n }\n\n /** Parse a tool call's JSON `arguments` from history into an object. */\n #parseArgs(raw: unknown): Record<string, unknown> {\n if (typeof raw !== \"string\") {\n // A restored call whose `arguments` are missing or not a string still has\n // a name worth showing, so this renders an empty-args card rather than\n // dropping the card.\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed === \"object\" && parsed !== null) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Malformed history \u2014 fall back to empty args rather than failing replay.\n }\n return {};\n }\n\n /**\n * Complete the checkpointed navigating tool call and continue the run.\n *\n * The call's card is settled here, from the result the continuation carries.\n * The restore left it open on purpose -- it is the one call a reload was\n * expected by -- and nothing after this answers it: the run that follows\n * streams no result for a call the client answered itself. Left open, it\n * spun through the whole continuation, and the sweep that closes a run then\n * found it pending and called it not finished -- on the one call known to\n * have finished, since the page it moved to is the page doing the asking.\n *\n * Settled from the string the stored message holds, and with no outcome,\n * since `addToolResult` writes none, so the card is the one a later reload\n * draws from that message. The card can be missing, when the stored\n * transcript does not hold the call -- a store that kept the checkpoint and\n * lost the turn that made it -- and then there is nothing to settle. That\n * guard is held by \"resumes a checkpointed navigating tool call on mount\" in\n * `ag_ui_chat.test.ts`, whose transcript never made the call.\n */\n async #resumeFrom(checkpoint: NavigationCheckpoint, generation: number): Promise<void> {\n this.#host.conversationStore().saveCheckpoint(this.#threadId, null);\n const client = this.#host.ensureClient();\n // Called on the element, as `this.navigationResult(...)` always was.\n const landed = JSON.stringify(\n this.#host.navigationResult().call(this.#host.element, checkpoint),\n );\n // The store's save and `navigationResult` are host code, and either can\n // have stopped the restore. Going on answered the call and resumed anyway:\n // on the client taken before `navigationResult` ran, which nothing held any\n // more, with its tools still driving the page -- or, stopped by the save, on\n // the new chat's own client, which the line above had just built.\n if (!this.#restoring(generation)) {\n return;\n }\n client.addToolResult(checkpoint.toolCallId, landed);\n this.#host.transcript.card(checkpoint.toolCallId)?.settle(TOOL_CALL_STATUS.DONE, landed);\n await client.resume();\n }\n}\n\n/** One tool call as a restored assistant message carries it. */\ninterface RestoredToolCall {\n readonly id: string;\n readonly function: { readonly name: string; readonly arguments?: unknown };\n}\n\n/**\n * The tool calls a restored assistant turn carries, with anything shapeless dropped.\n *\n * Narrowing here rather than trusting the declared type, for three reasons that\n * point the same way.\n *\n * **`null` is a value this field really takes.** `@ag-ui/core` types `toolCalls`\n * as optional (`z.ZodOptional`), so TypeScript offers only `undefined` \u2014 but the\n * protocol's Python models declare `tool_calls: list[ToolCall] | None`, and a\n * server dumping them without `exclude_none` sends `null`. The two SDKs disagree\n * about the wire, and a client cannot afford to take either one's word for it.\n *\n * **A throw here costs the rest of the transcript.** This runs inside the replay\n * of stored history, one message at a time; an exception aborts the whole replay,\n * so a single bad entry silently truncates the conversation from that point on \u2014\n * with no error state and nothing on screen to explain the gap.\n *\n * **Storage is untrusted anyway** \u2014 hand-edited, truncated, written by an older\n * version, or supplied by a host's own store. `messageAttachments` already takes\n * exactly this stance for the neighbouring field on the same message.\n */\nfunction restoredToolCalls(value: unknown): readonly RestoredToolCall[] {\n return Array.isArray(value) ? value.filter(isRestoredToolCall) : [];\n}\n\n/** Whether an unknown history entry has enough shape to render a tool card. */\nfunction isRestoredToolCall(value: unknown): value is RestoredToolCall {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const call = value as { id?: unknown; function?: { name?: unknown } };\n return typeof call.id === \"string\" && typeof call.function?.name === \"string\";\n}\n", "import type { ThreadMeta } from \"../../core/conversation_store.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\nimport { type RelativeTimeFormatter, relativeTime } from \"./relative_time.js\";\nimport { openerElement } from \"./utils.js\";\n\n/**\n * How many conversations there have to be before the filter appears.\n *\n * A search box above a list you can already read in one glance is a control\n * asking to be used on nothing.\n */\nexport const FILTER_FROM = 8;\n\n/**\n * When the search box shows: from {@link FILTER_FROM} conversations (`auto`),\n * over any list (`always`), or not at all (`never`).\n */\nexport type ThreadsSearch = \"auto\" | \"always\" | \"never\";\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** Actions the host ({@link AgUiChat}) wires to the drawer's rows. */\nexport interface ThreadDrawerCallbacks {\n /** A row was picked \u2014 load that thread and make it active. */\n readonly onSelect: (threadId: string) => void;\n /** The \"New chat\" action \u2014 start a fresh thread. */\n readonly onNew: () => void;\n /** A row was renamed to `title`. */\n readonly onRename: (threadId: string, title: string) => void;\n /** A row was deleted (after the inline confirm). */\n readonly onDelete: (threadId: string) => void;\n}\n\n/**\n * The chat-history drawer: a slide-over listing the user's threads (title,\n * relative time, preview), with select / new / rename / delete actions and an\n * empty state. Pure DOM, like {@link SkillsMenu}: the host appends\n * {@link element}, toggles it, feeds rows via {@link setThreads}, and acts on\n * the callbacks.\n *\n * A view only \u2014 it never mutates the store. After a callback the host updates\n * the store and calls {@link setThreads} to refresh. All visible text comes\n * from {@link UiStrings}; {@link setStrings} re-localizes a drawer built before\n * its strings resolved.\n */\nexport class ThreadDrawer {\n /** The drawer root (backdrop + panel). Append to the chat shell; hidden until opened. */\n readonly element: HTMLDivElement;\n\n readonly #callbacks: ThreadDrawerCallbacks;\n readonly #panel: HTMLDivElement;\n readonly #heading: HTMLSpanElement;\n readonly #newButton: HTMLButtonElement;\n readonly #list: HTMLDivElement;\n #formatRelativeTime: RelativeTimeFormatter | null = null;\n #strings: UiStrings;\n #threads: readonly ThreadMeta[] = [];\n #activeId = \"\";\n /** Dismisses the list without starting a new conversation. */\n #closeButton: HTMLButtonElement;\n /** Narrows the list. Only rendered once there is enough of a list to narrow. */\n #filter: HTMLInputElement;\n /** The current filter text, lowercased once rather than per row. */\n #query = \"\";\n #search: ThreadsSearch = \"auto\";\n\n /** The element focused before the drawer opened, restored on close. */\n #lastFocused: HTMLElement | null = null;\n\n constructor(callbacks: ThreadDrawerCallbacks, strings: UiStrings = DEFAULT_UI_STRINGS) {\n this.#callbacks = callbacks;\n this.#strings = strings;\n\n this.element = document.createElement(\"div\");\n this.element.className = \"drawer\";\n this.element.setAttribute(\"part\", \"drawer\");\n this.element.hidden = true;\n\n const backdrop = document.createElement(\"div\");\n backdrop.className = \"drawer-backdrop\";\n backdrop.setAttribute(\"part\", \"drawer-backdrop\");\n backdrop.addEventListener(\"click\", () => this.close());\n\n this.#panel = document.createElement(\"div\");\n this.#panel.className = \"drawer-panel\";\n this.#panel.setAttribute(\"part\", \"drawer-panel\");\n this.#panel.setAttribute(\"role\", \"dialog\");\n this.#panel.setAttribute(\"aria-modal\", \"true\");\n this.#panel.setAttribute(\"aria-label\", strings.chatHistory);\n // Escape closes the drawer; Tab is trapped within the panel while it's open.\n this.#panel.addEventListener(\"keydown\", (event) => this.#onPanelKeydown(event));\n\n const header = document.createElement(\"div\");\n header.className = \"drawer-header\";\n header.setAttribute(\"part\", \"drawer-header\");\n this.#heading = document.createElement(\"span\");\n this.#heading.className = \"drawer-title\";\n this.#heading.setAttribute(\"part\", \"drawer-title\");\n this.#heading.textContent = strings.chats;\n this.#newButton = document.createElement(\"button\");\n this.#newButton.type = \"button\";\n this.#newButton.className = \"drawer-new\";\n this.#newButton.setAttribute(\"part\", \"drawer-new\");\n this.#newButton.textContent = strings.newChat;\n this.#newButton.addEventListener(\"click\", () => {\n this.close();\n this.#callbacks.onNew();\n });\n // An explicit way back. The backdrop closes on click, which is enough\n // wherever a strip of it is showing -- but the embedded placement widens\n // the panel to the full width of the host's box, so there is no backdrop\n // left to hit and the only exits were Escape, picking a row, or starting a\n // new conversation. The first is invisible and the last is destructive of\n // the thing you were looking at.\n this.#closeButton = document.createElement(\"button\");\n this.#closeButton.type = \"button\";\n this.#closeButton.className = \"drawer-close\";\n this.#closeButton.setAttribute(\"part\", \"drawer-close\");\n this.#closeButton.title = strings.closeHistory;\n this.#closeButton.setAttribute(\"aria-label\", strings.closeHistory);\n this.#closeButton.append(document.createTextNode(\"\\u00d7\"));\n this.#closeButton.addEventListener(\"click\", () => this.close());\n header.append(this.#heading, this.#newButton, this.#closeButton);\n\n // Hidden until the list is long enough to be worth narrowing. A search box\n // above four conversations is a control asking to be used on something\n // already entirely visible.\n this.#filter = document.createElement(\"input\");\n this.#filter.type = \"search\";\n this.#filter.className = \"drawer-filter\";\n this.#filter.setAttribute(\"part\", \"drawer-filter\");\n this.#filter.placeholder = strings.searchConversations;\n this.#filter.setAttribute(\"aria-label\", strings.searchConversations);\n this.#filter.addEventListener(\"input\", () => {\n this.#query = this.#filter.value.trim().toLowerCase();\n this.#renderList();\n });\n\n this.#list = document.createElement(\"div\");\n this.#list.className = \"drawer-list\";\n this.#list.setAttribute(\"part\", \"drawer-list\");\n\n this.#panel.append(header, this.#filter, this.#list);\n this.element.append(backdrop, this.#panel);\n }\n\n /** Re-localize the drawer's chrome and rows (the host calls this on connect). */\n /**\n * Replace the timestamp formatter, or restore the built-in with `null`.\n *\n * The built-in is deliberately locale-neutral -- there is no `Intl` anywhere\n * in this component, so it never disagrees with a host's own formatting by\n * guessing a locale. That is a defensible default and a poor requirement, so\n * this is the way out.\n */\n setRelativeTimeFormatter(format: RelativeTimeFormatter | null): void {\n this.#formatRelativeTime = format;\n }\n\n /** This row's timestamp, through the host's formatter when it set one. */\n #formatTime(timestamp: number): string {\n return this.#formatRelativeTime !== null\n ? this.#formatRelativeTime(timestamp)\n : relativeTime(timestamp, undefined, this.#strings);\n }\n\n setStrings(strings: UiStrings): void {\n this.#strings = strings;\n this.#panel.setAttribute(\"aria-label\", strings.chatHistory);\n this.#heading.textContent = strings.chats;\n this.#newButton.textContent = strings.newChat;\n this.#closeButton.title = strings.closeHistory;\n this.#closeButton.setAttribute(\"aria-label\", strings.closeHistory);\n this.#filter.placeholder = strings.searchConversations;\n this.#filter.setAttribute(\"aria-label\", strings.searchConversations);\n this.#renderList();\n }\n\n isOpen(): boolean {\n return !this.element.hidden;\n }\n\n open(): void {\n if (this.isOpen()) {\n return;\n }\n // Remember what had focus so it's restored on close, then move focus into\n // the panel (its first control) so keyboard users land inside the dialog.\n this.#lastFocused = openerElement(\n this.element.getRootNode() as Document | ShadowRoot,\n ) as HTMLElement | null;\n this.element.hidden = false;\n this.#newButton.focus();\n }\n\n close(): void {\n if (!this.isOpen()) {\n return;\n }\n this.element.hidden = true;\n this.#lastFocused?.focus();\n this.#lastFocused = null;\n }\n\n toggle(): void {\n if (this.isOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /** The currently-focused element within the drawer's root (shadow-aware). */\n #activeElement(): Element | null {\n return (this.element.getRootNode() as Document | ShadowRoot).activeElement;\n }\n\n /** Escape-to-close and a Tab focus trap while the dialog is open. */\n #onPanelKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n event.preventDefault();\n this.close();\n return;\n }\n if (event.key !== \"Tab\") {\n return;\n }\n const focusables = Array.from(\n this.#panel.querySelectorAll<HTMLElement>(\"button, input, [tabindex]\"),\n ).filter((el) => !el.hidden);\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = this.#activeElement();\n if (event.shiftKey && active === first) {\n event.preventDefault();\n last?.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first?.focus();\n }\n }\n\n /** Choose when the search box shows; the host's `data-threads-search`. */\n setSearchMode(mode: ThreadsSearch): void {\n this.#search = mode;\n this.#renderList();\n }\n\n /** Render the rows (or the empty state), highlighting the active thread. */\n setThreads(threads: readonly ThreadMeta[], activeId: string): void {\n this.#threads = threads;\n this.#activeId = activeId;\n this.#renderList();\n }\n\n #renderList(): void {\n this.#list.replaceChildren();\n const hideFilter =\n this.#search === \"auto\" ? this.#threads.length < FILTER_FROM : this.#search === \"never\";\n this.#filter.hidden = hideFilter;\n // Cleared as it goes, or the query outlives the control that set it: a\n // list that drops below the threshold while a query matches nothing shows\n // \"no conversations match that\" over conversations that are right there,\n // with nothing left on screen to clear. Reopening does not help either --\n // only a new drawer would.\n if (hideFilter && this.#query !== \"\") {\n this.#filter.value = \"\";\n this.#query = \"\";\n }\n const shown = this.#matching();\n if (shown.length === 0) {\n const empty = document.createElement(\"div\");\n empty.className = \"drawer-empty\";\n empty.setAttribute(\"part\", \"drawer-empty\");\n // Two different situations wearing one sentence would be a small lie:\n // \"no conversations yet\" reads as data loss when what happened is that a\n // filter matched nothing.\n empty.textContent =\n this.#threads.length === 0 ? this.#strings.noConversations : this.#strings.noMatches;\n this.#list.appendChild(empty);\n return;\n }\n const groups = this.#groups(shown);\n for (const [label, metas] of groups) {\n // One group would label the whole list, which says nothing the rows do not.\n if (groups.length > 1) {\n const heading = document.createElement(\"div\");\n heading.className = \"drawer-group-label\";\n heading.setAttribute(\"part\", \"drawer-group-label\");\n heading.setAttribute(\"role\", \"heading\");\n heading.setAttribute(\"aria-level\", \"3\");\n heading.textContent = label;\n this.#list.appendChild(heading);\n }\n for (const meta of metas) {\n this.#list.appendChild(this.#renderRow(meta));\n }\n }\n }\n\n /**\n * The rows by age from local midnight, in list order within each group, empty\n * groups dropped. A date that does not parse is never today, so it lands in Older.\n */\n #groups(shown: readonly ThreadMeta[]): [string, ThreadMeta[]][] {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n const recent: ThreadMeta[] = [];\n const week: ThreadMeta[] = [];\n const older: ThreadMeta[] = [];\n for (const meta of shown) {\n const at = meta.updatedAt;\n (at >= today ? recent : at >= today - 7 * DAY_MS ? week : older).push(meta);\n }\n const groups: [string, ThreadMeta[]][] = [\n [this.#strings.threadsToday, recent],\n [this.#strings.threadsPreviousWeek, week],\n [this.#strings.threadsOlder, older],\n ];\n return groups.filter(([, metas]) => metas.length > 0);\n }\n\n /**\n * The rows the filter leaves.\n *\n * Title and preview both, because the title is often the model's summary of\n * a conversation and the thing being looked for is as likely to be a phrase\n * from inside it. Client-side over what the drawer already holds: the server\n * index is fetched whole, so a query would be a round trip to filter a list\n * already in memory.\n */\n #matching(): readonly ThreadMeta[] {\n if (this.#query === \"\") {\n return this.#threads;\n }\n return this.#threads.filter(\n (meta) =>\n meta.title.toLowerCase().includes(this.#query) ||\n meta.preview.toLowerCase().includes(this.#query),\n );\n }\n\n #renderRow(meta: ThreadMeta): HTMLDivElement {\n const row = document.createElement(\"div\");\n row.className = \"drawer-row\";\n row.setAttribute(\"part\", \"drawer-row\");\n if (meta.threadId === this.#activeId) {\n row.classList.add(\"drawer-row--active\");\n }\n\n const select = document.createElement(\"button\");\n select.type = \"button\";\n select.className = \"drawer-row-select\";\n select.setAttribute(\"part\", \"drawer-row-select\");\n const title = document.createElement(\"span\");\n title.className = \"drawer-row-title\";\n title.setAttribute(\"part\", \"drawer-row-title\");\n title.textContent = meta.title;\n const time = document.createElement(\"span\");\n time.className = \"drawer-row-time\";\n time.setAttribute(\"part\", \"drawer-row-time\");\n time.textContent = this.#formatTime(meta.updatedAt);\n const preview = document.createElement(\"span\");\n preview.className = \"drawer-row-preview\";\n preview.setAttribute(\"part\", \"drawer-row-preview\");\n preview.textContent = meta.preview;\n select.append(title, time, preview);\n select.addEventListener(\"click\", () => {\n this.close();\n this.#callbacks.onSelect(meta.threadId);\n });\n\n const rename = document.createElement(\"button\");\n rename.type = \"button\";\n rename.className = \"drawer-row-rename\";\n rename.setAttribute(\"part\", \"drawer-row-rename\");\n rename.title = this.#strings.rename;\n rename.setAttribute(\"aria-label\", this.#strings.renameConversation);\n rename.textContent = \"\u270E\";\n rename.addEventListener(\"click\", () => this.#startRename(row, meta));\n\n const remove = document.createElement(\"button\");\n remove.type = \"button\";\n remove.className = \"drawer-row-delete\";\n remove.setAttribute(\"part\", \"drawer-row-delete\");\n remove.title = this.#strings.delete;\n remove.setAttribute(\"aria-label\", this.#strings.deleteConversation);\n remove.textContent = \"\uD83D\uDDD1\";\n remove.addEventListener(\"click\", () => this.#confirmDelete(row, meta));\n\n const actions = document.createElement(\"div\");\n actions.className = \"drawer-row-actions\";\n actions.setAttribute(\"part\", \"drawer-row-actions\");\n actions.append(rename, remove);\n\n row.append(select, actions);\n return row;\n }\n\n /** Swap a row for an inline rename input; Enter/blur commits, Escape cancels. */\n #startRename(row: HTMLDivElement, meta: ThreadMeta): void {\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = \"drawer-rename-input\";\n input.setAttribute(\"part\", \"drawer-rename-input\");\n input.value = meta.title;\n // One-shot: Enter, Escape, and blur can all fire for a single edit (Enter\n // commits and re-renders, which blurs the detached input); the flag makes\n // the later events no-ops so a rename isn't submitted twice.\n let done = false;\n const commit = (): void => {\n if (done) {\n return;\n }\n done = true;\n const value = input.value.trim();\n if (value === \"\" || value === meta.title) {\n this.#renderList();\n } else {\n this.#callbacks.onRename(meta.threadId, value);\n }\n };\n const cancel = (): void => {\n if (done) {\n return;\n }\n done = true;\n this.#renderList();\n };\n input.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n commit();\n } else if (event.key === \"Escape\") {\n // Stop the panel's Escape handler from also closing the drawer.\n event.preventDefault();\n event.stopPropagation();\n cancel();\n }\n });\n input.addEventListener(\"blur\", () => commit());\n row.replaceChildren(input);\n input.focus();\n input.select();\n }\n\n /** Swap a row for an inline \"Delete? [Delete] [Cancel]\" confirm. */\n #confirmDelete(row: HTMLDivElement, meta: ThreadMeta): void {\n const confirm = document.createElement(\"div\");\n confirm.className = \"drawer-confirm\";\n confirm.setAttribute(\"part\", \"drawer-confirm\");\n const label = document.createElement(\"span\");\n label.className = \"drawer-confirm-label\";\n label.setAttribute(\"part\", \"drawer-confirm-label\");\n label.textContent = this.#strings.deletePrompt;\n const yes = document.createElement(\"button\");\n yes.type = \"button\";\n yes.className = \"drawer-confirm-yes\";\n yes.setAttribute(\"part\", \"drawer-confirm-yes\");\n yes.textContent = this.#strings.delete;\n yes.addEventListener(\"click\", () => this.#callbacks.onDelete(meta.threadId));\n const no = document.createElement(\"button\");\n no.type = \"button\";\n no.className = \"drawer-confirm-no\";\n no.setAttribute(\"part\", \"drawer-confirm-no\");\n no.textContent = this.#strings.cancel;\n no.addEventListener(\"click\", () => this.#renderList());\n confirm.append(label, yes, no);\n row.replaceChildren(confirm);\n }\n}\n", "/**\n * The decision a run is suspended on, and the one way to abandon it.\n *\n * A run pauses on a person in three places -- a client-side confirmation, a\n * batch of server interrupts, and the `ask_user` question -- and a Stop has to\n * reach whichever of them is open. Holding the abort controller here gives\n * it one owner: a wait opens, the Stop aborts what is open, and the wait closes\n * when it is answered.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class PendingDecision {\n // Aborting this dismisses (declines) an open confirmation card when the run\n // is cancelled while the card awaits a decision. One controller per wait.\n #controller: AbortController | null = null;\n\n /** Start waiting on a person; aborting the returned signal abandons the wait. */\n open(): AbortSignal {\n this.#controller = new AbortController();\n return this.#controller.signal;\n }\n\n /** The wait was answered; a later Stop has nothing of this wait's to abandon. */\n close(): void {\n this.#controller = null;\n }\n\n /** Abandon whatever wait is open, resolving it as declined. A no-op when none is. */\n abort(): void {\n this.#controller?.abort();\n }\n}\n", "import type { Context } from \"@ag-ui/core\";\nimport {\n ICON_PLACE,\n ICON_PLACE_SHARED,\n ICON_PLACE_WITHHELD,\n PLACE_CONTEXT,\n} from \"../../constants.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\nimport type { Place } from \"./place.js\";\n\n/** What identifies a place for the exclusion: its href, else its label and detail. */\nfunction keyOf(place: Place): string {\n return place.href ?? `${place.label}\\u0000${place.detail ?? \"\"}`;\n}\n\n/** Draw `text` into `el`, hiding it when there is none. */\nfunction setText(el: HTMLElement, text: string | undefined): void {\n el.textContent = text ?? \"\";\n el.hidden = text === undefined;\n}\n\n/**\n * The \"you are here\" chip in the composer's tool row, and the context entry it stands for.\n *\n * The exclusion is keyed on the place: it holds across turns on the same place and lapses\n * when a different one is read. A read of no place keeps it, so a page naming nothing\n * mid-navigation does not undo it. Nothing persists, and nothing the host sets can lift it.\n */\nexport class PlaceChip {\n readonly element: HTMLElement = document.createElement(\"div\");\n /** The same place for the collapsed bar, drawn by the same render. */\n readonly barElement: HTMLElement = document.createElement(\"span\");\n readonly #barLabel: HTMLElement = document.createElement(\"span\");\n readonly #barDetail: HTMLElement = document.createElement(\"span\");\n readonly #icon: HTMLElement = document.createElement(\"span\");\n readonly #label: HTMLElement = document.createElement(\"span\");\n readonly #detail: HTMLElement = document.createElement(\"span\");\n readonly #toggle: HTMLButtonElement = document.createElement(\"button\");\n #place: Place | null = null;\n #excluded: string | null = null;\n #strings: UiStrings = DEFAULT_UI_STRINGS;\n\n constructor() {\n this.element.className = \"place\";\n this.element.setAttribute(\"part\", \"place\");\n this.element.hidden = true;\n this.#icon.className = \"place-icon\";\n this.#icon.setAttribute(\"part\", \"place-icon\");\n this.#label.className = \"place-label\";\n this.#label.setAttribute(\"part\", \"place-label\");\n this.#detail.className = \"place-detail\";\n this.#detail.setAttribute(\"part\", \"place-detail\");\n this.#toggle.type = \"button\";\n this.#toggle.className = \"place-toggle\";\n this.#toggle.setAttribute(\"part\", \"place-toggle\");\n const text = document.createElement(\"span\");\n text.className = \"place-text\";\n text.append(this.#label, this.#detail);\n this.element.append(this.#icon, text, this.#toggle);\n this.barElement.className = \"bar-place\";\n this.barElement.setAttribute(\"part\", \"bar-place\");\n this.barElement.hidden = true;\n this.#barLabel.className = \"place-label\";\n this.#barLabel.setAttribute(\"part\", \"place-label\");\n this.#barDetail.className = \"place-detail\";\n this.#barDetail.setAttribute(\"part\", \"place-detail\");\n this.barElement.append(this.#barLabel, this.#barDetail);\n }\n\n /** Wire the toggle for one connection, with the strings it resolved. */\n mount(signal: AbortSignal, strings: UiStrings): void {\n this.#strings = strings;\n this.#toggle.addEventListener(\"click\", () => this.#flip(), { signal });\n this.#render();\n }\n\n /** Show a fresh read; null hides the chip and sends nothing. */\n update(place: Place | null): void {\n if (place !== null && this.#excluded !== null && this.#excluded !== keyOf(place)) {\n this.#excluded = null;\n }\n this.#place = place;\n this.#render();\n }\n\n /** Whether there is a place and the user withheld it, which withholds the page too. */\n get withheld(): boolean {\n return this.#place !== null && this.#excluded !== null;\n }\n\n /** The round's context entry: the place as shown, without its icon, or nothing. */\n context(): Context[] {\n const place = this.#place;\n if (place === null || this.#excluded !== null) {\n return [];\n }\n const sent = {\n label: place.label,\n ...(place.detail === undefined ? {} : { detail: place.detail }),\n ...(place.href === undefined ? {} : { href: place.href }),\n };\n return [{ description: PLACE_CONTEXT, value: JSON.stringify(sent) }];\n }\n\n #flip(): void {\n const place = this.#place;\n if (place === null) {\n return;\n }\n this.#excluded = this.#excluded === null ? keyOf(place) : null;\n this.#render();\n }\n\n #render(): void {\n const place = this.#place;\n this.element.hidden = place === null;\n this.barElement.hidden = place === null;\n if (place === null) {\n return;\n }\n const shared = this.#excluded === null;\n this.element.toggleAttribute(\"data-excluded\", !shared);\n this.barElement.toggleAttribute(\"data-excluded\", !shared);\n if (place.icon === undefined) {\n this.#icon.innerHTML = ICON_PLACE;\n } else {\n const img = document.createElement(\"img\");\n img.src = place.icon;\n img.alt = \"\";\n this.#icon.replaceChildren(img);\n }\n setText(this.#label, place.label);\n setText(this.#detail, place.detail);\n setText(this.#barLabel, place.label);\n setText(this.#barDetail, place.detail);\n this.element.title = fillUiString(\n shared ? this.#strings.placeShared : this.#strings.placeWithheld,\n { label: place.label },\n );\n const action = shared ? this.#strings.placeStopSharing : this.#strings.placeShareAgain;\n this.#toggle.innerHTML = shared ? ICON_PLACE_SHARED : ICON_PLACE_WITHHELD;\n this.#toggle.title = action;\n this.#toggle.setAttribute(\"aria-label\", action);\n }\n}\n", "import type { RouteMap } from \"../../tools/route_map.js\";\nimport type { Place } from \"./place.js\";\n\n/** A route path template as an anchored pattern, each placeholder one segment. */\nfunction pattern(path: string): RegExp {\n const escaped = path\n .replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/:[A-Za-z_][A-Za-z0-9_]*/g, \"[^/]+\");\n return new RegExp(`^${escaped}$`);\n}\n\n/**\n * The place a route map implies: the first route whose path template matches\n * `pathname`, its title (else its id) as the label, its group as the detail,\n * and the path as the href. Null when no route matches.\n */\nexport function placeFromRoute(routes: RouteMap, pathname: string): Place | null {\n const route = routes.find((candidate) => pattern(candidate.path).test(pathname));\n if (route === undefined) {\n return null;\n }\n return {\n label: route.title ?? route.id,\n ...(route.group === undefined ? {} : { detail: route.group }),\n href: pathname,\n };\n}\n", "import { SCREEN_EDGE_MARGIN } from \"../../constants.js\";\nimport type { LauncherBox, ViewportBox } from \"./launcher_placement.js\";\n\n/**\n * Keep a launcher fully on screen, and a little clear of the edge.\n *\n * Applied to a dragged position and again to a restored one, because the\n * viewport that stored it may since have shrunk. A launcher parked past the\n * edge is unreachable, and it is the only way back to a collapsed\n * conversation.\n *\n * Not the panel's 24px gutter, which was rejected here on purpose: a launcher\n * held that far in refuses the corners people actually drag it to. But not\n * zero either -- the bubble is a circle with a drop shadow, and one flush\n * against the boundary has its shadow cut and its curve running into the edge,\n * which reads as clipped whether or not a pixel is actually missing.\n */\nexport function clampLauncher(\n launcher: LauncherBox,\n viewport: ViewportBox,\n margin: number = SCREEN_EDGE_MARGIN,\n): { readonly left: number; readonly top: number } {\n // The margin is given up rather than enforced where it does not fit: a\n // viewport narrower than the bubble and its two margins would otherwise\n // produce a lower bound above the upper one and pin it to the wrong edge.\n const room = Math.min(margin, Math.max(0, (viewport.width - launcher.width) / 2));\n const vertical = Math.min(margin, Math.max(0, (viewport.height - launcher.height) / 2));\n return {\n left: Math.max(\n viewport.left + room,\n Math.min(launcher.left, viewport.left + viewport.width - launcher.width - room),\n ),\n top: Math.max(\n viewport.top + vertical,\n Math.min(launcher.top, viewport.top + viewport.height - launcher.height - vertical),\n ),\n };\n}\n", "import { EDGE_MARGIN } from \"../../constants.js\";\nimport type { ViewportBox } from \"./launcher_placement.js\";\nimport type { PanelRect } from \"./resize_handle.js\";\n\n/**\n * Hold a panel inside the viewport, keeping its size.\n *\n * The near edge is clamped and the far edge follows, so a panel too large for\n * the viewport is held against the near margin and left to the max-width and\n * max-height rules rather than centred by force. The lower bound wins a\n * contradiction for the same reason: `Math.min` first would put an oversized\n * panel off the left edge instead of against the margin it can still honour.\n */\nexport function clampPanel(\n host: PanelRect,\n viewport: ViewportBox,\n margin: number = EDGE_MARGIN,\n): PanelRect {\n const width = host.right - host.left;\n const height = host.bottom - host.top;\n const left = Math.max(\n viewport.left + margin,\n Math.min(host.left, viewport.left + viewport.width - margin - width),\n );\n const top = Math.max(\n viewport.top + margin,\n Math.min(host.top, viewport.top + viewport.height - margin - height),\n );\n return { left, top, right: left + width, bottom: top + height };\n}\n", "import { clampLauncher } from \"./clamp_launcher.js\";\nimport type { LauncherBox, ViewportBox } from \"./launcher_placement.js\";\n\n/** What the drag needs from its host to do its job. */\nexport interface LauncherDragOptions {\n /**\n * Whether the current placement lets the launcher move, read per interaction\n * because `placement` is a live attribute. A docked rail and a full-bleed\n * layout have nowhere to move it to.\n */\n readonly enabled: () => boolean;\n /** The launcher's current box, in viewport coordinates. */\n readonly rect: () => LauncherBox;\n /** The viewport the launcher has to stay inside. */\n readonly viewport: () => ViewportBox;\n /** Put the launcher's top-left at this point. Called per pointer move. */\n readonly apply: (left: number, top: number) => void;\n /**\n * Called once per completed move, for persistence: on `pointerup` for a\n * drag, and when the key comes up (or focus leaves) for a key press. Never\n * per pointer move, and never per key repeat.\n */\n readonly commit: (left: number, top: number) => void;\n /**\n * Ends the launcher's own listeners when aborted. The launcher outlives the\n * element's connection to the document and this is called on every connect,\n * so without it a re-inserted element moved one arrow press two steps.\n */\n readonly signal: AbortSignal;\n}\n\n/**\n * How far the pointer must travel before this counts as a drag rather than a\n * click. The launcher's first job is still to expand the panel, so a press\n * that wanders by a pixel has to remain a press.\n */\nconst DRAG_THRESHOLD = 4;\n\n/** Keyboard step, and the larger one Shift asks for. */\nconst STEP = 16;\nconst COARSE_STEP = 64;\n\n/**\n * Let the user drag the collapsed launcher anywhere on screen.\n *\n * The launcher is a button before it is a handle, and that ordering is the\n * whole difficulty: every drag ends in a `click` the browser synthesises, which\n * would expand the panel the user was only repositioning. So a completed drag\n * arms a one-shot capture listener that eats exactly one click.\n *\n * Two things stop that from eating a click it should not have. A drag ending\n * off the launcher never produces the click it armed, so the arming is cleared\n * on the next `pointerdown` -- a pointer click is always preceded by a press,\n * which puts the clearing ahead of any click it could reach.\n *\n * That leaves the clicks with no press in front of them at all: `Enter` and\n * `Space` on the focused button, assistive technology activating it, and a host\n * calling `click()` itself. None of those is the tail of a drag, and all of them\n * are the only way in for someone not using a pointer, so the suppression is\n * narrowed to clicks carrying a click count -- which is the pointer's own.\n */\nexport function enableLauncherDrag(launcher: HTMLElement, options: LauncherDragOptions): void {\n let suppressClick = false;\n const { signal } = options;\n\n launcher.addEventListener(\n \"click\",\n (event: MouseEvent) => {\n // detail is the click count on a pointer click and zero on a keyboard,\n // assistive or programmatic one. Only the first kind can end a drag.\n if (!suppressClick || event.detail === 0) {\n return;\n }\n suppressClick = false;\n // Capture phase, so this runs before the expand handler bound to the\n // same element rather than after it.\n event.stopPropagation();\n event.preventDefault();\n },\n { capture: true, signal },\n );\n\n launcher.addEventListener(\n \"pointerdown\",\n (event: PointerEvent) => {\n // Any suppression left armed by a drag that ended elsewhere dies here,\n // before it can reach a click belonging to this new gesture.\n suppressClick = false;\n if (!options.enabled()) {\n return;\n }\n const start = options.rect();\n const originX = event.clientX;\n const originY = event.clientY;\n let dragging = false;\n\n const onMove = (move: PointerEvent): void => {\n const dx = move.clientX - originX;\n const dy = move.clientY - originY;\n if (!dragging && Math.hypot(dx, dy) < DRAG_THRESHOLD) {\n return;\n }\n dragging = true;\n launcher.setAttribute(\"data-dragging\", \"true\");\n // Measured from the box the press started on, never from the live one:\n // reading it each move would chase the launcher as it moves and the\n // travel would compound.\n const next = clampLauncher(\n { ...start, left: start.left + dx, top: start.top + dy },\n options.viewport(),\n );\n options.apply(next.left, next.top);\n };\n\n const onUp = (up: PointerEvent): void => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", onUp);\n window.removeEventListener(\"pointercancel\", onUp);\n if (!dragging) {\n return;\n }\n launcher.removeAttribute(\"data-dragging\");\n suppressClick = true;\n const next = clampLauncher(\n {\n ...start,\n left: start.left + (up.clientX - originX),\n top: start.top + (up.clientY - originY),\n },\n options.viewport(),\n );\n options.commit(next.left, next.top);\n };\n\n // Listeners on `window`, not the launcher: a fast drag outruns the pointer\n // and would otherwise strand it mid-move with no pointerup.\n //\n // pointercancel matters on touch, where it is routine rather than\n // exceptional: the browser takes the pointer back for a scroll or a system\n // gesture and never sends pointerup. Without this the move listeners stay\n // attached and the drag stamp never clears, which leaves the launcher\n // following a finger that has stopped and the element believing a gesture\n // is still in flight.\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", onUp);\n window.addEventListener(\"pointercancel\", onUp);\n },\n { signal },\n );\n\n // The position this key gesture has applied but not yet persisted. The\n // pointer path can commit inline because a drag has one unambiguous end; a\n // key press does not, so the gesture's result is held here until it does.\n let pending: { left: number; top: number } | null = null;\n\n /** End a key gesture: persist what it applied, once. */\n const settle = (): void => {\n if (pending === null) {\n return;\n }\n const { left, top } = pending;\n pending = null;\n options.commit(left, top);\n };\n\n // Keyboard parity: a pointer-only move is unreachable without a mouse, and\n // the launcher has no equivalent control elsewhere. Arrow keys are free on a\n // button, so Enter and Space still expand.\n launcher.addEventListener(\n \"keydown\",\n (event: KeyboardEvent) => {\n if (!options.enabled()) {\n return;\n }\n const step = event.shiftKey ? COARSE_STEP : STEP;\n const rect = options.rect();\n let moved: { left: number; top: number } | null = null;\n if (event.key === \"ArrowLeft\") {\n moved = { left: rect.left - step, top: rect.top };\n } else if (event.key === \"ArrowRight\") {\n moved = { left: rect.left + step, top: rect.top };\n } else if (event.key === \"ArrowUp\") {\n moved = { left: rect.left, top: rect.top - step };\n } else if (event.key === \"ArrowDown\") {\n moved = { left: rect.left, top: rect.top + step };\n }\n if (moved === null) {\n return;\n }\n event.preventDefault();\n const next = clampLauncher({ ...rect, ...moved }, options.viewport());\n // Live feedback per key event, persistence only when the gesture ends: a\n // held arrow repeats at the OS rate, and committing here would put that\n // many storage writes behind a single press.\n options.apply(next.left, next.top);\n pending = next;\n },\n { signal },\n );\n\n // The key coming up ends the gesture, mirroring `pointerup`. `blur` closes\n // one whose keyup never arrives here -- focus moved on mid-press -- because a\n // position applied but never committed is a move the host silently forgets.\n launcher.addEventListener(\"keyup\", settle, { signal });\n launcher.addEventListener(\"blur\", settle, { signal });\n}\n", "import type { ExpandCorner, Extent, LauncherBox } from \"./launcher_placement.js\";\nimport type { PanelRect } from \"./resize_handle.js\";\n\n/** Where to put the host box, and where the launcher sits inside it. */\nexport interface WidgetInsets {\n /** An `inset` shorthand for the host box. */\n readonly hostInset: string;\n /** An `inset` shorthand for the launcher, relative to the host box. */\n readonly launcherInset: string;\n}\n\n/**\n * Express a panel and its launcher, both already positioned, as the two\n * `inset` shorthands the element writes.\n *\n * Both are measured from the **same** corner, which is what stops a later\n * resize from dragging the launcher: the pinned corner is the one edge a\n * resize cannot move. Which corner that is says nothing about where either box\n * ends up -- the positions are absolute and arrive decided -- so re-picking it\n * moves nothing, and the launcher may sit outside its own host box. Nothing\n * clips it there, and that is what lets a launcher be flush to a screen corner\n * while the panel it opens keeps its margin.\n *\n * `screen` is the **whole** viewport, not the part a host has left free. These\n * are CSS `inset` values on a fixed element, and the browser measures those\n * from the real edges -- so a `bottom` expressed against a box inset from the\n * top comes out short by exactly that inset. It only shows when the corner\n * flips mid-drag, because that is when the same point stops being expressed\n * from `top` and starts being expressed from `bottom`: the widget then leaps by\n * the reserved edge, which is a jump the gesture cannot explain.\n */\nexport function placeWidget(\n host: PanelRect,\n launcher: LauncherBox,\n corner: ExpandCorner,\n screen: Extent,\n): WidgetInsets {\n return {\n hostInset: inset({\n top: corner.y === \"top\" ? host.top : null,\n right: corner.x === \"right\" ? screen.width - host.right : null,\n bottom: corner.y === \"bottom\" ? screen.height - host.bottom : null,\n left: corner.x === \"left\" ? host.left : null,\n }),\n launcherInset: inset({\n top: corner.y === \"top\" ? launcher.top - host.top : null,\n right: corner.x === \"right\" ? host.right - (launcher.left + launcher.width) : null,\n bottom: corner.y === \"bottom\" ? host.bottom - (launcher.top + launcher.height) : null,\n left: corner.x === \"left\" ? launcher.left - host.left : null,\n }),\n };\n}\n\n/** An `inset` shorthand; a null side is `auto`, so the opposite one pins it. */\nfunction inset(sides: {\n top: number | null;\n right: number | null;\n bottom: number | null;\n left: number | null;\n}): string {\n const side = (value: number | null): string =>\n value === null ? \"auto\" : `${Math.round(value)}px`;\n return `${side(sides.top)} ${side(sides.right)} ${side(sides.bottom)} ${side(sides.left)}`;\n}\n", "import { SCREEN_EDGE_MARGIN } from \"../../constants.js\";\nimport { clampPanel } from \"./clamp_panel.js\";\nimport { placeWidget } from \"./place_widget.js\";\n\n/** A box in viewport coordinates. */\nexport interface LauncherBox {\n readonly left: number;\n readonly top: number;\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * The part of the screen a widget may rest in: a width and height, and the\n * corner they start from.\n *\n * The origin is not always zero. A host can reserve the edges its own chrome\n * occupies, and a panel clamped against a viewport that starts at the top-left\n * of the screen will happily park itself underneath a sticky header -- where it\n * cannot be reached, and where collapsing it only hides it further.\n */\nexport interface ViewportBox extends Extent {\n readonly left: number;\n readonly top: number;\n}\n\n/** A width/height pair, in CSS pixels. */\nexport interface Extent {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * The corner the panel is pinned by, and therefore grows away from: pinned\n * `top-left` opens down and to the right. It is also the corner the resize grip\n * must stay off, which is why the element stamps it rather than measuring it\n * once the launcher has been moved.\n */\nexport interface ExpandCorner {\n readonly x: \"left\" | \"right\";\n readonly y: \"top\" | \"bottom\";\n}\n\n/** Where to put the host box, and where the launcher sits inside it. */\nexport interface LauncherPlacement {\n /** The corner the panel opens away from. */\n readonly corner: ExpandCorner;\n /** An `inset` shorthand for the host box. */\n readonly hostInset: string;\n /** An `inset` shorthand for the launcher, relative to the host box. */\n readonly launcherInset: string;\n}\n\n/**\n * Decide where a panel should open from a launcher the user has dragged.\n *\n * The launcher is the fixed point: wherever it was dropped is where it stays,\n * collapsed and expanded alike. Everything here decides what happens *around*\n * it.\n *\n * Two steps, and they are separate on purpose:\n *\n * 1. **Pick the corner with the most clear space.** For each axis, compare the\n * room a panel would have on either side of the launcher and pin the side\n * with more of it. Pinning `left` means the panel runs rightward from the\n * launcher's left edge, so the room that decides it is the distance from\n * that edge to the far side of the viewport -- not \"which half of the screen\n * is the launcher in\", which gives a different and worse answer for a\n * launcher near the middle.\n *\n * 2. **Clamp the panel into the viewport, then put the launcher back.** A\n * launcher near the centre of a short viewport has a panel taller than\n * either side, so the winning corner still overflows. Clamping moves the\n * host box -- and the launcher is positioned inside that box, so it would be\n * dragged along with it. The launcher's own inset therefore carries the\n * difference: zero in the ordinary case, and exactly the distance the clamp\n * moved the box in the case that needs it. That the launcher may end up\n * outside its own host box is fine; nothing clips it, and it keeps its own\n * pointer events.\n *\n * Both insets are expressed from the *same* corner, which is what stops a\n * later panel resize from dragging the launcher: the pinned corner is the one\n * edge a resize cannot move.\n */\nexport function launcherPlacement(\n launcher: LauncherBox,\n panel: Extent,\n viewport: ViewportBox,\n screen: Extent,\n margin: number = SCREEN_EDGE_MARGIN,\n): LauncherPlacement {\n // Room for a panel pinned to each side of the launcher. A tie goes to the\n // first branch, so the result is deterministic for a centred launcher.\n //\n // Measured against the usable box's own edges, not against its width and\n // height as if it started at the origin. The launcher's coordinates are the\n // screen's, while the extents have already had the host's reserved edges\n // taken out of them, so mixing the two understates the room on one side and\n // overstates it on the other -- by the same reserved inset, in opposite\n // directions, which is what makes the comparison flip rather than merely\n // drift. The clamp below reads `viewport.left`/`top`; this had to as well.\n const roomRunningRight = viewport.left + viewport.width - launcher.left;\n const roomRunningLeft = launcher.left + launcher.width - viewport.left;\n const roomRunningDown = viewport.top + viewport.height - launcher.top;\n const roomRunningUp = launcher.top + launcher.height - viewport.top;\n const corner: ExpandCorner = {\n x: roomRunningRight >= roomRunningLeft ? \"left\" : \"right\",\n y: roomRunningDown >= roomRunningUp ? \"top\" : \"bottom\",\n };\n\n // The box the panel wants, then the box it can actually have. The launcher\n // is not moved by that clamp -- it is the fixed point of this gesture, so its\n // own inset carries the difference and it can end up outside the host box.\n const wantedLeft =\n corner.x === \"left\" ? launcher.left : launcher.left + launcher.width - panel.width;\n const wantedTop =\n corner.y === \"top\" ? launcher.top : launcher.top + launcher.height - panel.height;\n const host = clampPanel(\n {\n left: wantedLeft,\n top: wantedTop,\n right: wantedLeft + panel.width,\n bottom: wantedTop + panel.height,\n },\n viewport,\n margin,\n );\n\n // The usable box decides where things may rest; the screen is what the\n // resulting insets are measured from. They are the same only when the host\n // has reserved nothing.\n return { corner, ...placeWidget(host, launcher, corner, screen) };\n}\n", "import type { PanelRect } from \"./resize_handle.js\";\n\n/** What the drag needs from its host to do its job. */\nexport interface PanelDragOptions {\n /**\n * Whether the panel can be moved right now, read per interaction because\n * both halves of the answer are live: a docked or full-bleed placement has\n * nowhere to move the panel to, and a collapsed one has no panel on screen.\n */\n readonly enabled: () => boolean;\n /** The panel's current box, in viewport coordinates. */\n readonly rect: () => PanelRect;\n /**\n * Put the panel at this box. Called per pointer move, with the box the press\n * started on -- the whole gesture is one translation of that box, and a host\n * with anything else to move alongside the panel needs the same distance\n * rather than a distance measured from wherever the last move left things.\n */\n readonly apply: (box: PanelRect, from: PanelRect) => void;\n /** Called once per completed move, for persistence. Never per pointer move. */\n readonly commit: (box: PanelRect, from: PanelRect) => void;\n}\n\n/**\n * How far the pointer must travel before this counts as a drag. The header is\n * also where the title is selected and the controls are pressed, so a press\n * that wanders by a pixel has to remain a press.\n */\nconst DRAG_THRESHOLD = 4;\n\n/**\n * Elements inside the header that own their own press. A drag started on one\n * of these would move the panel out from under the control the user was\n * aiming at, and every one of them is the only way to reach what it does.\n */\nconst CONTROLS = \"button, a[href], input, select, textarea, [contenteditable]\";\n\n/**\n * Let the user move the whole widget by dragging the panel's header.\n *\n * The launcher can already be dragged, and this is the same gesture on the\n * half of the widget that is on screen when it is open -- a chat panel is a\n * window, and a window moves by its title bar. The two stay one position\n * rather than two: the host answers a moved panel by moving the launcher with\n * it, so collapsing after a drag leaves the launcher where the panel was.\n *\n * **No keyboard path here, deliberately.** Every other drag in this component\n * has arrow keys on the handle, because the handle is a control and the\n * capability is reachable nowhere else. A header is not a control: making it\n * focusable would put a tab stop with no role in front of every keyboard user,\n * ahead of the controls they actually came for. The capability is not lost --\n * arrow keys on the collapsed launcher move the widget, and the panel follows\n * it -- so what is missing is a shortcut, not the ability.\n */\nexport function enablePanelDrag(handle: HTMLElement, options: PanelDragOptions): void {\n handle.addEventListener(\"pointerdown\", (event: PointerEvent) => {\n // Secondary buttons open menus and paste on the platforms that have them;\n // none of that is a drag.\n //\n // Three conditions in one arc, which coverage counts as one branch however\n // many of them are deleted. Each is held by a named test in\n // panel_drag.test.ts -- \"ignores a secondary button\", \"does nothing where\n // the placement has nowhere to move the panel\", and \"steps aside for a\n // control in the header\" -- verified by mutating each one out.\n if (event.button !== 0 || !options.enabled() || onControl(event, handle)) {\n return;\n }\n const start = options.rect();\n const originX = event.clientX;\n const originY = event.clientY;\n let dragging = false;\n\n const boxAt = (x: number, y: number): PanelRect => {\n // Measured from the box the press started on, never from the live one:\n // reading it each move would chase the panel as it moves and the travel\n // would compound.\n const dx = x - originX;\n const dy = y - originY;\n return {\n left: start.left + dx,\n top: start.top + dy,\n right: start.right + dx,\n bottom: start.bottom + dy,\n };\n };\n\n const onMove = (move: PointerEvent): void => {\n if (\n !dragging &&\n Math.hypot(move.clientX - originX, move.clientY - originY) < DRAG_THRESHOLD\n ) {\n return;\n }\n dragging = true;\n handle.setAttribute(\"data-dragging\", \"true\");\n options.apply(boxAt(move.clientX, move.clientY), start);\n };\n\n const onUp = (up: PointerEvent): void => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", onUp);\n window.removeEventListener(\"pointercancel\", onUp);\n if (!dragging) {\n return;\n }\n handle.removeAttribute(\"data-dragging\");\n options.commit(boxAt(up.clientX, up.clientY), start);\n };\n\n // The press is the panel's from here: without this the browser starts\n // selecting the title text and the drag leaves a highlight behind it.\n event.preventDefault();\n // Listeners on `window`, not the header: a fast drag outruns the pointer\n // and would otherwise strand the panel mid-move with no pointerup.\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", onUp);\n // Routine on touch rather than exceptional: the browser takes the pointer\n // back for a scroll or a system gesture and never sends pointerup.\n window.addEventListener(\"pointercancel\", onUp);\n });\n}\n\n/**\n * Whether the press landed on a control inside the header rather than on the\n * header itself.\n *\n * The composed path rather than `target`, because a control a host slots into\n * the header lives in the light DOM: retargeting reports the host element for\n * it, which matches nothing. Everything below the handle is examined and\n * nothing above it, so a control the header happens to sit inside is not one\n * of ours.\n */\nfunction onControl(event: PointerEvent, handle: HTMLElement): boolean {\n const path = event.composedPath();\n return path\n .slice(0, path.indexOf(handle))\n .some((node) => node instanceof Element && node.matches(CONTROLS));\n}\n", "/**\n * Which edges a grip drags. An axis left out is an axis the grip does not\n * move: the left-edge grip is `{ x: \"left\" }`, the top-right corner is\n * `{ x: \"right\", y: \"top\" }`.\n */\nexport interface ResizeGrip {\n readonly x?: \"left\" | \"right\";\n readonly y?: \"top\" | \"bottom\";\n}\n\n/** Which edges the layout holds still while the panel changes size. */\nexport interface ResizeAnchor {\n /** The horizontal edge that does not move. */\n readonly x: \"left\" | \"right\";\n /** The vertical edge that does not move. */\n readonly y: \"top\" | \"bottom\";\n}\n\n/**\n * What the current placement allows: both axes, width only, or nothing. Which\n * edges a given grip drags is separate, and fixed when the grip is built.\n */\nexport type ResizeAxis = \"none\" | \"width\" | \"both\";\n\n/** Persisted size, in CSS pixels. Either axis may be absent. */\nexport interface ResizeSize {\n readonly width?: number;\n readonly height?: number;\n}\n\n/** The panel's position on screen, in viewport coordinates. */\nexport interface PanelRect {\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** What the handle needs from its host to do its job. */\nexport interface ResizeOptions {\n /**\n * Which axes the current placement allows, read per interaction. A getter\n * because `placement` is a live attribute, and a value read at construction\n * would survive the host switching to a docked or full-bleed layout.\n */\n readonly axis: () => ResizeAxis;\n /** The panel's current bounding box. */\n readonly rect: () => PanelRect;\n /** Apply a box (the host decides what that costs in properties). */\n readonly apply: (box: PanelRect) => void;\n /**\n * Called once per completed resize, for persistence: on `pointerup` for a\n * drag, and when the key comes up (or focus leaves the handle) for a key\n * press. Never per pointer move, and never per key repeat.\n */\n readonly commit: (box: PanelRect) => void;\n /** Accessible label. */\n readonly label: string;\n}\n\n/** Smallest usable panel; below this the composer and header collide. */\nconst MIN_WIDTH = 280;\nconst MIN_HEIGHT = 240;\n\n/** Keyboard step, and the larger one Shift asks for. */\nconst STEP = 16;\nconst COARSE_STEP = 64;\n\n/**\n * A drag handle that resizes the chat panel from one edge or corner.\n *\n * The rule that keeps it correct is that **the edge a grip does not drag is the\n * one that stays put**. That is the whole model, and it is what lets the same\n * code serve all eight grips: the left-edge grip moves the left edge and holds\n * the right, the right-edge grip does the reverse, a corner does both axes.\n *\n * Which edge the *layout* pins is a different question and is deliberately not\n * asked here. It matters only to the host, which has to rewrite its own\n * position when a grip drags the very edge the layout was holding still --\n * dragging the pinned edge of a panel is a move as much as a resize. The\n * handle reports the box it wants; what that costs in CSS properties is the\n * host's problem.\n *\n * An earlier version took the anchor and derived the direction from it, which\n * is where the asymmetries lived: whether an arrow key grew or shrank the\n * panel depended on which corner the single grip had been placed on. With the\n * grip stated outright, an arrow simply moves the edge it names.\n */\nexport function createResizeHandle(grip: ResizeGrip, options: ResizeOptions): HTMLDivElement {\n const handle = document.createElement(\"div\");\n handle.className = `resize-handle resize-handle--${gripName(grip)}`;\n handle.setAttribute(\"part\", `resize-handle resize-handle-${gripName(grip)}`);\n // A separator with an orientation: an edge grip splits along one axis, and a\n // corner has no single one to report.\n handle.setAttribute(\"role\", \"separator\");\n if (grip.x === undefined) {\n handle.setAttribute(\"aria-orientation\", \"horizontal\");\n } else if (grip.y === undefined) {\n handle.setAttribute(\"aria-orientation\", \"vertical\");\n }\n handle.setAttribute(\"aria-label\", options.label);\n handle.tabIndex = 0;\n\n handle.addEventListener(\"pointerdown\", (event: PointerEvent) => {\n const axis = options.axis();\n if (axis === \"none\" || !movable(grip, axis)) {\n return;\n }\n // Captured once: the edges this grip is not dragging cannot move during\n // the drag, and reading them live would chase the panel as it resizes.\n const rect = options.rect();\n\n const onMove = (move: PointerEvent): void => {\n options.apply(boxAt(grip, axis, rect, move.clientX, move.clientY));\n };\n\n const onUp = (up: PointerEvent): void => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", onUp);\n handle.removeAttribute(\"data-dragging\");\n options.commit(boxAt(grip, axis, rect, up.clientX, up.clientY));\n };\n\n handle.setAttribute(\"data-dragging\", \"true\");\n // Listeners on `window`, not the handle: a fast drag outruns the pointer\n // and would otherwise strand the panel mid-resize with no pointerup.\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", onUp);\n event.preventDefault();\n });\n\n // The box the current key gesture has applied but not yet persisted. The\n // pointer path can commit inline because a drag has one unambiguous end;\n // a key press does not, so the gesture's result is held here until it does.\n let pending: PanelRect | null = null;\n\n /** End a key gesture: persist what it applied, once. */\n const settle = (): void => {\n if (pending === null) {\n return;\n }\n const box = pending;\n pending = null;\n options.commit(box);\n };\n\n // Keyboard parity: a pointer-only resize is unreachable without a mouse, and\n // this control has no equivalent elsewhere in the UI. An arrow moves the edge\n // this grip names, in the direction it names -- so the same key grows one\n // side's grip and shrinks the opposite one, which is what a pointer does too.\n handle.addEventListener(\"keydown\", (event: KeyboardEvent) => {\n const axis = options.axis();\n if (axis === \"none\" || !movable(grip, axis)) {\n return;\n }\n const step = event.shiftKey ? COARSE_STEP : STEP;\n const rect = options.rect();\n const delta = ARROWS[event.key];\n if (delta === undefined) {\n return;\n }\n // An arrow across this grip's fixed axis has no edge to move.\n if ((delta.x !== 0 && grip.x === undefined) || (delta.y !== 0 && grip.y === undefined)) {\n return;\n }\n event.preventDefault();\n const x = (grip.x === \"left\" ? rect.left : rect.right) + delta.x * step;\n const y = (grip.y === \"top\" ? rect.top : rect.bottom) + delta.y * step;\n const next = boxAt(grip, axis, rect, x, y);\n // Live feedback per key event, persistence only when the gesture ends:\n // `commit` promises one call per completed resize, and a held arrow key\n // repeats at the OS rate (20-30 events a second), so committing here would\n // put that many storage writes or PATCHes behind a single press \u2014 landing\n // hardest on the keyboard users this path exists for.\n options.apply(next);\n pending = next;\n });\n\n // The key coming up ends the gesture, mirroring `pointerup`. `blur` closes one\n // whose keyup never arrives here \u2014 focus moved on mid-press \u2014 because a size\n // that was applied but never committed is a resize the host silently forgets.\n handle.addEventListener(\"keyup\", settle);\n handle.addEventListener(\"blur\", settle);\n\n return handle;\n}\n\n/** Which way each arrow key pushes the edge under it. */\nconst ARROWS: Record<string, { x: number; y: number } | undefined> = {\n ArrowLeft: { x: -1, y: 0 },\n ArrowRight: { x: 1, y: 0 },\n ArrowUp: { x: 0, y: -1 },\n ArrowDown: { x: 0, y: 1 },\n};\n\n/** The hyphenated name of a grip, for its class and part. */\nexport function gripName(grip: ResizeGrip): string {\n return [grip.y, grip.x].filter((side) => side !== undefined).join(\"-\");\n}\n\n/** Whether the current placement leaves this grip anything to move. */\nfunction movable(grip: ResizeGrip, axis: ResizeAxis): boolean {\n // A docked panel owns its height, so a grip that only moves a horizontal\n // edge has nothing to do and must not pretend otherwise.\n return axis === \"both\" || grip.x !== undefined;\n}\n\n/**\n * The box a pointer at (x, y) implies for this grip.\n *\n * Each axis is clamped by pushing the *dragged* edge back to the minimum,\n * never by moving the edge that is supposed to be standing still: clamping the\n * wrong one is how a panel dragged past its minimum starts travelling.\n */\nfunction boxAt(\n grip: ResizeGrip,\n axis: ResizeAxis,\n rect: PanelRect,\n x: number,\n y: number,\n): PanelRect {\n const left = grip.x === \"left\" ? Math.min(x, rect.right - MIN_WIDTH) : rect.left;\n const right = grip.x === \"right\" ? Math.max(x, rect.left + MIN_WIDTH) : rect.right;\n // A placement that owns its height leaves the vertical edges where they are.\n const vertical = axis === \"both\";\n const top = vertical && grip.y === \"top\" ? Math.min(y, rect.bottom - MIN_HEIGHT) : rect.top;\n const bottom = vertical && grip.y === \"bottom\" ? Math.max(y, rect.top + MIN_HEIGHT) : rect.bottom;\n return { left, top, right, bottom };\n}\n", "import type { ResizeAxis } from \"./resize_handle.js\";\n\n/**\n * What a collapsed panel shrinks to, stamped on the element as\n * data-collapsed-to so the stylesheet draws it.\n *\n * - `launcher` -- the round button in a corner.\n * - `rail` -- the slim full-height edge the sidebar docks against; the same\n * launcher element, shaped by the stylesheet.\n * - `header` -- the in-flow collapse: the body hides and the header bar stays\n * in the host's layout, so there is no launcher at all.\n * - `bar` -- `collapse-to=\"bar\"` over a placement that would otherwise\n * collapse to `launcher`: a strip along the bottom edge, the panel rising\n * from its right end.\n * - `none` -- `collapse-to=\"none\"` over any collapsible placement: collapsed\n * is hidden, and the host's own control brings the panel back.\n * - `null` -- no collapsed state. `page` is a dedicated route rather than a\n * panel on someone else's page, so there is no \"away\" for it to go to:\n * collapsing it left a strip of application chrome fixed over a route with\n * no owner, and it hides the launcher, so the usual way back did not exist.\n * The header drops its collapse control here, but a control removed from\n * the UI is not a state removed from the model: the property, the attribute\n * and a value restored from storage all still reach it, so every one of\n * those paths asks this record; the stylesheet covers the one path that\n * never does, an attribute written straight onto the element.\n */\nexport type CollapseTarget = \"launcher\" | \"rail\" | \"header\" | \"bar\" | \"none\" | null;\n\n/**\n * Everything the script needs to know about one display surface, in one\n * record, so a placement's behaviour is read in one place rather than\n * assembled from a table per question.\n *\n * The stylesheet still carries each surface's look (one module per placement\n * under this directory); this is the part of a surface that code decides.\n */\nexport interface Surface {\n /** What collapsing shrinks the panel to; `null` when it cannot collapse. */\n readonly collapseTo: CollapseTarget;\n /**\n * Whether a gesture may move the launcher. The rest have nowhere to put it:\n * the rail is a docked edge, `header` and `null` have no launcher, a\n * full-bleed panel covers the screen it would be opening into, and the bar\n * and the host's own control are not a launcher at all.\n */\n readonly launcherDraggable: boolean;\n /**\n * Whether the header drag and `moveTo` may move the open panel. The same\n * answer as {@link launcherDraggable} for every placement on its own; the two\n * part under `collapse-to=\"bar\"` and `\"none\"`, where a corner panel still\n * moves like one but has no launcher left to drag.\n */\n readonly panelMovable: boolean;\n /**\n * Which axes the resize grips may change. A full-bleed layout is the whole\n * viewport by definition and cannot be resized; a docked panel owns its\n * height, leaving only its inner edge.\n */\n readonly resizeAxis: ResizeAxis;\n /**\n * Whether a first mount with nothing stored starts collapsed. Only the\n * corner placements do: a launcher is the resting state of every corner chat\n * in the field, and mounting open put a 380x560 panel over the host page's\n * corner on a visitor's first load, uninvited. The placements that place\n * themselves start open -- a host that docks a sidebar has already decided\n * the widget belongs on screen, and one that embeds it has given it a box.\n *\n * Separate from {@link launcherDraggable} although the two agree today:\n * \"has a launcher to rest on\" and \"the launcher can be moved\" are different\n * questions, and a surface with a fixed launcher would answer them apart.\n */\n readonly startsCollapsed: boolean;\n /**\n * What the header's maximize control grows: both axes for a corner or docked\n * panel, the width for a side column, and `null` where there is no control\n * (a surface that already fills its box, or that the host sized).\n */\n readonly maximizes: \"both\" | \"width\" | null;\n}\n\nconst CORNER: Surface = {\n collapseTo: \"launcher\",\n launcherDraggable: true,\n panelMovable: true,\n resizeAxis: \"both\",\n startsCollapsed: true,\n maximizes: \"both\",\n};\n\nconst DOCKED: Surface = {\n collapseTo: \"launcher\",\n launcherDraggable: false,\n panelMovable: false,\n resizeAxis: \"width\",\n startsCollapsed: false,\n maximizes: \"width\",\n};\n\n/**\n * One record per `placement` value. Absent (`null`) and empty are the default\n * floating corner, as the stylesheet treats them.\n */\nconst SURFACES: ReadonlyMap<string | null, Surface> = new Map<string | null, Surface>([\n [null, CORNER],\n [\"\", CORNER],\n [\"floating\", CORNER],\n [\"bottom-left\", CORNER],\n [\"side\", DOCKED],\n [\"sidebar\", { ...DOCKED, collapseTo: \"rail\" }],\n [\n \"full\",\n {\n collapseTo: \"launcher\",\n launcherDraggable: false,\n panelMovable: false,\n resizeAxis: \"none\",\n startsCollapsed: false,\n maximizes: null,\n },\n ],\n [\n \"page\",\n {\n collapseTo: null,\n launcherDraggable: false,\n panelMovable: false,\n resizeAxis: \"none\",\n startsCollapsed: false,\n maximizes: null,\n },\n ],\n [\n \"embedded\",\n {\n collapseTo: \"header\",\n launcherDraggable: false,\n panelMovable: false,\n resizeAxis: \"both\",\n startsCollapsed: false,\n maximizes: null,\n },\n ],\n]);\n\n/**\n * A value no record names. The stylesheet lays it out as the default corner,\n * but the script has never treated an unknown value as one: its launcher stays\n * put and it mounts open, so a typo in a host's markup does not start moving\n * or hiding a panel the host meant to show.\n */\nconst UNKNOWN: Surface = {\n collapseTo: \"launcher\",\n launcherDraggable: false,\n panelMovable: false,\n resizeAxis: \"both\",\n startsCollapsed: false,\n maximizes: null,\n};\n\n/**\n * The surface `placement` and `collapse-to` describe together. Read per\n * interaction by every caller, because both are live attributes.\n *\n * `collapse-to` only ever replaces the round launcher or the whole collapsed\n * state, never a placement's own shape: `bar` applies where the placement\n * collapses to `launcher`, so the sidebar keeps its rail and an embedded chat\n * its header bar, and `none` applies to every collapsible placement. Absent,\n * `auto` and any other value leave the placement as it was. Both turn the\n * launcher drag off, because there is no launcher left to drag, and keep the\n * placement's own answer for moving the panel: a corner panel rises from the\n * bar or the anchor until the user drags it somewhere else, and a placement\n * that owns its position keeps owning it.\n */\nexport function surfaceFor(placement: string | null, collapseTo: string | null = null): Surface {\n const surface = SURFACES.get(placement) ?? UNKNOWN;\n if (collapseTo === \"bar\" && surface.collapseTo === \"launcher\") {\n return { ...surface, collapseTo: \"bar\", launcherDraggable: false };\n }\n if (collapseTo === \"none\" && surface.collapseTo !== null) {\n return { ...surface, collapseTo: \"none\", launcherDraggable: false };\n }\n return surface;\n}\n", "import { EDGE_MARGIN, SCREEN_EDGE_MARGIN, STORAGE_ROOT } from \"../../constants.js\";\nimport type { ChatCorner, ChatSurfaceReport } from \"../../tools/chat_surface_tools.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { clampLauncher } from \"./clamp_launcher.js\";\nimport { clampPanel } from \"./clamp_panel.js\";\nimport { enableLauncherDrag } from \"./launcher_drag.js\";\nimport {\n type ExpandCorner,\n type Extent,\n type LauncherBox,\n launcherPlacement,\n type ViewportBox,\n} from \"./launcher_placement.js\";\nimport { enablePanelDrag } from \"./panel_drag.js\";\nimport { placeWidget } from \"./place_widget.js\";\nimport {\n createResizeHandle,\n gripName,\n type PanelRect,\n type ResizeAnchor,\n type ResizeAxis,\n type ResizeGrip,\n type ResizeSize,\n} from \"./resize_handle.js\";\nimport { type Surface, surfaceFor } from \"./surface_for.js\";\n\n/** Persistence key for the dragged panel sizes, one per placement in one record. */\nconst SIZE_KEY = `${STORAGE_ROOT}:size`;\n\n/** The stored record: a dragged size per placement attribute value. */\ninterface StoredSizes {\n readonly v: 2;\n readonly placements: Readonly<Record<string, ResizeSize>>;\n}\n\n/**\n * The private properties a dragged size lives in. They are not the public\n * `--ag-ui-width` / `--ag-ui-height` tokens, which belong to the host: an\n * inline write there outranked every host rule and was read back by the\n * small-viewport block, so a size dragged in a wide window leaked into the\n * phone shape. The placement rules read these before the host token; the\n * small-viewport block does not read them at all.\n */\nconst DRAG_WIDTH = \"--_drag-width\";\nconst DRAG_HEIGHT = \"--_drag-height\";\n/**\n * How far above the bottom of the layout viewport a docked panel stands, and\n * how far in from its right edge: the bar's height, or the host anchor's top\n * and right. Private and written inline, like the dragged size, and read only\n * by the dock rules; never an inline --_inset, which would outrank the phone\n * block and keep a docked panel off full-bleed on a phone.\n */\nconst DOCK_BOTTOM = \"--_dock-bottom\";\nconst DOCK_RIGHT = \"--_dock-right\";\nconst DOCK_TOP = \"--_dock-top\";\n\n/** The side of its anchor a panel under collapse-to=\"none\" opens on. */\ntype AnchorSide = \"above\" | \"below\";\n\n/** Per-tab persistence key for a dragged launcher position. */\nconst LAUNCHER_KEY = `${STORAGE_ROOT}:launcher`;\n\n/**\n * Persistence key for where the user dragged a docked panel. Its own key, not\n * the launcher's: a spot stored under the corner launcher describes another\n * surface, and reading it here would open every panel away from the bar for a\n * host that switched to the bar after its users had dragged their corner\n * panels.\n */\nconst DOCK_KEY = `${STORAGE_ROOT}:dock`;\n\n/**\n * Where the user last put a corner panel's launcher, and the panel itself when\n * they stated that too. The shape the launcher's record is stored in.\n */\ninterface CornerSpot {\n readonly left: number;\n readonly top: number;\n readonly panel?: { readonly left: number; readonly top: number };\n}\n\n/** A stored `{ left, top }` pair, or null for anything that is not one. */\nfunction asPoint(value: unknown): { readonly left: number; readonly top: number } | null {\n if (typeof value !== \"object\" || value === null) {\n return null;\n }\n const { left, top } = value as { left?: unknown; top?: unknown };\n return typeof left === \"number\" && typeof top === \"number\" ? { left, top } : null;\n}\n\n/**\n * Whether a box covers the usable viewport, which is what full-bleed means.\n *\n * A pixel of slack on each axis, because a box sized from `100vw` and one sized\n * from the visual viewport disagree by sub-pixel rounding, and a panel that\n * fills the screen must not read as one that could still be moved within it.\n */\nfunction coversViewport(box: Extent, viewport: Extent): boolean {\n return box.width >= viewport.width - 1 && box.height >= viewport.height - 1;\n}\n\n/** One edge the host reserved, read off the probe's padding. */\nfunction reservedEdge(style: CSSStyleDeclaration, name: string): number {\n const value = Number.parseFloat(style.getPropertyValue(name));\n // A detached or not-yet-rendered probe resolves to nothing at all, and\n // reserving NaN is worse than reserving zero in every case.\n return Number.isFinite(value) ? value : 0;\n}\n\n/**\n * Whether a box that covers the usable viewport stands off any edge of it.\n *\n * The far edges are read against the layout viewport rather than the usable box,\n * because a keyboard shortens the second and pans the panel down inside the\n * first: a phone's full-bleed panel is correctly past the usable box's foot then,\n * and pinning it back would put its header above the screen.\n */\nfunction hangsOff(box: PanelRect, viewport: ViewportBox, screen: Extent): boolean {\n const slack = 0.5;\n return (\n box.left < viewport.left - slack ||\n box.top < viewport.top - slack ||\n box.right > screen.width + slack ||\n box.bottom > screen.height + slack\n );\n}\n\n/** A box of the same size as `box`, standing at the start of the usable viewport. */\nfunction atStartOf(viewport: ViewportBox, box: PanelRect): PanelRect {\n return {\n left: viewport.left,\n top: viewport.top,\n right: viewport.left + (box.right - box.left),\n bottom: viewport.top + (box.bottom - box.top),\n };\n}\n\n/**\n * The `--ag-ui-inset` value that pins `box` by `corner`.\n *\n * Only the two sides the corner names get a length; the other two are `auto`,\n * so the box keeps its size and grows away from that corner. Right and bottom\n * are measured from `screen`, the layout viewport, because that is what the\n * browser measures a fixed element's inset from.\n */\nfunction insetFrom(corner: ResizeAnchor, box: PanelRect, screen: Extent): string {\n const side = (value: number): string => `${Math.round(value)}px`;\n return [\n corner.y === \"top\" ? side(box.top) : \"auto\",\n corner.x === \"right\" ? side(screen.width - box.right) : \"auto\",\n corner.y === \"bottom\" ? side(screen.height - box.bottom) : \"auto\",\n corner.x === \"left\" ? side(box.left) : \"auto\",\n ].join(\" \");\n}\n\n/**\n * Every edge and corner the panel can be dragged by. Corners last, so they sit\n * above the edge strips they overlap and win the pointer at the corners.\n */\nconst RESIZE_GRIPS: readonly ResizeGrip[] = [\n { y: \"top\" },\n { y: \"bottom\" },\n { x: \"left\" },\n { x: \"right\" },\n { x: \"left\", y: \"top\" },\n { x: \"right\", y: \"top\" },\n { x: \"left\", y: \"bottom\" },\n { x: \"right\", y: \"bottom\" },\n];\n\n/**\n * What the placement needs from the element that owns it.\n *\n * Everything the element keeps private is reached through a thunk here, the\n * same shape `PanelDragOptions` and `ResizeOptions` already give their hosts:\n * read per call, so a value the element replaces later (the resolved string\n * table, the connected flag) is never captured stale.\n */\nexport interface PlacementHost {\n /** The custom element itself: its inline style, attributes and box. */\n readonly element: HTMLElement;\n /** The collapsed widget's button, which a drag moves and a resize carries. */\n readonly launcher: HTMLButtonElement;\n /** The shadow root, searched for a header mid-drag. */\n readonly root: ShadowRoot;\n /** Whether the element is in the document. */\n readonly connected: () => boolean;\n /** Whether the widget is collapsed. */\n readonly collapsed: () => boolean;\n /** Whether the current placement has a collapsed state at all. */\n readonly collapsible: () => boolean;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Read a layout preference, durable store first. */\n readonly readPreference: (base: string) => string | null;\n /** Persist a layout preference to both stores. */\n readonly writePreference: (base: string, value: string) => void;\n /** Drop a layout preference from both stores. */\n readonly clearPreference: (base: string) => void;\n /** Tell the reader the agent moved their window, with the way back. */\n readonly announceSurfaceChange: (text: string, undo: () => void) => void;\n}\n\n/**\n * Where the panel and its launcher sit, and how big the panel is: the dragged\n * launcher, the dragged header, the eight resize grips, the corner the panel\n * opens from, and the persisted record of all of it.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance, so two elements on a page place themselves independently.\n */\nexport class PanelPlacement {\n readonly #host: PlacementHost;\n\n constructor(host: PlacementHost) {\n this.#host = host;\n }\n\n /**\n * Make the header a title bar. Only while open: a collapsed widget has no\n * header on screen, and the launcher is the handle then.\n */\n enablePanelDrag(header: HTMLElement): void {\n this.#header = header;\n enablePanelDrag(header, {\n enabled: () => !this.#host.collapsed() && this.#canDragPanel(),\n rect: () => this.#host.element.getBoundingClientRect(),\n apply: (box, from) => this.#movePanel(box, from),\n commit: (box, from) => this.#commitPanel(box, from),\n });\n }\n\n /**\n * Let the launcher be dragged. Only while collapsed: the launcher is scaled\n * away and unclickable behind the open panel, so a drag there would move\n * something nobody can see.\n */\n enableLauncherDrag(signal: AbortSignal): void {\n enableLauncherDrag(this.#host.launcher, {\n signal,\n enabled: () => this.#host.collapsed() && this.#launcherDraggable(),\n rect: () => this.#launcherBox(),\n viewport: () => this.#viewport(),\n apply: (left, top) => this.#moveLauncher(left, top),\n commit: (left, top) => this.#commitLauncher(left, top),\n });\n }\n\n /** Build the eight resize grips into `chat`, with one of them in the tab order. */\n mountResizeGrips(chat: HTMLElement): void {\n // The grips a key gesture was on are gone, and a key that comes up on nothing\n // ends nothing, so an element taken out mid-gesture would otherwise come back\n // deaf to every window resize.\n this.#resizing = false;\n for (const grip of RESIZE_GRIPS) {\n const handle = createResizeHandle(grip, {\n axis: () => this.#resizeAxis(),\n rect: () => this.#host.element.getBoundingClientRect(),\n apply: (box) => {\n this.#resizing = true;\n this.#applyResize(grip, box);\n },\n commit: (box) => {\n this.#resizing = false;\n this.#commitResize(grip, box);\n },\n label: this.#host.strings().resizePanel,\n });\n // Only one of the eight is in the tab order: eight separators between the\n // transcript and the composer would be an obstacle, and one grip reaches\n // both axes. syncResizeAnchor picks the free corner, so an arrow key grows\n // the panel rather than moving it.\n handle.tabIndex = -1;\n handle.setAttribute(\"aria-hidden\", \"true\");\n this.#resizeHandles.set(gripName(grip), handle);\n chat.appendChild(handle);\n }\n this.#focusableGrip();\n }\n\n /** Restore the current placement's dragged size before the panel paints. */\n restoreSize(): void {\n // A reconnect may find the stored size gone, and a size kept inline would outlive it.\n this.#host.element.style.removeProperty(DRAG_WIDTH);\n this.#host.element.style.removeProperty(DRAG_HEIGHT);\n this.#applySize(this.#readSize());\n }\n\n /**\n * Swap the dragged size for the one stored under the placement just set, so a\n * floating drag never sizes a sidebar. Between two corner placements a stated\n * spot moves with the size, as on resetSize, so the launcher keeps its corner.\n * Before connect the namespace is unclaimed, and connect restores the size.\n */\n switchPlacement(previous: string | null): void {\n const element = this.#host.element;\n const sized = element.getBoundingClientRect();\n element.style.removeProperty(DRAG_WIDTH);\n element.style.removeProperty(DRAG_HEIGHT);\n if (!this.#host.connected()) {\n return;\n }\n this.#applySize(this.#readSize());\n if (surfaceFor(previous, element.getAttribute(\"collapse-to\")).launcherDraggable) {\n this.#carrySpotWithSize(sized);\n }\n }\n\n /**\n * Drop the current placement's dragged size and its stored copy, so the\n * placement's own size and the host's tokens apply again; other placements\n * keep theirs. For a host entering a sized state of its\n * own, which a user's drag would otherwise outrank.\n *\n * A docked panel the user dragged off its dock goes back to it as well, and\n * the stored spot with it: there the position is part of the same resting\n * state the host is asking for. A corner panel keeps a dragged position, as\n * it always has.\n */\n resetSize(): void {\n const sized = this.#host.element.getBoundingClientRect();\n this.#host.element.style.removeProperty(DRAG_WIDTH);\n this.#host.element.style.removeProperty(DRAG_HEIGHT);\n this.#writeSizes(this.#bucket(), null);\n if (this.#docked()) {\n if (this.#dockPos !== null) {\n this.#host.element.style.removeProperty(\"--ag-ui-inset\");\n }\n this.#dockPos = null;\n this.#storeDockPosition(null);\n // A size the host holds does not change here, so no observer is coming to\n // stand a panel that fills the window back on the screen.\n this.#placeDocked();\n } else {\n this.#carrySpotWithSize(sized);\n }\n // The anchor was measured against the dragged box; the resting one may\n // pin different edges.\n this.syncResizeAnchor();\n }\n\n /**\n * Stand the larger panel back on the screen once the element has stamped the\n * maximized state, whose rules size the box outright, over any dragged size\n * still held inline. The stored size and every stored spot are kept: restore\n * puts them back.\n */\n enterMaximized(): void {\n this.#replace();\n }\n\n /** Put the stored size back once the element has left the maximized state. */\n leaveMaximized(): void {\n this.restoreSize();\n this.#replace();\n }\n\n /** Re-place the panel from the record after its size changed under it. */\n #replace(): void {\n if (this.#docked()) {\n this.#placeDocked();\n } else {\n this.restoreLauncherPosition();\n }\n this.syncResizeAnchor();\n }\n\n /**\n * Carry a stated corner spot along with a dragged size coming off.\n *\n * The size comes off toward the corner the layout holds still, so the top-left\n * the spot is kept as moves with it, and a restore from the old one would swing\n * the panel away from its launcher. Only that movement goes onto the spot, not\n * where the box stands: in a window narrower than the spot the box is held\n * short of it, and that is not something the user stated.\n *\n * Left alone while a host's own size is in force, because that cannot be told\n * from the dragged size coming off, and it may be a state the host is about to\n * leave: counting it would throw the spot off by as much as that state is\n * bigger. A panel that is the screen needs no case of its own: the small-viewport\n * block ignores a dragged size, so its box does not move.\n *\n * Left alone too under data-launcher-drag=\"false\", where a spot left over from\n * before the attribute is a record kept for the day it comes off, and nothing\n * that happens to the box now is a statement about it.\n */\n #carrySpotWithSize(sized: DOMRect): void {\n const element = this.#host.element;\n const box = element.getBoundingClientRect();\n const spot = this.#cornerSpot ?? this.#readLauncherPosition();\n const style = getComputedStyle(element);\n if (\n spot?.panel === undefined ||\n !this.#launcherDraggable() ||\n style.getPropertyValue(\"--ag-ui-width\") !== \"\" ||\n style.getPropertyValue(\"--ag-ui-height\") !== \"\"\n ) {\n return;\n }\n this.#writeCornerSpot({\n ...spot,\n panel: {\n left: spot.panel.left + box.left - sized.left,\n top: spot.panel.top + box.top - sized.top,\n },\n });\n }\n\n /**\n * A zero-sized box carrying the host's viewport insets as padding, so they\n * can be read back as used pixel lengths. See the `.viewport-probe` rule for\n * why a custom property cannot be read directly.\n */\n readonly probe = document.createElement(\"div\");\n\n /**\n * Where the user dragged the launcher, in viewport coordinates, or null\n * while the host's own CSS still places it. Set means this element owns its\n * position -- see #applyLauncherPlacement for what that costs the host.\n */\n #launcherPos: { readonly left: number; readonly top: number } | null = null;\n\n /**\n * Where the user dragged the *panel*, in viewport coordinates, or null while\n * its position is still derived from the launcher's.\n *\n * The two gestures state different things and are restored differently. A\n * launcher drag says where the bubble goes and leaves the panel to open into\n * whatever space the viewport has, so it is re-derived every time -- which is\n * what lets a widget re-decide its direction when the window changes under\n * it. A header drag states the panel's own position, and re-deriving that\n * from the launcher would move the panel the user just placed.\n */\n #panelPos: { readonly left: number; readonly top: number } | null = null;\n\n /**\n * The spot #launcherPos and #panelPos were last stated as, or null while\n * nothing has been stated since this element connected.\n *\n * Those two say where the launcher and the panel stand now, held inside the\n * viewport, because that is where a press finds them and a drag starts from.\n * This is what the user asked for, kept apart so that a window narrower than\n * the spot, or a phone that took the panel full-bleed, gives it back unchanged\n * once there is room again. Only a gesture, a move or a dragged size coming\n * off changes it; re-applying it against a viewport never does, so a clamped\n * position never quietly becomes the record.\n */\n #cornerSpot: CornerSpot | null = null;\n\n /**\n * The inset a grip wrote on a corner panel with no spot, or null. A grip on an\n * edge the layout holds moves the panel without stating a spot, so this is the\n * only way to tell its inline inset from one a host wrote there, which stays,\n * and to give it back once a phone has taken the panel full-bleed.\n */\n #gripInset: string | null = null;\n\n /**\n * The inset standing a panel at the start of a window a host's size fills, or\n * null: a corner panel with no spot, or a docked one with or without one. Told\n * apart from a host's own for the same reason, and it lasts only as long as that\n * size does.\n */\n #fillInset: string | null = null;\n\n /**\n * Where the user dragged a docked panel, in viewport coordinates, or null\n * while it stands on the bar or the anchor.\n *\n * Apart from the two corner positions above because it moves nothing else:\n * a docked panel has no launcher to carry, and the corner it opens from is\n * the dock's. Held as the user stated it and never as clamped, so a bar that\n * grew, or a phone that took the panel full-bleed, gives the spot back\n * unchanged once there is room for it again.\n */\n #dockPos: { readonly left: number; readonly top: number } | null = null;\n\n /**\n * The line a docked panel stays above, in viewport coordinates: the bar's\n * top, or the anchor's. Infinite where neither is drawn. Measured by\n * syncDock, which runs on every change either can make.\n */\n #dockTop = Number.POSITIVE_INFINITY;\n /**\n * The line a panel docked below its anchor stays below: the anchor's bottom.\n * Negative infinity on every other dock.\n */\n #dockFloor = Number.NEGATIVE_INFINITY;\n /** The side of the anchor the panel last stood on, held while a gesture runs. */\n #anchorSide: AnchorSide = \"above\";\n /** The bar's height, as last measured: what a fill takes away when it stamps. */\n #barHeight = 0;\n /**\n * What the usable box and the window measured when a fill took the bar away, and what\n * the bar was. Null while no fill holds it. See {@link #fillRoom}.\n */\n #barTaken: { readonly room: number; readonly window: number; readonly bar: number } | null = null;\n\n /**\n * The corner the panel opens away from, once this element is placing itself.\n * Null means the host's layout still decides, and the anchor is measured.\n */\n #expandCorner: ExpandCorner | null = null;\n\n /**\n * The edges the layout is holding still, as last measured. Cached because a\n * resize reads it per pointer move and measuring forces a reflow -- thirty a\n * second while the panel is already being laid out on every one of them.\n */\n #anchor: ResizeAnchor = { x: \"right\", y: \"bottom\" };\n\n /** The header the panel drag listens on, stamped by #stampHeader. */\n #header: HTMLElement | null = null;\n\n /** Whether a grip has applied a box it has not committed yet. */\n #resizing = false;\n\n /** The eight grips, by name, so the keyboard-reachable one can be moved. */\n readonly #resizeHandles = new Map<string, HTMLDivElement>();\n\n /**\n * Hold a resized box inside the part of the screen the host left free.\n *\n * Each edge on its own, unlike the drag's clamp: a drag moves a box of fixed\n * size, so pushing it back in is right, while a resize is anchored on the\n * opposite edge and pushing it back would move the edge the user is not\n * touching. Bounding each edge instead leaves the grip stopped at the limit\n * -- the gesture keeps going and the panel simply stops growing, which is\n * what dragging already does.\n *\n * The minimum size is the grip's own concern and is applied before this, so\n * a panel that cannot fit the space is left at its minimum and overflowing\n * rather than collapsed to nothing.\n */\n #withinViewport(box: PanelRect): PanelRect {\n // A docked panel that moves has its room stop at the dock, so no grip\n // pulls it over the bar it minimises to. A placement that owns its\n // position keeps the bound it always had.\n const viewport = this.#docked() && this.#panelMovable() ? this.#dockRoom() : this.#viewport();\n // The same bound a drag stops at, so a grip pulled to the edge and a panel\n // dragged to it come to rest on the same line. The inner Math.max/min pair\n // keeps an already-inverted box from turning inside out.\n const left = viewport.left + SCREEN_EDGE_MARGIN;\n const top = viewport.top + SCREEN_EDGE_MARGIN;\n const right = viewport.left + viewport.width - SCREEN_EDGE_MARGIN;\n const bottom = viewport.top + viewport.height - SCREEN_EDGE_MARGIN;\n return {\n left: Math.min(Math.max(box.left, left), box.right),\n top: Math.min(Math.max(box.top, top), box.bottom),\n right: Math.max(Math.min(box.right, right), box.left),\n bottom: Math.max(Math.min(box.bottom, bottom), box.top),\n };\n }\n\n /**\n * Whether a pointer or key gesture is currently placing the widget.\n *\n * Read from the stamp the drag helpers already set, rather than tracked\n * separately: one source of truth, and it clears on `pointercancel` as well\n * as `pointerup`, which is the end a touch gesture usually gets. The one\n * gesture that stamps nothing is an arrow key on a grip, which applies a box\n * per key and states it only when the key comes up, hence #resizing.\n */\n dragging(): boolean {\n return (\n this.#resizing ||\n this.#host.launcher.hasAttribute(\"data-dragging\") ||\n this.#host.root.querySelector(\".header[data-dragging], .resize-handle[data-dragging]\") !==\n null\n );\n }\n\n /** The report behind `AgUiChat.describeSurface`, whose doc is the contract. */\n describeSurface(): ChatSurfaceReport {\n const box = this.#host.element.getBoundingClientRect();\n const viewport = this.#viewport();\n const fullBleed = coversViewport(box, this.#fillRoom());\n return {\n placement: this.#host.element.getAttribute(\"placement\"),\n collapseTo: this.#surface().collapseTo,\n collapsed: this.#host.collapsed(),\n collapsible: this.#host.collapsible(),\n maximized: this.#host.element.hasAttribute(\"maximized\"),\n movable: this.#panelMovable() && !fullBleed,\n // The page's setting alone, true unless `data-launcher-drag=\"false\"`, so\n // it does not change with `collapse-to`; whether this panel moves is `movable`.\n draggable: this.#host.element.getAttribute(\"data-launcher-drag\") !== \"false\",\n fullBleed,\n box: {\n left: Math.round(box.left),\n top: Math.round(box.top),\n width: Math.round(box.width),\n height: Math.round(box.height),\n },\n viewport: {\n left: Math.round(viewport.left),\n top: Math.round(viewport.top),\n width: Math.round(viewport.width),\n height: Math.round(viewport.height),\n },\n };\n }\n\n /** The move behind `AgUiChat.moveTo`, whose doc is the contract. */\n moveTo(corner: ChatCorner, options: { readonly announce?: boolean } = {}): boolean {\n if (!this.#panelMovable()) {\n return false;\n }\n const restore = options.announce === true ? this.#captureGeometry() : null;\n const viewport = this.#viewport();\n const box = this.#host.element.getBoundingClientRect();\n if (coversViewport(box, this.#fillRoom())) {\n return false;\n }\n const [edgeY, edgeX] = corner.split(\"-\");\n // A docked panel's bottom corners are above its dock, not on the bar.\n const docked = this.#docked();\n const room = docked ? this.#dockRoom() : viewport;\n // Every term is an absolute screen coordinate, because that is what the\n // clamps and the insets both speak. The usable box carries an origin, so\n // its near edge is `viewport.left`, not zero, and its far edge is\n // `viewport.left + viewport.width` -- a margin applied to the extents\n // alone would send the agent's own move under the chrome the host\n // reserved, which is the failure the usable box exists to prevent.\n const nearX = room.left + EDGE_MARGIN;\n const nearY = room.top + EDGE_MARGIN;\n const left =\n edgeX === \"left\" ? nearX : Math.max(nearX, room.left + room.width - EDGE_MARGIN - box.width);\n const top =\n edgeY === \"top\" ? nearY : Math.max(nearY, room.top + room.height - EDGE_MARGIN - box.height);\n const host = { left, top, right: left + box.width, bottom: top + box.height };\n if (docked) {\n this.#dockPos = { left, top };\n this.#writeDockInset(host);\n this.#storeDockPosition(this.#dockPos);\n if (restore !== null) {\n this.#host.announceSurfaceChange(this.#host.strings().chatMoved, restore);\n }\n return true;\n }\n // Both axes measured, rather than one read twice: a host can restyle the\n // launcher as a pill, and squaring it here would put it off the corner.\n const launcherWidth = this.#host.launcher.offsetWidth;\n const launcherHeight = this.#host.launcher.offsetHeight;\n this.#placePanelAndLauncher(host, {\n left: edgeX === \"left\" ? host.left : host.right - launcherWidth,\n top: edgeY === \"top\" ? host.top : host.bottom - launcherHeight,\n width: launcherWidth,\n height: launcherHeight,\n });\n this.#storeLauncherPosition();\n if (restore !== null) {\n this.#host.announceSurfaceChange(this.#host.strings().chatMoved, restore);\n }\n return true;\n }\n\n /**\n * Snapshot the panel's stated position, and return a function that puts it\n * back.\n *\n * Both insets and the expand corner, because they are one decision: the\n * corner is what the panel grows from, so restoring a position without it\n * puts the box back and animates it out of the wrong side. Absent values are\n * captured as absent and removed on the way back, rather than written as\n * empty strings that would outrank the placement. And what the inset is, because\n * one put back with no record of having come from a grip or a fill reads as a\n * host's own, and a phone would leave it holding the panel off the screen.\n *\n * The surface may have changed by the time of the undo, so the two halves are\n * put back apart. Both records are, always, each to its own store, so the\n * memory and the storage cannot disagree and the surface they belong to finds\n * them when it comes back. The inline values only mean something to the surface\n * they were read from: written on any other, they pin a sidebar to where a\n * floating panel used to be.\n */\n #captureGeometry(): () => void {\n const inset = this.#host.element.style.getPropertyValue(\"--ag-ui-inset\");\n const launcherInset = this.#host.element.style.getPropertyValue(\"--ag-ui-launcher-inset\");\n const corner = this.#host.element.getAttribute(\"data-expand-corner\");\n const launcherPos = this.#launcherPos;\n const panelPos = this.#panelPos;\n const dockPos = this.#dockPos ?? this.#readDockPosition();\n const expandCorner = this.#expandCorner;\n const gripInset = this.#gripInset;\n const fillInset = this.#fillInset;\n const cornerSpot = this.#cornerSpot ?? this.#readLauncherPosition();\n const owner = this.#positionOwner();\n return () => {\n this.#dockPos = dockPos;\n this.#storeDockPosition(dockPos);\n // Erased rather than rewritten when there was nothing to go back to,\n // which would leave the move this is undoing sitting in storage -- and\n // since that store outlives the tab, the next resize or reload would\n // quietly put the panel back in the corner the user had just rejected.\n if (cornerSpot === null) {\n this.#cornerSpot = null;\n this.#host.clearPreference(LAUNCHER_KEY);\n } else {\n this.#writeCornerSpot(cornerSpot);\n }\n if (owner === this.#positionOwner()) {\n this.#restoreProperty(\"--ag-ui-inset\", inset);\n this.#restoreProperty(\"--ag-ui-launcher-inset\", launcherInset);\n if (corner === null) {\n this.#host.element.removeAttribute(\"data-expand-corner\");\n } else {\n this.#host.element.setAttribute(\"data-expand-corner\", corner);\n }\n this.#launcherPos = launcherPos;\n this.#panelPos = panelPos;\n this.#expandCorner = expandCorner;\n this.#gripInset = gripInset;\n this.#fillInset = fillInset;\n } else {\n this.#forgetCornerPosition();\n }\n // Against the viewport there is now, which may be a phone's: the insets\n // put back above were written for the one the move was made in.\n this.restoreLauncherPosition();\n this.syncResizeAnchor();\n };\n }\n\n /** Which of the three kinds of surface decides where the panel stands. */\n #positionOwner(): \"dock\" | \"corner\" | \"placement\" {\n if (this.#docked()) {\n return \"dock\";\n }\n return this.#surface().launcherDraggable ? \"corner\" : \"placement\";\n }\n\n /**\n * Which axes the current placement allows.\n *\n * A full-bleed layout is `100vw`/`100vh` by definition and cannot be resized\n * at all; a docked panel owns its height, leaving only its inner edge. Read\n * per interaction, because `placement` is a live attribute.\n */\n #resizeAxis(): ResizeAxis {\n // Refused while maximized, so restore always lands on the size stored before it.\n return this.#host.element.hasAttribute(\"maximized\") ? \"none\" : this.#surface().resizeAxis;\n }\n\n /**\n * Which edges the layout is holding still, by measuring rather than guessing:\n * nudge the size by a pixel, see which edges stayed put, and undo. One forced\n * reflow per drag.\n *\n * `placement` cannot answer this \u2014 an embedded panel goes wherever the page's\n * CSS puts it \u2014 and see {@link createResizeHandle} for why guessing produces\n * a visibly broken control.\n */\n #measureAnchor(): ResizeAnchor {\n const before = this.#host.element.getBoundingClientRect();\n const width = this.#host.element.style.getPropertyValue(DRAG_WIDTH);\n const height = this.#host.element.style.getPropertyValue(DRAG_HEIGHT);\n // Shrink first: at a size resting against max-width or max-height a grown\n // box does not change, and every clamped axis would read as pinned on its\n // free side (the default panel is born clamped under 428px). Shrinking is\n // measured from the used width, so it always moves an edge.\n const shrunk = this.#probeAnchor(before, -1);\n // Unless a host rule sets a minimum, in which case that axis is asked the\n // opposite question rather than left to a guess.\n const grown = shrunk.x === null || shrunk.y === null ? this.#probeAnchor(before, 1) : shrunk;\n // Restore exactly what was there, including \"nothing\" \u2014 leaving a probe\n // value behind would pin a panel that had been sizing itself.\n this.#restoreProperty(DRAG_WIDTH, width);\n this.#restoreProperty(DRAG_HEIGHT, height);\n return {\n // Neither direction moved it: the axis cannot be resized at all, so the\n // floating default is the best answer available and is the one the\n // stylesheet would have used with no measurement at all.\n x: shrunk.x ?? grown.x ?? \"right\",\n y: shrunk.y ?? grown.y ?? \"bottom\",\n };\n }\n\n /**\n * Which edge each axis holds still when the panel changes size by `delta`.\n *\n * Null for an axis whose size did not change: nothing moved, so nothing was\n * learned, and reporting the unmoved edge as the pinned one would be exactly\n * backwards.\n */\n #probeAnchor(\n before: DOMRect,\n delta: number,\n ): { x: \"left\" | \"right\" | null; y: \"top\" | \"bottom\" | null } {\n this.#applySize({ width: before.width + delta, height: before.height + delta });\n const after = this.#host.element.getBoundingClientRect();\n const moved = (a: number, b: number): boolean => Math.abs(a - b) >= 0.5;\n return {\n x: moved(after.width, before.width)\n ? moved(after.left, before.left)\n ? \"right\"\n : \"left\"\n : null,\n y: moved(after.height, before.height)\n ? moved(after.top, before.top)\n ? \"bottom\"\n : \"top\"\n : null,\n };\n }\n\n /** Stamp the measured anchor so the shadow CSS can place the grip. */\n syncResizeAnchor(): void {\n if (!this.#host.connected()) {\n return;\n }\n // When this element owns its position it knows which edges are pinned --\n // it just wrote them -- so there is nothing to probe. The probe is also\n // unreliable at a size resting against max-width or max-height, where a\n // nudge moves no edge and every axis reads as pinned on the wrong side.\n const anchor = this.#expandCorner ?? this.#measureAnchor();\n this.#anchor = anchor;\n this.#host.element.setAttribute(\"data-resize-anchor\", `${anchor.y}-${anchor.x}`);\n this.#focusableGrip();\n this.#stampHeader();\n }\n\n /**\n * Tell the stylesheet whether the panel is the screen, for the header's cursor.\n *\n * Only this half of what refuses a header drag: the resting rules already answer\n * for the placement and for data-launcher-drag=\"false\", and neither of those\n * re-applies anything when it changes, so a stamp taking them in would go on\n * refusing, in the cursor, a drag the header would take.\n */\n #stampHeader(): void {\n this.#header?.toggleAttribute(\"data-fills-screen\", this.#fillsScreen());\n // And for the bar and the grips, which go while it does. The next frame, because\n // this runs inside the transcript's observer, and the bar it takes away sits\n // above that in the tree: its own observer would be left undelivered, which the\n // browser reports on the window, where a host's error tracking counts it.\n const element = this.#host.element;\n if (this.#fillsWindow() !== element.hasAttribute(\"data-fills-window\")) {\n requestAnimationFrame(() => {\n const fills = this.#fillsWindow();\n if (fills !== element.hasAttribute(\"data-fills-window\")) {\n this.#barTaken = fills\n ? { room: this.#viewport().height, window: this.#screen().height, bar: this.#barHeight }\n : null;\n element.toggleAttribute(\"data-fills-window\", fills);\n }\n });\n }\n }\n\n /**\n * Whether the panel fills the window in a placement it can move in. Not one that owns\n * its position: full stops at the bar, so taking the bar away would make it fill the\n * window, and that would take the bar away for good.\n */\n #fillsWindow(): boolean {\n return this.#fillsScreen() && this.#surface().panelMovable;\n }\n\n /** Put a custom property back to a previous value, or remove it if there was none. */\n #restoreProperty(name: string, value: string): void {\n if (value === \"\") {\n this.#host.element.style.removeProperty(name);\n return;\n }\n this.#host.element.style.setProperty(name, value);\n }\n\n /**\n * Write a dragged size onto the host, on the axes this placement leaves free.\n *\n * Writing a custom property rather than inline `width` / `height` does not\n * by itself leave placement in charge: an inline custom property still\n * outranks a `:host([placement=\u2026])` rule setting the same property, so a\n * height dragged while floating would cap a docked sidebar asking for\n * `100vh`. The cascade cannot arbitrate this, so the axis check must \u2014 a\n * placement owns the axes it fixes, and a persisted size is applied only to\n * the ones it leaves free.\n */\n #applySize(size: ResizeSize): void {\n const axis = this.#resizeAxis();\n if (axis === \"none\") {\n return;\n }\n // The placement's max-width and max-height are left alone, so a grip pushed\n // against the edge the placement is not anchored to stops one gutter short:\n // moving the cap would shift several resting sizes by a pixel. Staying inside\n // what the host left free is enforced by #withinViewport.\n if (size.width !== undefined) {\n this.#host.element.style.setProperty(DRAG_WIDTH, `${size.width}px`);\n }\n if (size.height !== undefined && axis === \"both\") {\n this.#host.element.style.setProperty(DRAG_HEIGHT, `${size.height}px`);\n }\n }\n\n /**\n * Drop any dragged size the new placement has taken ownership of.\n *\n * Without this a size survives the switch as an inline property and silently\n * overrides the placement it moved to \u2014 the panel keeps a floating height\n * while docked, and reads as a component that cannot do full height.\n */\n releaseOwnedAxes(): void {\n const axis = this.#resizeAxis();\n if (axis !== \"both\") {\n this.#host.element.style.removeProperty(DRAG_HEIGHT);\n }\n if (axis === \"none\") {\n this.#host.element.style.removeProperty(DRAG_WIDTH);\n }\n }\n\n /** The surface the live placement and collapse-to attributes describe. */\n #surface(): Surface {\n const element = this.#host.element;\n return surfaceFor(element.getAttribute(\"placement\"), element.getAttribute(\"collapse-to\"));\n }\n\n /**\n * Whether the panel rises from the bottom bar or the host's anchor, until the\n * user drags it somewhere else.\n */\n #docked(): boolean {\n const target = this.#surface().collapseTo;\n return target === \"bar\" || target === \"none\";\n }\n\n /**\n * Write where a docked panel stands, and return the bar's height.\n *\n * Under the bar it is the strip's border box, which is 0 whenever the strip\n * is not drawn (a phone with the panel open, where the panel is the screen).\n * Under a host anchor it is the anchor's top, or its bottom on the side below,\n * and its right, measured against the\n * layout viewport a fixed element is placed in; an anchor of null leaves the\n * panel in its placement's own corner. Every other surface carries neither\n * property, so nothing stale is left behind by a live switch.\n */\n syncDock(bar: HTMLElement, anchor: Element | null): number {\n const element = this.#host.element;\n const target = this.#surface().collapseTo;\n const height = target === \"bar\" ? bar.offsetHeight : 0;\n const rect = target === \"none\" && anchor !== null ? anchor.getBoundingClientRect() : null;\n const side = rect === null ? null : this.#resolveSide(rect);\n if (target === \"bar\") {\n element.style.setProperty(DOCK_BOTTOM, `${height}px`);\n } else if (rect !== null && side === \"above\") {\n element.style.setProperty(DOCK_BOTTOM, `${Math.max(0, this.#screen().height - rect.top)}px`);\n } else {\n element.style.removeProperty(DOCK_BOTTOM);\n }\n if (rect !== null && side === \"below\") {\n element.style.setProperty(DOCK_TOP, `${Math.max(0, rect.bottom)}px`);\n } else {\n element.style.removeProperty(DOCK_TOP);\n }\n if (rect !== null) {\n element.style.setProperty(DOCK_RIGHT, `${this.#dockRight(rect)}px`);\n } else {\n element.style.removeProperty(DOCK_RIGHT);\n }\n if (side === null) {\n element.removeAttribute(\"data-dock-anchored\");\n } else {\n element.setAttribute(\"data-dock-anchored\", side);\n }\n this.#barHeight = height;\n if (target !== \"bar\") {\n this.#barTaken = null;\n }\n this.#dockTop =\n target === \"bar\" && height > 0\n ? bar.getBoundingClientRect().top\n : rect !== null && side === \"above\"\n ? rect.top\n : Number.POSITIVE_INFINITY;\n this.#dockFloor = rect !== null && side === \"below\" ? rect.bottom : Number.NEGATIVE_INFINITY;\n // Every change the dock can make passes through here -- the bar's height\n // arrives by a ResizeObserver after the first restore, and a bar that grew\n // since the drag would otherwise cover the panel's foot -- so the dragged\n // spot is held against it here rather than only when it is restored.\n this.#placeDocked();\n return height;\n }\n\n /**\n * The part of the usable viewport a docked panel may stand in: all of it\n * above the dock's line. The bar is what it minimises to, and the anchor is\n * the host's own way back, so a dragged panel never covers either.\n */\n #dockRoom(): ViewportBox {\n const viewport = this.#viewport();\n const top = Math.max(viewport.top, this.#dockFloor);\n const bottom = Math.min(viewport.top + viewport.height, this.#dockTop);\n return { ...viewport, top, height: Math.max(0, bottom - top) };\n }\n\n /**\n * The side of the anchor the panel opens on: the host's anchor-side, or under\n * auto the side with more of the usable viewport, kept while a gesture runs.\n */\n #resolveSide(rect: DOMRect): AnchorSide {\n const stated = this.#host.element.getAttribute(\"anchor-side\");\n if (stated === \"above\" || stated === \"below\") {\n this.#anchorSide = stated;\n } else if (!this.dragging()) {\n const viewport = this.#viewport();\n const below = viewport.top + viewport.height - rect.bottom;\n this.#anchorSide = below > rect.top - viewport.top ? \"below\" : \"above\";\n }\n return this.#anchorSide;\n }\n\n /**\n * The panel's distance from the right edge: on the anchor's right, unless a\n * panel that wide would then cross the gutter on the left of the usable box,\n * and never inside the gutter on the right of it.\n */\n #dockRight(rect: DOMRect): number {\n const screen = this.#screen();\n const fits =\n screen.width - this.#viewport().left - EDGE_MARGIN - this.#host.element.offsetWidth;\n const floor = EDGE_MARGIN + reservedEdge(getComputedStyle(this.probe), \"padding-right\");\n return Math.max(floor, Math.min(screen.width - rect.right, fits));\n }\n\n /**\n * Put a docked panel back where the user dragged it, held inside its room.\n *\n * The inline inset comes off first, which is both how the panel's resting\n * box is measured and what leaves a phone full-bleed: the small-viewport\n * block reads the host's inset before its own, so a dragged spot written\n * there would hold the panel off the screen's edges. The spot itself stays,\n * for the next time there is room for it.\n *\n * A host's size that makes the panel the window hangs it off the resting inset's\n * far side, past the top of the window with the header on it under the bar, so\n * it stands at the start of the room instead, moved or not, as a corner panel\n * does, and the stylesheet takes the bar away for as long as it does. A placement\n * that owns its position keeps it, whatever the host's size.\n *\n * Under data-launcher-drag=\"false\" a spot from before the attribute is left alone\n * while the panel is on the screen, as a corner panel's is, and the record stays\n * for the day the attribute comes off.\n */\n #placeDocked(): void {\n if (!this.#docked() || !this.#surface().panelMovable || this.dragging()) {\n return;\n }\n const element = this.#host.element;\n const at = this.#panelMovable() ? (this.#dockPos ?? this.#readDockPosition()) : null;\n if (at === null) {\n if (this.#dockPos !== null) {\n const filling = element.style.getPropertyValue(\"--ag-ui-inset\") === this.#fillInset;\n if (!filling && !this.#offScreen()) {\n return;\n }\n this.#dockPos = null;\n element.style.removeProperty(\"--ag-ui-inset\");\n }\n this.#placeUnstated();\n return;\n }\n this.#dockPos = at;\n element.style.removeProperty(\"--ag-ui-inset\");\n const rest = element.getBoundingClientRect();\n const viewport = this.#viewport();\n if (coversViewport(rest, this.#fillRoom())) {\n if (hangsOff(rest, viewport, this.#screen())) {\n this.#standAtStart(rest);\n }\n return;\n }\n // Measured at the dock, so the inset below is written from the corner the\n // dock holds still and a resize grows the panel away from it.\n this.syncResizeAnchor();\n this.#writeDockInset(\n clampPanel(\n { left: at.left, top: at.top, right: at.left + rest.width, bottom: at.top + rest.height },\n this.#dockRoom(),\n SCREEN_EDGE_MARGIN,\n ),\n );\n }\n\n /** Write the inset that stands a docked panel at `box`. */\n #writeDockInset(box: PanelRect): void {\n this.#host.element.style.setProperty(\n \"--ag-ui-inset\",\n insetFrom(this.#anchor, box, this.#screen()),\n );\n }\n\n /** Remember a docked panel's dragged spot, or forget it for null. */\n #storeDockPosition(at: { readonly left: number; readonly top: number } | null): void {\n if (at === null) {\n this.#host.clearPreference(DOCK_KEY);\n return;\n }\n this.#host.writePreference(DOCK_KEY, JSON.stringify({ left: at.left, top: at.top }));\n }\n\n /** The stored spot of a docked panel, or null for none or anything corrupt. */\n #readDockPosition(): { readonly left: number; readonly top: number } | null {\n const raw = this.#host.readPreference(DOCK_KEY);\n if (raw === null) {\n return null;\n }\n try {\n return asPoint(JSON.parse(raw));\n } catch {\n return null;\n }\n }\n\n /**\n * Whether the header drag and moveTo may move the open panel: the\n * placement's answer, unless the host turned moving off.\n */\n #panelMovable(): boolean {\n return (\n this.#host.element.getAttribute(\"data-launcher-drag\") !== \"false\" &&\n this.#surface().panelMovable\n );\n }\n\n /**\n * Whether a header drag may start now. A panel that is the screen, on a phone\n * or by a host's own sizing, has nowhere to go, and a drag there would pull it\n * off the edges it fills.\n */\n #canDragPanel(): boolean {\n return this.#panelMovable() && !this.#fillsScreen();\n }\n\n /** Whether the panel covers the usable viewport, as it stands now. */\n #fillsScreen(): boolean {\n return coversViewport(this.#host.element.getBoundingClientRect(), this.#fillRoom());\n }\n\n /**\n * The box a fill is judged against: the usable one, unless taking the bar away is\n * what grew it.\n *\n * A host can write the bar's height into the inset it reserves. The panel fills the\n * box that leaves, so the bar goes, the height says 0, the host writes that, the box\n * grows by what the bar took, and the panel no longer fills it. Judged against that,\n * the bar comes back and it all goes round again every frame without end. So on the\n * same window, a box grown by the bar's height is the box it was, and the panel\n * stands where it stood with the bar gone. Grown by anything else, or on a window of\n * another size, it is a change of the host's or the reader's and is judged as one.\n * The slack is the pixel a host rounding the height up can add.\n */\n #fillRoom(): ViewportBox {\n const viewport = this.#viewport();\n const taken = this.#barTaken;\n if (\n taken !== null &&\n taken.window === this.#screen().height &&\n Math.abs(viewport.height - taken.room - taken.bar) <= 1\n ) {\n return { ...viewport, height: taken.room };\n }\n return viewport;\n }\n\n /**\n * Whether the panel stands off an edge of the screen, as it stands now.\n *\n * The screen rather than the usable box: a panel under chrome the host reserved\n * has its controls where the host can still bring them back, and is not what a\n * position kept under data-launcher-drag=\"false\" has to give way to.\n */\n #offScreen(): boolean {\n const screen = this.#screen();\n return hangsOff(\n this.#host.element.getBoundingClientRect(),\n { left: 0, top: 0, ...screen },\n screen,\n );\n }\n\n /**\n * Whether this placement lets the launcher be dragged, read per interaction\n * because `placement` is a live attribute. `data-launcher-drag=\"false\"` opts\n * a host out without giving up the launcher itself.\n */\n #launcherDraggable(): boolean {\n return (\n this.#host.element.getAttribute(\"data-launcher-drag\") !== \"false\" &&\n this.#surface().launcherDraggable\n );\n }\n\n /**\n * The viewport the launcher and the panel both have to fit inside.\n *\n * The *visual* viewport, not the layout one, because they come apart exactly\n * when this matters. An on-screen keyboard shrinks the visual viewport and\n * leaves the layout viewport alone, so clamping against `innerHeight` parks\n * the launcher behind the keyboard and decides which corner to open into\n * using space that is not on the screen. Pinch-zoom does the same on both\n * axes.\n *\n * Falls back where the API is absent, which keeps this working in the\n * happy-dom project as well as in an old browser.\n */\n #viewport(): ViewportBox {\n const visual = window.visualViewport;\n const width = visual?.width ?? window.innerWidth;\n const height = visual?.height ?? window.innerHeight;\n // And minus whatever the host reserved for its own chrome. Without this a\n // panel is clamped against the whole screen and settles happily underneath\n // a sticky header, where it cannot be reached -- and where collapsing it,\n // the one thing a user tries, hides it completely rather than rescuing it.\n // Read as padding off the probe, not as custom properties off this\n // element. `getPropertyValue` on an unregistered custom property returns\n // the token stream rather than a length, so a host stating `4rem` reserves\n // four pixels here and sixty-four in the stylesheet, and one stating\n // `calc(56px + env(safe-area-inset-top))` -- which is the natural spelling\n // of what the token's own documentation recommends -- parses as NaN and\n // takes the panel's whole inset down with it.\n const style = getComputedStyle(this.probe);\n const left = reservedEdge(style, \"padding-left\");\n const top = reservedEdge(style, \"padding-top\");\n return {\n left,\n top,\n width: Math.max(0, width - left - reservedEdge(style, \"padding-right\")),\n height: Math.max(0, height - top - reservedEdge(style, \"padding-bottom\")),\n };\n }\n\n /**\n * The whole viewport, before anything the host reserved is taken out of it.\n *\n * Distinct from {@link #viewport} on purpose, and the two must not be\n * swapped. The usable box decides where the widget may rest; this is what a\n * CSS `inset` on a fixed element is measured from, because that is what the\n * browser measures it from.\n */\n #screen(): Extent {\n // The *layout* viewport, and `clientWidth`/`clientHeight` rather than\n // `innerWidth`/`innerHeight`, because those two disagree by the width of a\n // classic scrollbar and it is the smaller one a fixed element is laid out\n // against. Reading the visual viewport here would be the same mistake one\n // level up as clamping against the whole screen was one level down: a\n // keyboard shrinks the visual viewport without moving the box CSS measures\n // an inset from, so a panel the clamp had just held inside the visible\n // band would be written back out behind the keyboard.\n //\n // The zero checks are for a detached or not-yet-laid-out document, where\n // `clientWidth` is 0 and no viewport ever is.\n const root = document.documentElement;\n return {\n width: root.clientWidth || window.innerWidth,\n height: root.clientHeight || window.innerHeight,\n };\n }\n\n /**\n * Publish the measured viewport height so the stylesheet can size a\n * full-bleed panel to what the user can see.\n *\n * No CSS length carries this. An on-screen keyboard has no effect on any\n * viewport-percentage unit, so a panel sized from `100dvh` puts its composer\n * behind the keyboard being typed into. Written inline, and read through a\n * token the host's own `--ag-ui-viewport-height` still outranks.\n *\n * Removed rather than frozen when the two viewports agree, so a desktop that\n * never diverges carries no inline override at all and the declared fallback\n * stays in charge.\n */\n publishVisualViewport(): void {\n const visual = window.visualViewport;\n if (visual === null || visual === undefined) {\n return;\n }\n // The layout viewport from the box a fixed element is laid out against,\n // for the reasons #screen gives -- and one more that only a phone shows.\n // While iOS Safari has the visible area panned down to show a focused\n // field, innerHeight reads the layout height less the pan, and goes on\n // reading it until a window scroll the element never hears about. Measured\n // from that, the band below came out as nothing, and at the deepest pan the\n // browser makes -- the one that shows a composer docked at the foot of the\n // screen -- the shorter number equals the visible height, so the check\n // below took every measurement back and put the panel at the layout top at\n // full height, its header above the screen. clientHeight held the layout\n // height throughout.\n const layout = this.#screen().height;\n if (Math.abs(visual.height - layout) < 1) {\n this.#host.element.style.removeProperty(\"--ag-ui-visual-viewport-height\");\n this.#host.element.style.removeProperty(\"--ag-ui-visual-viewport-inset-bottom\");\n this.#host.element.style.removeProperty(\"--ag-ui-visual-viewport-inset-top\");\n return;\n }\n this.#host.element.style.setProperty(\n \"--ag-ui-visual-viewport-height\",\n `${Math.round(visual.height)}px`,\n );\n // What is hidden below the visible area, which is where a keyboard is. A\n // shorter panel does not help anything anchored to the bottom: a floating\n // widget is positioned against the layout viewport, so its bottom edge and\n // the launcher at that corner stay behind the keyboard until this lifts\n // them. Never negative -- a visual viewport panned up past the layout one\n // would otherwise pull the panel down off the screen.\n const hidden = layout - visual.height - visual.offsetTop;\n this.#host.element.style.setProperty(\n \"--ag-ui-visual-viewport-inset-bottom\",\n `${Math.max(0, Math.round(hidden))}px`,\n );\n // And what is hidden above it. To show a field the keyboard would cover, a\n // browser pans the visual viewport down the layout one, and a fixed panel\n // anchored at the top stays at the layout top: sized to the visible height,\n // it then shows only its lower part, from the pan down, with its header off\n // the screen and page background under it. Never negative, for the same\n // reason as the band below.\n this.#host.element.style.setProperty(\n \"--ag-ui-visual-viewport-inset-top\",\n `${Math.max(0, Math.round(visual.offsetTop))}px`,\n );\n }\n\n /**\n * The launcher's box in viewport coordinates, with its transform divided out.\n *\n * The launcher is scaled in four states -- the collapse animation, hover,\n * press, and the resting scale(0.4) it sits at while the panel is open -- and\n * `getBoundingClientRect` reports every one of them. A drag that started from\n * that rect would begin a couple of pixels off, because a press is one of\n * those states.\n *\n * So the size comes from `offsetWidth`/`offsetHeight`, which are layout\n * metrics no transform reaches, and the position from the rect's *centre*,\n * which a centred scale is the one point that cannot move.\n */\n #launcherBox(): LauncherBox {\n const width = this.#host.launcher.offsetWidth;\n const height = this.#host.launcher.offsetHeight;\n const dragged = this.#launcherPos;\n if (dragged !== null) {\n return { left: dragged.left, top: dragged.top, width, height };\n }\n const rect = this.#host.launcher.getBoundingClientRect();\n return {\n left: rect.left + rect.width / 2 - width / 2,\n top: rect.top + rect.height / 2 - height / 2,\n width,\n height,\n };\n }\n\n /**\n * Place the host box and the launcher for the position the user dragged to.\n *\n * This writes `--ag-ui-inset`, which is a host-facing property: an inline\n * value outranks the page's own rule for it, exactly as a dragged width\n * outranks a placement's. That is the intent -- the user moved it -- and it\n * is why switching to a placement that owns its position hands the property\n * back rather than leaving a stale inline one behind.\n */\n #applyLauncherPlacement(at: { readonly left: number; readonly top: number }): void {\n this.#launcherPos = at;\n // Dropping the bubble hands the panel's position back to the placement.\n // Keeping a stated one would pin the panel where it was dragged and leave\n // the launcher deriving nothing, which is the gesture doing half its job.\n this.#panelPos = null;\n // The host box keeps its expanded size while collapsed, so its own rect is\n // the panel's size in either state and needs no separate bookkeeping.\n const panel = this.#host.element.getBoundingClientRect();\n const placement = launcherPlacement(\n this.#launcherBox(),\n { width: panel.width, height: panel.height },\n this.#viewport(),\n this.#screen(),\n );\n this.#host.element.style.setProperty(\"--ag-ui-inset\", placement.hostInset);\n this.#host.element.style.setProperty(\"--ag-ui-launcher-inset\", placement.launcherInset);\n this.#expandCorner = placement.corner;\n // The corner the panel grows from, for the open/close animation's origin.\n this.#host.element.setAttribute(\n \"data-expand-corner\",\n `${placement.corner.y}-${placement.corner.x}`,\n );\n this.syncResizeAnchor();\n }\n\n /** Move the launcher live during a drag, without persisting. */\n #moveLauncher(left: number, top: number): void {\n // Stated from the first move, not the last: a key gesture only ends at its\n // keyup, and an Enter pressed before then expands by way of a restore.\n this.#cornerSpot = { left, top };\n this.#applyLauncherPlacement({ left, top });\n }\n\n /** Move the launcher and remember where, per tab, like the dragged size. */\n #commitLauncher(left: number, top: number): void {\n this.#moveLauncher(left, top);\n this.#storeLauncherPosition();\n }\n\n /**\n * Move the panel live during a header drag, without persisting.\n *\n * Only the host box is written, and that is the whole trick: the launcher is\n * positioned *inside* that box, so leaving its own inset alone carries it\n * along by exactly the distance the panel travelled -- which is what a person\n * dragging a window expects of the thing it collapses into. Placing it on the\n * panel's pinned corner instead, as an earlier version did, sent it leaping\n * across the panel the moment the drag re-picked that corner.\n *\n * The corner is therefore held for the length of the gesture. Both insets are\n * measured from it, and rewriting one of them from a new corner while the\n * other still names the old one would move the launcher for no reason.\n */\n #movePanel(box: PanelRect, from: PanelRect): { held: PanelRect; launcher: LauncherBox | null } {\n if (this.#docked()) {\n // Inside the room above the dock, with nothing carried along.\n const held = clampPanel(box, this.#dockRoom(), SCREEN_EDGE_MARGIN);\n this.#dockPos = { left: held.left, top: held.top };\n this.#writeDockInset(held);\n return { held, launcher: null };\n }\n if (!this.#launcherDraggable()) {\n return { held: box, launcher: null };\n }\n // Where the launcher rests, recorded before the first move writes anything.\n // From here on the DOM shows it mid-gesture, so this is the last moment it\n // can be read rather than derived.\n if (this.#launcherPos === null) {\n const resting = this.#launcherBox();\n this.#launcherPos = { left: resting.left, top: resting.top };\n }\n // The launcher as it was when the gesture began. Held for the whole drag:\n // every move measures from here, so the two halves cannot drift apart.\n const start = this.#launcherPos;\n // The screen-edge bound, not the resting gutter: the 24px margin is where a\n // placement rests one, not where a person may put it. Not zero either: the\n // launcher is held the same distance off, and the restore below agrees.\n const held = clampPanel(box, this.#viewport(), SCREEN_EDGE_MARGIN);\n const corner = this.#expandCorner ?? this.#anchor;\n // The usable box decides where the panel may rest, above; these insets are\n // measured from the screen, as the browser measures a fixed element's.\n this.#host.element.style.setProperty(\"--ag-ui-inset\", insetFrom(corner, held, this.#screen()));\n this.#panelPos = { left: held.left, top: held.top };\n\n // Where the launcher has ended up, derived rather than read. During a\n // header drag it rides inside the host box with its own inset untouched,\n // so the DOM shows it moving while `#launcherPos` still holds where it\n // started -- reading it back mid-gesture returns the stale value, and\n // adding the panel's travel to that a second time on release is a jump.\n // Measured from the box the press started on, so a long drag cannot\n // accumulate the rounding each move writes.\n const carried = {\n ...this.#launcherBox(),\n left: start.left + (held.left - from.left),\n top: start.top + (held.top - from.top),\n };\n // A bubble carried into an edge the host reserved is one nobody can press.\n // Clamping it live rather than at the end is what makes releasing the drag\n // change nothing: leaving it until then parked it under a nav bar for the\n // whole gesture and hopped it out on pointerup.\n const launcher = { ...carried, ...clampLauncher(carried, this.#viewport()) };\n this.#host.element.style.setProperty(\n \"--ag-ui-launcher-inset\",\n placeWidget(held, launcher, corner, this.#screen()).launcherInset,\n );\n return { held, launcher };\n }\n\n /**\n * Finish a header drag: settle where both halves ended up, and remember it.\n *\n * The launcher travels the distance the panel actually travelled, which is\n * the clamped distance rather than the pointer's -- a panel held against the\n * viewport margin stops, and so does the bubble attached to it. Measured from\n * the box the press started on, so a long drag cannot accumulate the rounding\n * each move writes into the inset.\n *\n * Only now is the corner re-picked, from where the launcher has ended up, so\n * the panel opens into clear space next time. Re-picking it moves nothing:\n * both insets are rewritten from positions that are already decided.\n */\n #commitPanel(box: PanelRect, from: PanelRect): void {\n // Exactly what the last move applied, rather than the same sum computed\n // again. Recomputing it is how the two came apart: releasing the drag\n // moved the bubble by the panel's whole travel a second time.\n const { held, launcher } = this.#movePanel(box, from);\n if (this.#docked()) {\n this.#storeDockPosition({ left: held.left, top: held.top });\n return;\n }\n if (launcher === null) {\n return;\n }\n this.#placePanelAndLauncher(held, launcher);\n this.#storeLauncherPosition();\n }\n\n /**\n * Write both insets for a panel and launcher that are already positioned,\n * re-picking the corner they are measured from.\n */\n #placePanelAndLauncher(host: PanelRect, launcher: LauncherBox): void {\n const viewport = this.#viewport();\n const screen = this.#screen();\n const size = { width: host.right - host.left, height: host.bottom - host.top };\n const { corner } = launcherPlacement(launcher, size, viewport, screen);\n // The screen again, not the usable box: these are CSS insets on a fixed\n // element and the browser measures them from the real edges.\n const insets = placeWidget(host, launcher, corner, screen);\n this.#host.element.style.setProperty(\"--ag-ui-inset\", insets.hostInset);\n this.#host.element.style.setProperty(\"--ag-ui-launcher-inset\", insets.launcherInset);\n this.#launcherPos = { left: launcher.left, top: launcher.top };\n this.#panelPos = { left: host.left, top: host.top };\n this.#expandCorner = corner;\n this.#host.element.setAttribute(\"data-expand-corner\", `${corner.y}-${corner.x}`);\n this.syncResizeAnchor();\n }\n\n /**\n * Re-apply a panel position the user stated, against the current viewport.\n *\n * The launcher keeps its offset from the panel through the clamp -- it was\n * put where it is relative to the panel, and a viewport that has since shrunk\n * is no reason to move one without the other -- and is then held on screen in\n * its own right.\n */\n #restorePanelPosition(at: { readonly left: number; readonly top: number }): void {\n const rect = this.#host.element.getBoundingClientRect();\n // The same bound the drag itself used. Taking the default here instead is\n // what made a panel dragged to an edge jump a whole resting gutter inward\n // on the next resize, reload or expand -- re-placing a position the user\n // had stated, against a limit they had never been shown.\n const held = clampPanel(\n { left: at.left, top: at.top, right: at.left + rect.width, bottom: at.top + rect.height },\n this.#viewport(),\n SCREEN_EDGE_MARGIN,\n );\n const launcher = this.#launcherBox();\n const carried = {\n ...launcher,\n left: launcher.left + (held.left - at.left),\n top: launcher.top + (held.top - at.top),\n };\n this.#placePanelAndLauncher(held, {\n ...carried,\n ...clampLauncher(carried, this.#viewport()),\n });\n }\n\n /**\n * Write the current position, if this element owns one.\n *\n * The panel's own position rides along only when the user stated it, because\n * its presence is what tells a restore which of the two gestures to honour:\n * with it, the panel goes back where it was put; without it, the panel is\n * re-derived from the launcher and opens into whatever room the viewport has\n * now.\n *\n * Every caller is a gesture ending or a move being made, so where the two\n * stand now is what was stated. A restore never calls this.\n */\n #storeLauncherPosition(): void {\n const position = this.#launcherPos;\n if (position === null) {\n return;\n }\n const panel = this.#panelPos;\n this.#writeCornerSpot(panel === null ? position : { ...position, panel });\n }\n\n /** Make `spot` the stated one, and remember it. */\n #writeCornerSpot(spot: CornerSpot): void {\n this.#cornerSpot = spot;\n this.#host.writePreference(LAUNCHER_KEY, JSON.stringify(spot));\n }\n\n /**\n * Re-apply the dragged position against the current viewport: on connect,\n * whenever the window resizes, and before an expand. The viewport that\n * stored a position may since have shrunk, and a launcher past the edge is\n * unreachable -- it is the only way back to a collapsed conversation.\n *\n * The one gate on whether a stored position is this element's to honour: the\n * gestures check their own before they ever reach the placing below.\n */\n restoreLauncherPosition(): void {\n this.#placeFromRecord(true);\n this.#stampHeader();\n }\n\n /**\n * Re-apply it for a change in the panel's own layout, which needs no window or\n * reopen to happen: a line typed in the composer is one. A position waiting to\n * be handed back under data-launcher-drag=\"false\" waits on, because a panel that leaves for the\n * host's corner as the reader starts typing is a jump with no cause they can see.\n * It waits no longer than the panel stays on the screen: a host's size can stand\n * it off an edge, where its header is out of reach until something else happens.\n */\n settleLauncherPosition(): void {\n this.#placeFromRecord(false);\n this.#stampHeader();\n }\n\n /** The placing behind {@link restoreLauncherPosition}. */\n #placeFromRecord(handBack: boolean): void {\n // Before the launcher's record is read at all: it belongs to the corner\n // surface, and seeding anything from it would put a spot dragged there on\n // a panel that should stand on its dock.\n if (this.#docked()) {\n this.#placeDocked();\n return;\n }\n if (!this.#surface().launcherDraggable) {\n return;\n }\n // Under data-launcher-drag=\"false\" the widget is wherever the host's CSS puts\n // it, so a position this element took before the attribute went on is handed\n // back here, at the first window resize or reopen, and the record stays for the\n // day the attribute comes off. Nothing watches the attribute: it is read per\n // interaction, like every other answer here.\n const draggable = this.#launcherDraggable();\n if (!draggable && this.#launcherPos !== null) {\n if (!handBack && !this.#offScreen()) {\n return;\n }\n this.releaseLauncherPosition();\n }\n const spot = draggable ? (this.#cornerSpot ?? this.#readLauncherPosition()) : null;\n if (spot === null) {\n this.#placeUnstated();\n return;\n }\n if (this.#standFullBleed(spot)) {\n return;\n }\n if (spot.panel !== undefined) {\n // Stated rather than derived: the launcher is only read here to keep the\n // offset the two were left with, so it has to be seeded before the panel\n // is placed around it.\n this.#launcherPos = { left: spot.left, top: spot.top };\n this.#restorePanelPosition(spot.panel);\n return;\n }\n const box = this.#launcherBox();\n this.#applyLauncherPlacement(\n clampLauncher({ ...box, left: spot.left, top: spot.top }, this.#viewport()),\n );\n }\n\n /**\n * Leave a corner panel full-bleed if it has become the screen, and say whether\n * it has.\n *\n * The inline inset comes off, because the small-viewport block reads the\n * host's inset before its own: a spot written there holds the panel off the\n * edges it should fill, and past them by the same amount, since its size is\n * the screen's. What the panel covers is read before that, from the size\n * alone, which no inset changes.\n *\n * The launcher stays a place of its own. It is positioned from the host box,\n * so it is measured again from the box that has just moved, and it is held on\n * the screen, because it is the way back from a collapsed conversation. The\n * spot itself is untouched, for the next time there is room for it.\n *\n * Above the breakpoint nothing in the stylesheet takes the panel to the edges.\n * A host's own size makes it the screen while the resting inset still spends a\n * gutter on one corner, which hangs the box off the opposite one, so there it\n * stands at the start of the room the host left free and keeps that inset. A\n * box the placement already holds on the screen has no inset to keep, which is\n * every phone, and a host's rule that placed the box itself.\n */\n #standFullBleed(spot: CornerSpot): boolean {\n const element = this.#host.element;\n const viewport = this.#viewport();\n if (!coversViewport(element.getBoundingClientRect(), viewport)) {\n return false;\n }\n element.style.removeProperty(\"--ag-ui-inset\");\n const rest = element.getBoundingClientRect();\n const hanging = hangsOff(rest, viewport, this.#screen());\n const box = hanging ? atStartOf(viewport, rest) : rest;\n const launcher = { ...this.#launcherBox(), left: spot.left, top: spot.top };\n this.#placePanelAndLauncher(box, { ...launcher, ...clampLauncher(launcher, viewport) });\n if (!hanging) {\n element.style.removeProperty(\"--ag-ui-inset\");\n }\n return true;\n }\n\n /**\n * Place a panel that has no spot, a corner one or a docked one, the half of\n * {@link #standFullBleed} with nothing stated to keep and no launcher of its own\n * to measure.\n *\n * Only an inset this element wrote comes off or goes back. One the host wrote\n * inline is a token a host may state on a phone as anywhere else, and with no\n * spot it never came from here.\n */\n #placeUnstated(): void {\n const element = this.#host.element;\n const inline = element.style.getPropertyValue(\"--ag-ui-inset\");\n const viewport = this.#viewport();\n if (!coversViewport(element.getBoundingClientRect(), this.#fillRoom())) {\n if (inline === \"\" || inline === this.#fillInset) {\n this.#restoreProperty(\"--ag-ui-inset\", this.#gripInset ?? \"\");\n this.syncResizeAnchor();\n }\n this.#fillInset = null;\n return;\n }\n if (inline === this.#gripInset || inline === this.#fillInset) {\n element.style.removeProperty(\"--ag-ui-inset\");\n }\n const rest = element.getBoundingClientRect();\n const screen = this.#screen();\n if (\n element.style.getPropertyValue(\"--ag-ui-inset\") === \"\" &&\n hangsOff(rest, viewport, screen)\n ) {\n this.#standAtStart(rest);\n }\n }\n\n /** Stand a box a host's size fills at the start of the room the host left free. */\n #standAtStart(rest: PanelRect): void {\n this.#fillInset = insetFrom(\n { x: \"left\", y: \"top\" },\n atStartOf(this.#viewport(), rest),\n this.#screen(),\n );\n this.#host.element.style.setProperty(\"--ag-ui-inset\", this.#fillInset);\n this.syncResizeAnchor();\n }\n\n /** The persisted position for this instance, or null. */\n #readLauncherPosition(): CornerSpot | null {\n const raw = this.#host.readPreference(LAUNCHER_KEY);\n if (raw === null) {\n return null;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n const { left, top, panel } = parsed as { left?: unknown; top?: unknown; panel?: unknown };\n if (typeof left !== \"number\" || typeof top !== \"number\") {\n return null;\n }\n // A record written before the panel could be dragged has no panel half,\n // and one written by a launcher drag never will -- both restore by\n // deriving the panel, which is what they meant.\n const at = asPoint(panel);\n return at === null ? { left, top } : { left, top, panel: at };\n } catch {\n // A corrupt entry is not worth failing a mount over; fall back to the\n // placement's own corner.\n return null;\n }\n }\n\n /**\n * Give the position back to the host when the new placement owns it, the way\n * releaseOwnedAxes gives back a size. Without this a dragged inset survives\n * the switch inline and pins a sidebar to wherever the floating launcher was.\n */\n releaseLauncherPosition(): void {\n // A dragged dock spot belongs to a docked panel that moves. Any other\n // surface hands it back; a docked one keeps it, and syncDock holds it\n // against the new dock.\n if (this.#dockPos !== null && !(this.#docked() && this.#panelMovable())) {\n this.#dockPos = null;\n this.#host.element.style.removeProperty(\"--ag-ui-inset\");\n }\n if (this.#launcherDraggable()) {\n return;\n }\n this.#forgetCornerPosition();\n }\n\n /** Take everything off that placed a corner panel, leaving its record alone. */\n #forgetCornerPosition(): void {\n this.#launcherPos = null;\n this.#panelPos = null;\n this.#expandCorner = null;\n this.#gripInset = null;\n this.#fillInset = null;\n this.#host.element.style.removeProperty(\"--ag-ui-inset\");\n this.#host.element.style.removeProperty(\"--ag-ui-launcher-inset\");\n this.#host.element.removeAttribute(\"data-expand-corner\");\n }\n\n /**\n * Apply the box a grip is asking for.\n *\n * The size is the easy half. The other half is that **dragging the edge the\n * layout is holding still moves the panel as well as resizing it**, and the\n * layout cannot express that on its own: a floating panel pinned bottom-right\n * cannot grow rightward, because its right edge is what the placement fixed.\n * So a grip on a pinned edge takes the position over -- which is the same\n * ownership the launcher drag takes, written the same way.\n *\n * A grip on a free edge writes nothing but the size, exactly as before, so a\n * host positioning the panel with its own rule keeps that rule until someone\n * drags the edge it was holding.\n */\n #applyResize(grip: ResizeGrip, box: PanelRect): PanelRect {\n box = this.#withinViewport(box);\n if (this.#docked() && this.#dockPos === null) {\n // A panel standing on its dock keeps it through a resize: the edges it\n // stands on are the bar's or the anchor's, and a grip on one of them\n // would write the position below and take the panel off its dock. So\n // the pinned edges stay where they are and only the free ones follow.\n // Once dragged off, it resizes like a corner panel, below.\n const now = this.#host.element.getBoundingClientRect();\n box = {\n left: grip.x === this.#anchor.x ? now.left : box.left,\n right: grip.x === this.#anchor.x ? now.right : box.right,\n top: grip.y === this.#anchor.y ? now.top : box.top,\n bottom: grip.y === this.#anchor.y ? now.bottom : box.bottom,\n };\n this.#applySize({ width: box.right - box.left, height: box.bottom - box.top });\n return box;\n }\n this.#applySize({ width: box.right - box.left, height: box.bottom - box.top });\n if (this.#docked()) {\n // Any grip moves the top-left corner the spot is kept as, including one\n // on a free edge, which leaves the inset alone.\n this.#dockPos = { left: box.left, top: box.top };\n }\n if (grip.x === this.#anchor.x || grip.y === this.#anchor.y) {\n // The whole screen, not the usable box: a CSS inset on a fixed element is\n // measured from the real edges, so expressing a right or bottom against a\n // box the host has inset comes out short by exactly that inset.\n const anchor = this.#anchor;\n const inset = insetFrom(anchor, box, this.#screen());\n this.#host.element.style.setProperty(\"--ag-ui-inset\", inset);\n this.#gripInset = this.#launcherPos === null && !this.#docked() ? inset : null;\n // The launcher lives at this corner of the panel, so a corner that moved\n // takes it along. Without this the next expand would re-derive the panel's\n // position from a launcher still standing where the panel used to be, and\n // undo the move.\n if (this.#launcherPos !== null) {\n const size = this.#host.launcher.offsetWidth;\n this.#launcherPos = {\n left: anchor.x === \"left\" ? box.left : box.right - size,\n top: anchor.y === \"top\" ? box.top : box.bottom - size,\n };\n }\n }\n // A stated corner panel's spot is a claim about this box, so it moves with\n // it, by a free edge as well as by a pinned one. Read from what was drawn,\n // not what the pointer asked for, because a host's maximum stops the box short\n // of the pointer. Not while docked: this position belongs to the corner.\n if (this.#panelPos !== null && !this.#docked()) {\n const drawn = this.#host.element.getBoundingClientRect();\n this.#panelPos = { left: drawn.left, top: drawn.top };\n }\n return box;\n }\n\n /** Finish a resize: keep the box, remember it, and re-read the pinned edges. */\n #commitResize(grip: ResizeGrip, box: PanelRect): void {\n // The bounded box, not the one the pointer asked for. Persisting the raw\n // one would store a size the panel never had and restore it on the next\n // mount, which is the same disagreement between apply and commit that made\n // the header drag jump on release.\n const held = this.#applyResize(grip, box);\n // A grip on the free edges of a panel standing at the start of a filled window\n // leaves that inset alone, and the size it stated takes the panel off the\n // screen's shape. It has to stay where the grip left it, so the inset stops\n // being one that lasts only as long as the host's size does.\n if (this.#host.element.style.getPropertyValue(\"--ag-ui-inset\") === this.#fillInset) {\n this.#gripInset = this.#fillInset;\n this.#fillInset = null;\n }\n this.#persistSize({ width: held.right - held.left, height: held.bottom - held.top });\n this.#storeLauncherPosition();\n if (this.#dockPos !== null) {\n this.#storeDockPosition(this.#dockPos);\n }\n // Re-stamp after the drag: a host whose layout changed underneath us would\n // otherwise keep the tab-reachable grip in the old corner, which reads as\n // the control being in the wrong place even though the drag was right.\n this.syncResizeAnchor();\n }\n\n /**\n * Put the tab stop on the grip diagonally opposite the pinned corner.\n *\n * That is the corner a resize grows the panel from, so an arrow key there\n * changes the size and never the position -- the behaviour the single grip\n * this replaced had, kept for the one path that cannot simply grab a\n * different edge.\n */\n #focusableGrip(): void {\n const free = `${this.#anchor.y === \"top\" ? \"bottom\" : \"top\"}-${\n this.#anchor.x === \"left\" ? \"right\" : \"left\"\n }`;\n for (const [name, handle] of this.#resizeHandles) {\n const reachable = name === free;\n handle.tabIndex = reachable ? 0 : -1;\n if (reachable) {\n handle.removeAttribute(\"aria-hidden\");\n } else {\n handle.setAttribute(\"aria-hidden\", \"true\");\n }\n }\n }\n\n /**\n * The stored-size bucket for the live placement: its attribute value, with\n * absent and empty read as floating, as the stylesheet treats them.\n */\n #bucket(): string {\n const placement = this.#host.element.getAttribute(\"placement\");\n return placement === null || placement === \"\" ? \"floating\" : placement;\n }\n\n /** Persist a dragged size under the current placement, keeping the others. */\n #persistSize(size: ResizeSize): void {\n this.#writeSizes(this.#bucket(), { ...this.#readSize(), ...size });\n }\n\n /** Store one placement's size, or drop it with null, clearing an emptied record. */\n #writeSizes(bucket: string, size: ResizeSize | null): void {\n const placements: Record<string, ResizeSize> = { ...this.#readSizes() };\n if (size === null) {\n delete placements[bucket];\n } else {\n placements[bucket] = size;\n }\n if (Object.keys(placements).length === 0) {\n this.#host.clearPreference(SIZE_KEY);\n return;\n }\n const stored: StoredSizes = { v: 2, placements };\n this.#host.writePreference(SIZE_KEY, JSON.stringify(stored));\n }\n\n /** The persisted size for the current placement, or an empty record. */\n #readSize(): ResizeSize {\n return this.#readSizes()[this.#bucket()] ?? {};\n }\n\n /**\n * Every persisted size by placement. A record from before sizes were kept per\n * placement is one flat size, read as floating's, which is where it was\n * nearly always dragged.\n */\n #readSizes(): Readonly<Record<string, ResizeSize>> {\n const raw = this.#host.readPreference(SIZE_KEY);\n if (raw === null) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (typeof parsed !== \"object\" || parsed === null) {\n return {};\n }\n const record = parsed as Partial<StoredSizes>;\n if (record.v === 2 && typeof record.placements === \"object\" && record.placements !== null) {\n return record.placements;\n }\n return { floating: parsed as ResizeSize };\n } catch {\n // A corrupt entry is not worth failing a mount over; fall back to the\n // placement's own size.\n return {};\n }\n }\n}\n", "import { ANNOUNCE_CLEAR_MS } from \"../../constants.js\";\n\n/**\n * The screen-reader-only status region, and the one short thing it says at a\n * time about how a run is going.\n *\n * The transcript cannot do this job. It is rewritten on every animation frame\n * while an answer streams, so as a live region it re-announced the whole\n * answer tens of times per turn -- not merely unhelpful but actively hostile.\n * The published fix for this exact bug (Microsoft's Bot Framework WebChat\n * #3236) is architectural rather than a matter of tuning attributes: demote the\n * visible transcript out of live-region duty and put one synthesised status per\n * event into a separate invisible region. MDN and Scott O'Hara prescribe the\n * same empty-region-then-inject shape.\n *\n * Roughly four calls land per turn -- responding, answered, a card is waiting,\n * stopped or failed -- so the user is told what happened and reads the answer\n * itself by navigating the log, at their own pace, rather than having it\n * shouted at them a token at a time.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance. The element places {@link region} in its shadow root.\n */\nexport class RunAnnouncer {\n /** The invisible `role=\"status\"` region the statuses are written into. */\n readonly region = document.createElement(\"div\");\n /** Pending clear of {@link region}; see {@link announce} for why it is cleared at all. */\n #timer: ReturnType<typeof setTimeout> | null = null;\n\n /** Stamp the region's live-region semantics, before the element places it. */\n mount(): void {\n this.region.className = \"sr-only\";\n this.region.setAttribute(\"role\", \"status\");\n this.region.setAttribute(\"aria-live\", \"polite\");\n // Atomic: each announcement replaces the last and is read whole. Without\n // it a reader may announce only the changed words between two statuses.\n this.region.setAttribute(\"aria-atomic\", \"true\");\n }\n\n /**\n * Say one short thing to a screen reader, without touching the transcript.\n *\n * **The clear is load-bearing, twice.** A reader announces a live region when\n * its content *changes*, so setting the same string twice running -- two turns\n * in a row both starting -- is not a change and is silently not announced.\n * Emptying first makes the next set a change again. It also stops a stale\n * status being read out when a reader later lands on the region.\n */\n announce(message: string): void {\n if (this.#timer !== null) {\n clearTimeout(this.#timer);\n }\n this.region.textContent = message;\n this.#timer = setTimeout(() => {\n this.#timer = null;\n this.region.textContent = \"\";\n }, ANNOUNCE_CLEAR_MS);\n }\n\n /** Cancel a pending clear, so no timer outlives the element's connection. */\n dispose(): void {\n if (this.#timer !== null) {\n clearTimeout(this.#timer);\n this.#timer = null;\n }\n }\n}\n", "/**\n * A muted one-line notice about something the run did (history condensed, a\n * skill loaded), rendered inline between turns.\n *\n * Distinct from a tool card, which reports work the agent asked for and\n * settles, and from an error, which is a failure. A notice never settles and\n * takes no action of its own.\n *\n * It may carry exactly one control, and only ever an undo. That is a narrower\n * rule than \"no controls\", which is what this said until the agent could move\n * the panel it speaks from: something that rearranges the user's window without\n * being asked has to be both visible and reversible, and a notice is already\n * the surface that says what the run did. Anything the user has to *decide* is\n * a confirmation card instead -- the difference is that this reports something\n * already done.\n */\nexport function renderRunNotice(\n icon: string,\n text: string,\n kind: string,\n undo?: { readonly label: string; readonly onActivate: () => void },\n): HTMLDivElement {\n const notice = document.createElement(\"div\");\n notice.className = `run-notice run-notice--${kind}`;\n notice.setAttribute(\"part\", `run-notice run-notice-${kind}`);\n // status, not alert: informational, so it must not interrupt a screen reader\n // mid-sentence. Polite announcements land after the current utterance.\n notice.setAttribute(\"role\", \"status\");\n\n const glyph = document.createElement(\"span\");\n glyph.className = \"run-notice-icon\";\n glyph.setAttribute(\"part\", \"run-notice-icon\");\n glyph.textContent = icon;\n // Decorative: the adjacent text already says what happened, so announcing the\n // glyph's name would only add noise.\n glyph.setAttribute(\"aria-hidden\", \"true\");\n\n const label = document.createElement(\"span\");\n label.className = \"run-notice-text\";\n label.setAttribute(\"part\", \"run-notice-text\");\n label.textContent = text;\n\n notice.append(glyph, label);\n\n if (undo !== undefined) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = \"run-notice-undo\";\n button.setAttribute(\"part\", \"run-notice-undo\");\n button.textContent = undo.label;\n button.addEventListener(\"click\", () => {\n // One use. The state it restores is the state as it was when the notice\n // was written, so offering it twice would put back something that has\n // since moved again.\n button.disabled = true;\n undo.onActivate();\n });\n notice.append(button);\n }\n return notice;\n}\n", "import type { SUBAGENT_PHASE } from \"../../constants.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\n\n/** One phase of a delegation's life, as the server spells it. */\nexport type SubAgentPhase = (typeof SUBAGENT_PHASE)[keyof typeof SUBAGENT_PHASE];\n\n/**\n * One tool call the child made, as the two tool phases report it.\n *\n * `ok` is a tri-state and stays one here rather than collapsing to a boolean:\n * `null` is the call in flight, `true` a result the child accepted, `false` a\n * result that came back to it. Flattening `null` into `false` would draw a\n * running call as a failed one for as long as it runs.\n */\nexport interface SubAgentTool {\n readonly toolCallId: string;\n readonly name: string;\n readonly ok: boolean | null;\n}\n\n/**\n * One narrowed progress announcement about a delegation.\n *\n * Every field but `phase` and `delegationId` is nullable because the wire's\n * `value` is `unknown` and a malformed announcement must not take the run down\n * with it. `null` means \"said nothing about this\", never \"said nothing was\n * there\" \u2014 the panel leaves what it already shows alone.\n */\nexport interface SubAgentUpdate {\n /** The **parent's** `delegate_task` tool-call id, not the child's run id. */\n readonly delegationId: string;\n /** The child agent's name, for a host that wants to style or select by it. */\n readonly agent: string | null;\n readonly phase: SubAgentPhase;\n /** The server's pre-rendered line. The collapsed row needs nothing else. */\n readonly status: string | null;\n /** Present on the two tool phases only. */\n readonly tool: SubAgentTool | null;\n}\n\n/**\n * The nested surface for one delegation: a collapsed status row that expands\n * onto the child agent's own tool calls.\n *\n * ## Where it goes and why\n *\n * Into {@link ToolCallCard.subagentSlot} \u2014 the card the parent's own\n * `delegate_task` call already drew. The wire keys progress on the *parent's*\n * tool-call id, so the thing being narrated is already on screen; a floating\n * element would have duplicated its identity and then had to explain the\n * relationship. Attaching instead means the delegation reuses how tool cards\n * already behave, and there is no second visual language to learn.\n *\n * ## The shape\n *\n * One row per delegation, live, carrying nothing but the server's own `status`\n * line \u2014 which is what makes a ten-step child cost one row until somebody opens\n * it. Two alternatives were rejected on the way here and both are worth naming:\n * a bare status line is cheaper and gives up the detail entirely, and inline\n * child cards in the transcript interleave parent and child with nothing marking\n * whose is whose, in an order the persisted transcript will not reproduce.\n *\n * A child's steps are keyed by the child's own `toolCallId`, so the `tool_call`\n * that opens one and the `tool_result` that settles it are the same row updated\n * in place rather than two rows stacked.\n *\n * ## What it never does\n *\n * It never renders failure text. A `failed` phase carries none, on purpose; the\n * detail arrives on the ordinary `TOOL_CALL_RESULT` and lands in the same card's\n * result region, a few pixels below. Anything invented here would be this\n * component guessing at words the server declined to send.\n *\n * Nothing here is persisted: the events ride the imperative carrier, so a thread\n * restore rebuilds the tool card and not the delegation under it.\n *\n * Pure DOM, like the other widgets: the host appends {@link element}, and all\n * chrome text comes from {@link UiStrings}. The status line is server text and\n * is set with `textContent`, never parsed as markup.\n */\nexport class SubAgentPanel {\n /** The panel's root; append this into the delegating card's slot. */\n readonly element: HTMLDivElement;\n\n /**\n * The child agent's name, as the last update that carried one gave it.\n *\n * Read back rather than only written to the DOM, because the two carriers\n * split the name away from the close: `SUBAGENT_STARTED` names the agent and\n * `SUBAGENT_FINISHED` carries only an id, so whoever words the closing line\n * has to recover the name from what the delegation already told it.\n */\n get agent(): string | null {\n return this.#agent;\n }\n\n /**\n * The collapsed row, which is the expander as well as the status.\n *\n * Disabled while the child has called nothing, so a delegation that failed\n * before it started offers no control that expands onto an empty region \u2014\n * the same refusal the card's own Details toggle already makes.\n */\n readonly #row: HTMLButtonElement;\n readonly #status: HTMLSpanElement;\n readonly #steps: HTMLDivElement;\n /** The child's tool calls, keyed by the child's own call id. */\n readonly #stepRows = new Map<string, HTMLDivElement>();\n #agent: string | null = null;\n\n constructor(strings: UiStrings = DEFAULT_UI_STRINGS) {\n this.element = document.createElement(\"div\");\n this.element.className = \"subagent\";\n this.element.setAttribute(\"part\", \"subagent\");\n\n this.#row = document.createElement(\"button\");\n this.#row.type = \"button\";\n this.#row.className = \"subagent-row\";\n this.#row.setAttribute(\"part\", \"subagent-row\");\n this.#row.setAttribute(\"aria-expanded\", \"false\");\n this.#row.disabled = true;\n\n // Left empty in the DOM, like the tool card's: the shadow CSS draws a\n // spinner or a settled mark from the panel's data-phase, so a host themes\n // the glyph without either side reaching into the other's stylesheet.\n const icon = document.createElement(\"span\");\n icon.className = \"subagent-icon\";\n icon.setAttribute(\"part\", \"subagent-icon\");\n icon.setAttribute(\"aria-hidden\", \"true\");\n\n this.#status = document.createElement(\"span\");\n this.#status.className = \"subagent-status\";\n this.#status.setAttribute(\"part\", \"subagent-status\");\n // Seeded rather than left blank: an announcement whose status field is\n // unusable must still leave a readable row, since the row is the control.\n this.#status.textContent = strings.subAgentWorking;\n\n this.#row.append(icon, this.#status);\n\n this.#steps = document.createElement(\"div\");\n this.#steps.className = \"subagent-steps\";\n this.#steps.setAttribute(\"part\", \"subagent-steps\");\n this.#steps.setAttribute(\"role\", \"list\");\n this.#steps.setAttribute(\"aria-label\", strings.subAgentSteps);\n this.#steps.hidden = true;\n\n // The attribute is the state, as it is on the tool card: one place holds\n // whether the region is open, and it is the one a screen reader reads.\n this.#row.addEventListener(\"click\", () => {\n this.#setExpanded(this.#row.getAttribute(\"aria-expanded\") !== \"true\");\n });\n\n this.element.append(this.#row, this.#steps);\n }\n\n /**\n * Fold one announcement in.\n *\n * Every field is applied only when the update actually carried it, so a phase\n * that says nothing about the agent or the status leaves both as they stand.\n * That is what lets `finished` be two keys wide on the wire without blanking\n * the row it closes.\n */\n report(update: SubAgentUpdate): void {\n this.element.setAttribute(\"data-phase\", update.phase);\n if (update.agent !== null) {\n this.#agent = update.agent;\n this.element.setAttribute(\"data-agent\", update.agent);\n }\n if (update.status !== null) {\n this.#status.textContent = update.status;\n }\n if (update.tool !== null) {\n this.#recordStep(update.tool);\n }\n }\n\n /**\n * Open or settle one of the child's calls, keyed by its own id.\n *\n * The absence of `data-ok` is what \"still running\" looks like, mirroring the\n * wire's `null` rather than inventing a third value for it \u2014 so the attribute\n * is removed on the way in and written on the way out.\n */\n #recordStep(tool: SubAgentTool): void {\n const row = this.#stepRows.get(tool.toolCallId) ?? this.#createStep(tool);\n if (tool.ok === null) {\n row.removeAttribute(\"data-ok\");\n return;\n }\n row.setAttribute(\"data-ok\", String(tool.ok));\n }\n\n #createStep(tool: SubAgentTool): HTMLDivElement {\n const row = document.createElement(\"div\");\n row.className = \"subagent-step\";\n row.setAttribute(\"part\", \"subagent-step\");\n row.setAttribute(\"role\", \"listitem\");\n row.setAttribute(\"data-tool-call-id\", tool.toolCallId);\n\n const icon = document.createElement(\"span\");\n icon.className = \"subagent-step-icon\";\n icon.setAttribute(\"part\", \"subagent-step-icon\");\n icon.setAttribute(\"aria-hidden\", \"true\");\n\n const name = document.createElement(\"span\");\n name.className = \"subagent-step-name\";\n name.setAttribute(\"part\", \"subagent-step-name\");\n // The child's raw tool name. Not prettified and not looked up in the tool\n // catalog: a sub-agent's tools are its own and never reached the browser's\n // schema, and the status line above quotes the same raw name, so relabelling\n // here would make the two lines disagree about one call.\n name.textContent = tool.name;\n\n row.append(icon, name);\n this.#steps.appendChild(row);\n this.#stepRows.set(tool.toolCallId, row);\n // There is something behind the row now, so it becomes a control.\n this.#row.disabled = false;\n return row;\n }\n\n #setExpanded(expanded: boolean): void {\n this.#steps.hidden = !expanded;\n this.#row.setAttribute(\"aria-expanded\", String(expanded));\n }\n}\n", "/**\n * Narrow one `ag_ui.subagent` payload into a {@link SubAgentUpdate}.\n *\n * Kept out of the panel for the reason `chartSpecFrom` is kept out of the\n * renderer: the panel's job is drawing, and a value that reaches it has already\n * been vouched for.\n *\n * **The three lifecycle phases are still accepted here, deliberately.** A current\n * server sends only `tool_call` and `tool_result` on this carrier -- the\n * delegation's lifetime moved to the protocol's `SUBAGENT_*` events -- but a\n * server one release older sends all five, and this element is published and\n * vendored separately from it. Continuing to narrow the older shape costs\n * nothing (the panel needs those phases as visual states regardless) and is the\n * difference between a mixed-version pair that degrades and one that shows a\n * delegation which never opens.\n *\n * Defensive about the payload, not about the name. A `CUSTOM` event's `value` is\n * `unknown` by the protocol, so a server can put anything there, and a malformed\n * announcement must not take a run down with it \u2014 the same rule the invalidation\n * channel applies to the same field. What is refused here is only what cannot be\n * rendered at all: without a `delegationId` there is no card to attach to, and\n * without a known `phase` there is no state to be in. Everything else degrades to\n * `null`, which the panel reads as \"said nothing about this\".\n */\n\nimport { SUBAGENT_PHASE } from \"../../constants.js\";\nimport type { SubAgentPhase, SubAgentTool, SubAgentUpdate } from \"./subagent_panel.js\";\n\nconst PHASES: readonly string[] = Object.values(SUBAGENT_PHASE);\n\n/** A record view of `value`, or `null` for anything that is not an object. */\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n // `typeof null` is \"object\", and an array is one too \u2014 neither carries the\n // keys below, and both arrive from a JSON decoder without any warning.\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return null;\n }\n return value as Record<string, unknown>;\n}\n\n/** A non-empty string, or `null`. */\nfunction asText(value: unknown): string | null {\n return typeof value === \"string\" && value !== \"\" ? value : null;\n}\n\n/**\n * The `tool` record the two tool phases carry.\n *\n * All-or-nothing: the contract states all three keys on every tool phase, so a\n * partial record is a payload this client does not understand rather than a step\n * to draw half of. A step row keyed by an empty id would also collide with the\n * next one, silently merging two of the child's calls into one row.\n */\nfunction asTool(value: unknown): SubAgentTool | null {\n const record = asRecord(value);\n if (record === null) {\n return null;\n }\n const toolCallId = asText(record[\"toolCallId\"]);\n const name = asText(record[\"name\"]);\n const ok = record[\"ok\"];\n if (toolCallId === null || name === null) {\n return null;\n }\n if (ok !== null && typeof ok !== \"boolean\") {\n return null;\n }\n return { toolCallId, name, ok };\n}\n\n/** Narrow an `ag_ui.subagent` `CUSTOM` value, or `null` if it cannot be drawn. */\nexport function subAgentUpdate(value: unknown): SubAgentUpdate | null {\n const record = asRecord(value);\n if (record === null) {\n return null;\n }\n const delegationId = asText(record[\"delegationId\"]);\n const phase = record[\"phase\"];\n if (delegationId === null || typeof phase !== \"string\" || !PHASES.includes(phase)) {\n return null;\n }\n return {\n delegationId,\n phase: phase as SubAgentPhase,\n agent: asText(record[\"agent\"]),\n status: asText(record[\"status\"]),\n tool: asTool(record[\"tool\"]),\n };\n}\n", "import { SUBAGENT_PHASE } from \"../../constants.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { SubAgentPanel, type SubAgentPhase, type SubAgentUpdate } from \"./subagent_panel.js\";\nimport { subAgentUpdate } from \"./subagent_update.js\";\nimport type { ToolCallCard } from \"./tool_call_card.js\";\n\n/** What delegated progress needs from the element that owns it. */\nexport interface SubAgentProgressHost {\n /** The tool card drawn for a call id, which a delegation's panel hangs off. */\n readonly card: (callId: string) => ToolCallCard | undefined;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Keep the transcript at its foot, if the reader is there. */\n readonly follow: () => void;\n}\n\n/**\n * A delegated sub-agent's progress, hung off the card that delegated: the live\n * panels by delegation, and which delegation each child run belongs to.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class SubAgentProgress {\n readonly #host: SubAgentProgressHost;\n /**\n * The live delegation panels, keyed by the **parent's** `delegate_task` call\n * id \u2014 which is what the wire keys a sub-agent's progress on, so this map and\n * the element's tool cards answer to the same key.\n *\n * Kept beside the cards rather than on them, so a card stays a card: the tool\n * card holds the slot and this holds what went into it, the same division the\n * approval prompt already uses.\n */\n readonly #subagentPanels = new Map<string, SubAgentPanel>();\n /**\n * Which delegation each live `subagentRunId` belongs to.\n *\n * The protocol's closing events -- `SUBAGENT_FINISHED` and `SUBAGENT_ERROR`\n * -- carry the child's run id and nothing else, while everything drawn here\n * is keyed on the parent's `delegate_task` call id. `SUBAGENT_STARTED` is the\n * one event carrying both, so the pairing is recorded there and read back on\n * the close. A close naming a run this never saw open is dropped, which is\n * the same refusal a step for an undrawn card gets.\n */\n readonly #subagentRunDelegations = new Map<string, string>();\n\n constructor(host: SubAgentProgressHost) {\n this.#host = host;\n }\n\n /**\n * Draw one step of a delegated sub-agent's progress, on the card that\n * delegated.\n *\n * `delegationId` is the parent's own `delegate_task` tool-call id, so the\n * attachment point is a card this element already drew on `TOOL_CALL_START`.\n * Without this a run that hands work to a sub-agent reads as a stall, the\n * card sitting at \"running\u2026\" for the child's whole duration, so the narration\n * goes *into* that card rather than a second element with the same identity.\n *\n * A progress event for a call this client never drew is dropped. It has no\n * card to attach to, and inventing a floating one is precisely the alternative\n * that was rejected: parent and child interleave in the transcript with\n * nothing marking whose is whose, and the persisted transcript -- which never\n * held the progress at all -- would not match what was on screen.\n *\n * Nothing here writes to the conversation store. `CUSTOM` never enters\n * `agent.messages`, so a reload mid-run leaves the tool card and loses the\n * nested detail, which is the intended behaviour rather than a gap.\n */\n report(value: unknown): void {\n const update = subAgentUpdate(value);\n if (update === null) {\n return;\n }\n this.#apply(update);\n }\n\n /** Open a delegation, on `SUBAGENT_STARTED`. */\n start(subagentRunId: string, agent: string, parentToolCallId: string | null): void {\n // A delegation naming no parent call names no card, and a floating\n // panel is exactly what attaching to the card was chosen over.\n if (parentToolCallId === null) {\n return;\n }\n this.#subagentRunDelegations.set(subagentRunId, parentToolCallId);\n this.#apply({\n delegationId: parentToolCallId,\n agent: agent === \"\" ? null : agent,\n phase: SUBAGENT_PHASE.STARTED,\n status: fillUiString(this.#host.strings().subAgentDelegatedTo, { agent }),\n tool: null,\n });\n }\n\n /** Settle a delegation that completed, on `SUBAGENT_FINISHED`. */\n finish(subagentRunId: string): void {\n this.#close(subagentRunId, SUBAGENT_PHASE.FINISHED, null);\n }\n\n /** Settle a delegation that failed, on `SUBAGENT_ERROR`. */\n fail(subagentRunId: string, message: string): void {\n // The server's own words, which the contract keeps to the sub-agent's\n // name. Passed through as the status line and set with textContent\n // downstream, never parsed as markup.\n //\n // The message is required by the protocol and can still arrive empty,\n // which would settle the row to a blank line -- a delegation that reads\n // as having said nothing rather than as having failed. The fallback was\n // written and documented in UiStrings and never wired up, so until now\n // the only reader who knew it existed was the one reading the string\n // table.\n this.#close(\n subagentRunId,\n SUBAGENT_PHASE.FAILED,\n message === \"\" ? this.#host.strings().subAgentFailed : message,\n );\n }\n\n /**\n * Forget every delegation. The panels go with the cards they hung off.\n * Nothing restores them: the progress rode the imperative carrier and was\n * never persisted, which is the correct half of that split -- a delegation\n * that was live before this transcript was wiped is not live now.\n */\n clear(): void {\n this.#subagentPanels.clear();\n this.#subagentRunDelegations.clear();\n }\n\n /**\n * Settle the delegation a closing lifecycle event names.\n *\n * `status` is the server's text on a failure and `null` on a success, where\n * the wording is this element's own -- the protocol's finish event carries no\n * message, which is the better shape for a localised UI and the reason\n * {@link UiStrings.subAgentFinished} exists.\n *\n * The pairing is deliberately not deleted on close. A panel outlives the\n * delegation it drew, the map is cleared with the transcript alongside the\n * panels, and forgetting the id here would only make a duplicate close draw\n * nothing instead of drawing the same settled row again.\n */\n #close(subagentRunId: string, phase: SubAgentPhase, status: string | null): void {\n const delegationId = this.#subagentRunDelegations.get(subagentRunId);\n if (delegationId === undefined) {\n // A close naming a delegation this never saw open -- the same refusal a\n // step for an undrawn card gets, and the same reason.\n return;\n }\n const agent = this.#subagentPanels.get(delegationId)?.agent ?? null;\n this.#apply({\n delegationId,\n agent,\n phase,\n status: status === null ? this.#finishedLine(agent) : status,\n tool: null,\n });\n }\n\n /** The row's line for a delegation that completed, named if its name is known. */\n #finishedLine(agent: string | null): string {\n const strings = this.#host.strings();\n return agent === null\n ? strings.subAgentWorking\n : fillUiString(strings.subAgentFinished, { agent });\n }\n\n /**\n * Fold one already-narrowed update into the delegation's panel.\n *\n * The join point of the two carriers, and the reason it is separate from\n * {@link report}: a `CUSTOM` step arrives as `unknown` and has to be vouched\n * for, while a lifecycle event arrives typed off the protocol and has nothing\n * left to check. Both end up here, so the panel has one way in and the phases\n * stay a single state machine regardless of which wire they came from.\n */\n #apply(update: SubAgentUpdate): void {\n const card = this.#host.card(update.delegationId);\n if (card === undefined) {\n return;\n }\n let panel = this.#subagentPanels.get(update.delegationId);\n if (panel === undefined) {\n // Created on whichever phase arrives first rather than only on `started`.\n // The contract says exactly one opens a delegation, and a client that\n // insisted on it would answer a server that dropped one frame by showing\n // nothing at all for the rest of the run.\n panel = new SubAgentPanel(this.#host.strings());\n this.#subagentPanels.set(update.delegationId, panel);\n card.subagentSlot.appendChild(panel.element);\n }\n panel.report(update);\n // The card grew, and the transcript is usually pinned to the foot while a\n // run is in flight.\n this.#host.follow();\n }\n}\n", "// Charts drawn in the transcript: the block, its title and legend.\nexport const CHART_STYLES: string = `\n/* Charts.\n *\n * The SVG scales to the column and carries no colours of its own beyond the\n * series palette, so a host restyles it the same way it restyles everything\n * else. Series colours are custom properties with fallbacks rather than fixed\n * values, and the axis furniture inherits currentColor at low opacity so it\n * reads correctly in either theme without a second palette.\n */\n/* A chart is sized like a message, not like a panel: it takes the width it\n needs and stops, rather than stretching into whatever room the transcript\n has. A message bubble caps at 80% for the same reason -- widening the panel\n should not resize what is already in it. The cap is a token so a host with a\n wide panel and a real reason can raise it; the default is the width this\n renderer has always drawn at. Below the cap the block still fills its column,\n which is what a narrow panel needs. */\n.chart-block {\n align-self: flex-start;\n width: 100%;\n max-width: var(--_chart-max-width);\n margin: 6px 0;\n color: var(--_fg);\n}\n\n/* The drawing fills the block's width and carries its own height in the\n viewBox, so it is laid out rather than magnified: block display keeps the\n inline baseline gap from adding a stripe under every chart. */\n.chart-block svg {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.chart-title {\n margin-bottom: 2px;\n font-size: 0.85em;\n font-weight: 600;\n opacity: 0.85;\n}\n\n.chart-legend {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 12px;\n margin-top: 4px;\n font-size: 0.78em;\n opacity: 0.75;\n}\n\n.chart-legend-item {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.chart-legend-swatch {\n width: 9px;\n height: 9px;\n border-radius: 2px;\n flex: 0 0 auto;\n}\n`;\n", "// The composer's attachment picker, voice button and attachment tray.\nexport const ATTACHMENT_STYLES: string = `\n/* \u2500\u2500 File attachments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* The picker button sits in the composer's tool row; hidden until\n data-attachments-url. */\n.attach-input {\n display: none;\n}\n\n/* The mic button's mount point; filled only once ComposerVoice.wire mounts\n the control, which it skips unless transcription is configured. */\n.voice-slot {\n display: contents;\n}\n\n/* Recording: a red tint + a gentle pulse so it's clearly \"live\". */\n.voice-btn[data-state=\"recording\"] {\n background: var(--_danger);\n color: var(--_on-danger);\n animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;\n}\n\n.voice-btn[data-state=\"recording\"]:hover {\n background: var(--_danger);\n color: var(--_on-danger);\n}\n\n@keyframes ag-ui-voice-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .voice-btn[data-state=\"recording\"] {\n animation: none;\n }\n}\n\n/* Pending-attachments tray, above the input row; collapses (hidden) when empty. */\n.attachment-slot {\n display: contents;\n}\n\n/* The padding is the only separation the tray gets: its slot is display:\n contents, so the tray is a direct child of the .chat column, and that column\n sets no gap. The bottom value keeps a chip off the composer's top edge.\n The inline value here is only the default: the page placement overrides\n padding-inline further down to compute its reading-column gutter, and wins\n on specificity whichever way this declaration is written. Read the two\n together before changing either. */\n.attachment-tray {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 12px;\n}\n\n/* The tray sets the hidden property while empty, and an author display beats\n the UA stylesheet's rule for it, so without this the empty tray keeps\n laying out and its padding is permanent dead space above the composer. */\n.attachment-tray[hidden] {\n display: none;\n}\n\n.attachment-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n}\n`;\n", "// The composer: field, tool row, icon buttons, send and stop, and the glyph\n// class every icon button and icon holder paints with.\nexport const COMPOSER_STYLES: string = `\n/* \u2500\u2500 Composer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One surface owns the border, the background and the focus ring; the field\n and its tool row sit inside it, rather than being siblings stretched to the\n textarea's height. */\n.input-row {\n display: flex;\n padding: 12px;\n border-top: 1px solid var(--_border);\n}\n\n.composer {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 6px 6px 6px 10px;\n background: var(--_input-bg);\n border: 1px solid var(--_border);\n border-radius: var(--_composer-radius);\n transition: border-color var(--_motion) var(--_ease);\n}\n\n.composer:focus-within {\n border-color: var(--_accent);\n}\n\n/* The field grows with its content (sized by #autoGrow) up to the ceiling,\n then scrolls. border-box keeps that measurement stable: with content-box the\n padding would be added to every scrollHeight read and the field would creep\n taller on each keystroke. */\n.input {\n box-sizing: border-box;\n resize: none;\n max-height: var(--_composer-max-height);\n overflow-y: auto;\n /* Scrolling past the end of this must not scroll the page behind it. */\n overscroll-behavior: contain;\n padding: 6px 4px 2px;\n background: transparent;\n border: none;\n font: inherit;\n color: inherit;\n outline: none;\n}\n\n.composer-tools {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n/* Icon buttons: quiet at rest, so the field is what the eye lands on. They\n keep their size when the row is short of width: the place chip beside them\n is what gives way. */\n.attach-btn,\n.voice-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: var(--_tool-btn-size);\n height: var(--_tool-btn-size);\n padding: 0;\n border: none;\n border-radius: 8px;\n background: transparent;\n color: var(--_muted);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n transition:\n background-color var(--_motion) var(--_ease),\n color var(--_motion) var(--_ease);\n}\n\n.attach-btn:hover,\n.voice-btn:hover {\n background: var(--_hover);\n color: var(--_fg);\n}\n\n.attach-btn:disabled,\n.voice-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n/* The same trap the attachment tray carries a note about, two rules along: an\n author display beats the UA stylesheet's rule for the hidden property, so a\n button the element has explicitly hidden keeps laying out and painting. The\n clip is hidden until a host supplies an upload handler or an attachments URL,\n and without this it is a visible control that cannot do anything.\n\n The mic needs no such rule, and the asymmetry is worth knowing before adding\n one: it is not hidden when unconfigured, it is never built. The voice wiring\n returns before constructing the button, leaving only an empty voice slot that\n is display: contents. A hidden-state rule for the mic would match nothing. */\n.attach-btn[hidden] {\n display: none;\n}\n\n/* Send closes the row on the right: a circle, the only filled control in the\n composer, so \"the thing that acts\" reads at a glance. */\n.send {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: var(--_send-size);\n height: var(--_send-size);\n padding: 0;\n border: none;\n border-radius: 50%;\n background: var(--_accent);\n color: var(--_on-accent);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n transition:\n background-color var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease-pop);\n}\n\n.send:hover {\n transform: scale(1.08);\n}\n\n.send:active {\n transform: scale(0.92);\n}\n\n.send:disabled {\n opacity: 0.5;\n cursor: default;\n transform: none;\n}\n\n/* The composer button doubles as the Stop control while a run is in flight \u2014\n same circle, different glyph, so nothing moves when a run starts. */\n.send[data-state=\"running\"] {\n background: var(--_muted);\n}\n\n.send[data-state=\"idle\"] .send-stop,\n.send[data-state=\"running\"] .send-send {\n display: none;\n}\n\n/* Glyphs \u2014 one class, painted from the button's own colour so every state\n (hover, recording, running) carries the icon with it. */\n.glyph {\n width: var(--_glyph-size);\n height: var(--_glyph-size);\n fill: none;\n stroke: currentColor;\n stroke-width: var(--_glyph-stroke);\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.glyph--solid {\n fill: currentColor;\n stroke: none;\n}\n\n/* In an icon holder (header brand, launcher) the glyph takes the holder's size\n rather than the composer's. */\n.icon-holder .glyph {\n width: 100%;\n height: 100%;\n}\n`;\n", "// Skills and suggestions over the composer: the chip rows and the / palette.\nexport const SKILL_STYLES: string = `\n/* Skills \u2014 chips row + the /-command palette, above the input. */\n.skill-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 10px 12px;\n}\n\n/* The row is hidden whenever the host offers no skills, which is most elements\n most of the time, and an author display beats the user-agent rule for the\n hidden attribute. Without this it kept its padding: 20px of panel between\n the transcript and the composer, under every placement, reading as the gap\n under whatever the transcript ends with. */\n.skill-chips[hidden] {\n display: none;\n}\n\n.skill-chip {\n border: 1px solid var(--_border);\n border-radius: 999px;\n padding: 4px 12px;\n font: inherit;\n font-size: 0.9em;\n cursor: pointer;\n background: var(--_assistant-bg);\n color: var(--_fg);\n}\n\n.skill-chip:hover {\n border-color: var(--_accent);\n}\n\n/* Follow-up suggestion chips. Deliberately the skill chips' shape rather than a\n second chip vocabulary -- both are \"a question you could ask\", and the only\n difference is who chose it. Inside the transcript, so they scroll with the\n answer they follow instead of hovering above the composer. */\n.suggestions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n align-self: stretch;\n}\n\n.suggestion-chip {\n border: 1px solid var(--_border);\n border-radius: 999px;\n padding: 4px 12px;\n font: inherit;\n font-size: 0.9em;\n text-align: left;\n cursor: pointer;\n background: var(--_assistant-bg);\n color: var(--_fg);\n}\n\n.suggestion-chip:hover,\n.suggestion-chip:focus-visible {\n border-color: var(--_accent);\n}\n\n.skill-palette {\n margin: 8px 12px 0;\n display: flex;\n flex-direction: column;\n max-height: 220px;\n overflow: auto;\n /* Scrolling past the end of this must not scroll the page behind it. */\n overscroll-behavior: contain;\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: 8px;\n box-shadow: 0 8px 24px rgba(20, 20, 50, 0.16);\n}\n\n/* Closed nearly all of the time and mounted on every element. The display\n above beats the user-agent rule for the hidden attribute, so without this a\n closed palette still painted its margin, border and shadow as a line over\n the composer. */\n.skill-palette[hidden] {\n display: none;\n}\n\n.skill-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n align-items: flex-start;\n padding: 8px 12px;\n border: none;\n background: none;\n font: inherit;\n text-align: left;\n cursor: pointer;\n color: var(--_fg);\n}\n\n.skill-item[aria-selected=\"true\"] {\n background: var(--_assistant-bg);\n}\n\n.skill-item-title {\n font-weight: 600;\n}\n\n.skill-item-desc {\n font-size: 0.85em;\n color: var(--_muted);\n}\n\n/* The hint sits directly above the composer's top border, so a zero bottom\n margin left the text touching the divider. */\n.skill-hint {\n margin: 8px 12px;\n font-size: 0.85em;\n line-height: 1.4;\n color: var(--_danger);\n}\n`;\n", "// The thread drawer, its list and filter, and the checkpoint menu. The\n// queued-message row over the composer sits among them only because no rule\n// moved in the split.\nexport const HISTORY_STYLES: string = `\n/* Chat-history drawer \u2014 a slide-over within the chat panel.\n The hidden attribute stays the single source of truth for open/closed (no\n JS-driven animation state): display is transitioned discretely, so on close\n the drawer stays displayed for the whole exit and is removed only at the end,\n which is what lets the backdrop fade and the panel slide out. */\n.drawer {\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n /* Visible at once on the way in. Opening moves focus to the list in the\n same task that unhides it, and an element still hidden cannot take focus:\n a transition on visibility starts at its first value, so easing it in\n left the drawer hidden at exactly that instant and the focus call was\n dropped at every placement. Reduced motion shortens the transition\n without removing it, so it had the same first frame. */\n transition: visibility 0s;\n}\n\n/* Closed. The overlay keeps its box (display, not none) so the backdrop and\n panel inside it stay rendered and can transition both ways; visibility is\n what takes the whole subtree out of the tab order, the a11y tree and hit\n testing at rest. On the way out it is delayed rather than eased, so it\n flips only once the slide has finished. A transition is read from the\n state being entered, which is what lets the two directions differ. */\n.drawer[hidden] {\n display: flex;\n visibility: hidden;\n pointer-events: none;\n transition: visibility 0s var(--_motion);\n}\n\n.drawer[hidden] .drawer-backdrop {\n opacity: 0;\n}\n\n.drawer[hidden] .drawer-panel {\n transform: translateX(-100%);\n}\n\n.checkpoints {\n position: absolute;\n inset-block-start: 3rem;\n inset-inline: 0.75rem;\n z-index: 6;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n padding: 0.5rem;\n border: 1px solid var(--_border);\n border-radius: 0.5rem;\n background: var(--_assistant-bg);\n box-shadow: 0 6px 24px rgb(0 0 0 / 12%);\n max-height: 60%;\n overflow-y: auto;\n /* Scrolling past the end of this must not scroll the page behind it. */\n overscroll-behavior: contain;\n transform-origin: top center;\n /* Visibility flips at once on the way in, for the drawer's reason: opening\n focuses the panel in the same task that unhides it, and an element still\n hidden cannot take focus. The fade and the scale still ease in. */\n transition:\n opacity var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease),\n visibility 0s;\n}\n\n/* Same idiom as the drawer: laid out at rest, hidden by visibility, so the\n popover can animate open and closed. The whole list is restated because a\n transition is read from the state being entered; only visibility differs,\n delayed rather than eased so it flips once the exit has played. */\n.checkpoints[hidden] {\n display: flex;\n visibility: hidden;\n pointer-events: none;\n opacity: 0;\n transform: scale(0.96) translateY(-6px);\n transition:\n opacity var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease),\n visibility 0s var(--_motion);\n}\n\n.checkpoints-title {\n font-size: 0.75rem;\n font-weight: 600;\n opacity: 0.7;\n}\n\n.checkpoints-empty {\n padding: 0.5rem 0.25rem;\n font-size: 0.8125rem;\n opacity: 0.7;\n}\n\n/* A row is a label and two buttons, and nothing about the row itself is\n pressable. Hover is the affordance of something clickable, and a lit-up row made the\n buttons look like decoration on a clickable strip, so the resting surface\n groups the row and only the buttons respond to hover.\n\n It wraps for the same reason the tool-call head does. Every child but the label\n is fixed-width, so in a narrow panel the label is the only thing that can give\n -- and a flex-basis of zero lets it give everything. Adding the run id was\n enough to crush \"just now\" to zero pixels: present, correct, and invisible.\n Wrapping puts the buttons on their own line instead. */\n.checkpoint-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem;\n padding: 0.3125rem 0.4375rem;\n border-radius: 0.375rem;\n background: var(--_hover);\n}\n\n/* Grows into spare room, and refuses to shrink past the shortest thing it ever\n says. A time is short and bounded, so there is no case for eliding it. */\n.checkpoint-label {\n flex: 1 1 auto;\n min-width: 7ch;\n font-size: 0.8125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* When the label holds the run's first message, the time moves here: still worth\n showing, no longer what identifies the row. Muted and unshrinkable, so it does\n not compete with the words beside it. */\n.checkpoint-time {\n flex: 0 0 auto;\n font-size: 0.6875rem;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n/* Enough of the run id to tell two runs apart when both say \"just now\". Muted\n and monospaced: it is a reference, not a name. */\n.checkpoint-id {\n flex: 0 0 auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.6875rem;\n opacity: 0.55;\n}\n\n/* On the panel's own surface, not the row's: the row now paints the hover token\n itself, and a badge the same colour as what it sits on is not a badge. */\n.checkpoint-branch {\n font-size: 0.6875rem;\n padding: 0 0.375rem;\n border-radius: 999px;\n background: var(--_assistant-bg);\n opacity: 0.8;\n}\n\n/* The two things in the row that actually do something, so they are the two\n things that look like it: a filled surface at rest rather than a transparent\n outline, which on top of the old row highlight was nearly invisible. */\n.checkpoint-action {\n font: inherit;\n font-size: 0.75rem;\n line-height: 1.4;\n cursor: pointer;\n padding: 0.1875rem 0.5625rem;\n border: 1px solid var(--_border);\n border-radius: 0.375rem;\n background: var(--_bg);\n color: inherit;\n transition:\n background var(--_motion) var(--_ease),\n border-color var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease);\n}\n\n/* Resume is what a reader wants nine times in ten; fork is the deliberate choice\n beside it. Filled and outlined, the same pair the confirmation and approval\n cards already use for their primary and secondary action. */\n.checkpoint-resume {\n font-weight: 600;\n border-color: var(--_accent);\n background: var(--_accent);\n color: var(--_on-accent);\n}\n\n.checkpoint-fork:hover {\n background: var(--_hover);\n border-color: var(--_accent);\n}\n\n/* The filled one cannot go lighter on hover without losing its contrast with the\n white label, so it dims instead. */\n.checkpoint-resume:hover {\n opacity: 0.88;\n}\n\n/* Pressed: a pixel down, so the click is felt as well as seen. */\n.checkpoint-action:active {\n transform: translateY(1px);\n}\n\n/* Keyboard focus was invisible here, in a panel that traps focus and is reached\n by Tab -- so the one navigation path guaranteed to land on these buttons was\n the one with nothing to show for it. */\n.checkpoint-action:focus-visible {\n outline: 2px solid var(--_accent);\n outline-offset: 2px;\n}\n\n.drawer-backdrop {\n position: absolute;\n inset: 0;\n background: rgba(20, 20, 50, 0.32);\n opacity: 1;\n transition: opacity var(--_motion) var(--_ease);\n}\n\n.drawer-panel {\n position: relative;\n display: flex;\n flex-direction: column;\n width: min(300px, 85%);\n height: 100%;\n background: var(--_bg);\n border-right: 1px solid var(--_border);\n box-shadow: var(--_shadow);\n overflow: hidden;\n transform: none;\n transition: transform var(--_motion) var(--_ease);\n}\n\n.drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--_space);\n padding: var(--_pad);\n border-bottom: 1px solid var(--_border);\n}\n\n.drawer-title {\n /* Takes the slack so the two controls group at the trailing edge. With\n space-between and three items the middle one floats, which reads as the\n title and the close button being a pair with New chat wedged between\n them. Truncates rather than pushing them off the row. */\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n}\n\n.drawer-new {\n flex: 0 0 auto;\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n background: var(--_bg);\n color: var(--_accent);\n padding: 4px 10px;\n font: inherit;\n font-size: 0.85em;\n cursor: pointer;\n}\n\n/* Narrows the list. Sits under the header rather than in it: the header's two\n controls act on the conversation, and a field that filters what is below it\n belongs with what it filters. */\n/* What is waiting for the run to finish. Above the composer, beside the\n attachment tray, because both are things already handed over and not yet\n sent. Each chip is a button: pressing it takes that message back. */\n.queued {\n display: flex;\n flex-wrap: wrap;\n gap: var(--_space);\n padding: 0 var(--_pad) var(--_space);\n}\n\n/* Empty whenever no run is in flight, and hidden then. Same reason as the\n palette: the display above would otherwise keep the bottom padding as dead\n space over the composer. */\n.queued[hidden] {\n display: none;\n}\n\n.queued-chip {\n max-width: 100%;\n overflow: hidden;\n padding: 4px 10px;\n border: 1px dashed var(--_border);\n border-radius: var(--_msg-radius);\n background: var(--_bg);\n color: var(--_muted);\n font: inherit;\n font-size: 0.9em;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n}\n\n.queued-chip:hover {\n border-style: solid;\n color: var(--_fg);\n}\n\n.drawer-filter {\n flex: 0 0 auto;\n box-sizing: border-box;\n width: calc(100% - var(--_pad) * 2);\n margin: var(--_space) var(--_pad) 0;\n padding: 6px 10px;\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n background: var(--_input-bg);\n color: var(--_fg);\n font: inherit;\n font-size: 0.9em;\n}\n\n.drawer-filter::placeholder {\n color: var(--_muted);\n}\n\n.drawer-list {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n /* Scrolling past the end of this must not scroll the page behind it. */\n overscroll-behavior: contain;\n}\n\n.drawer-empty {\n padding: var(--_pad);\n font-size: 0.9em;\n color: var(--_muted);\n}\n\n/* An age group's heading: quieter than the rows it heads, and not a stop for Tab. */\n.drawer-group-label {\n padding: 0.75rem var(--_pad) 0.25rem;\n border-bottom: 1px solid var(--_border);\n font-size: 0.75em;\n font-weight: 600;\n color: var(--_muted);\n}\n\n.drawer-row {\n display: flex;\n align-items: stretch;\n border-bottom: 1px solid var(--_border);\n}\n\n.drawer-row--active {\n background: var(--_assistant-bg);\n}\n\n.drawer-row-select {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.drawer-row-title {\n font-weight: 600;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-time {\n font-size: 0.72em;\n color: var(--_muted);\n}\n\n.drawer-row-preview {\n font-size: 0.8em;\n color: var(--_muted);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.drawer-row-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 6px;\n}\n\n.drawer-row-rename,\n.drawer-row-delete {\n border: none;\n background: none;\n color: var(--_muted);\n font-size: 0.9em;\n padding: 4px;\n cursor: pointer;\n}\n\n.drawer-rename-input {\n flex: 1;\n min-width: 0;\n margin: 6px 10px;\n padding: 4px 8px;\n border: 1px solid var(--_accent);\n border-radius: 6px;\n background: var(--_input-bg);\n color: var(--_fg);\n font: inherit;\n}\n\n.drawer-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n font-size: 0.85em;\n}\n\n.drawer-confirm-label {\n color: var(--_danger);\n}\n\n.drawer-confirm-yes {\n border: none;\n border-radius: 6px;\n background: var(--_danger);\n color: var(--_on-danger);\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n.drawer-confirm-no {\n border: 1px solid var(--_border);\n border-radius: 6px;\n background: none;\n color: inherit;\n padding: 3px 10px;\n font: inherit;\n cursor: pointer;\n}\n\n/* Embedded placement: an inline, flush side panel rather than a dimmed,\n floating slide-over. */\n:host([placement=\"embedded\"]) .drawer-backdrop {\n background: none;\n}\n\n/* The way back out of the list. It sits beside New chat, which is the control\n it must not be mistaken for: one returns you to the conversation you were\n reading, the other replaces it. */\n.drawer-close {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: inherit;\n font: inherit;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n}\n\n.drawer-close:hover {\n background: var(--_hover);\n}\n\n:host([placement=\"embedded\"]) .drawer-panel {\n width: 100%;\n border-right: none;\n box-shadow: none;\n}\n`;\n", "// The approval card that gates a server-side tool call.\nexport const APPROVAL_STYLES: string = `\n/* Approval card \u2014 the server-side-tool gate (approve/deny an interrupt). */\n.approval {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--_bg);\n border: 1px solid var(--_accent);\n border-radius: 10px;\n}\n\n.approval[data-resolved] {\n opacity: 0.7;\n border-color: var(--_border);\n}\n\n.approval-body {\n font-weight: 600;\n}\n\n.approval-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.approval-btn {\n border: 1px solid var(--_border);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--_bg);\n color: var(--_fg);\n}\n\n.approval-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.approval-btn--approve {\n border-color: var(--_accent);\n background: var(--_accent);\n color: var(--_on-accent);\n}\n`;\n", "// The confirmation card for a destructive client tool, and the editable\n// arguments an approval shares with it.\nexport const CONFIRMATION_STYLES: string = `\n/* Inline confirmation card \u2014 lives in the transcript, no focus-stealing overlay. */\n.confirm {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--_bg);\n border: 1px solid var(--_accent);\n border-radius: 10px;\n}\n\n.confirm[data-resolved] {\n opacity: 0.7;\n border-color: var(--_border);\n}\n\n.confirm-body {\n font-weight: 600;\n}\n\n.confirm-args {\n margin: 0;\n padding: 8px 10px;\n max-height: 140px;\n overflow: auto;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n background: var(--_assistant-bg);\n border-radius: 8px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.confirm-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.confirm-btn {\n border: 1px solid var(--_border);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--_bg);\n color: var(--_fg);\n}\n\n.confirm-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.confirm-btn--confirm {\n border-color: var(--_accent);\n background: var(--_accent);\n color: var(--_on-accent);\n}\n\n/* The session waiver. Deliberately the quietest of the three: it is the widest\n decision on the card, so it should be reachable without being the one the eye\n lands on when the user means to say yes once. */\n.confirm-btn--always {\n font-weight: 500;\n opacity: 0.85;\n}\n\n.confirm-btn--always:hover,\n.confirm-btn--always:focus-visible {\n opacity: 1;\n}\n\n/* Editable arguments on an approval card. A plain field rather than a code\n editor: it holds the JSON a card already displays, and the only interaction\n is correcting a value before letting the call run. */\n.approval-edit {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.approval-args {\n box-sizing: border-box;\n width: 100%;\n resize: vertical;\n border: 1px solid var(--_border);\n border-radius: 8px;\n padding: 8px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 0.85em;\n background: var(--_bg);\n color: var(--_fg);\n}\n\n.approval-args:focus-visible {\n border-color: var(--_accent);\n outline: none;\n}\n\n.approval-error {\n font-size: 0.85em;\n color: var(--_danger);\n}\n\n/* Message action row. Sits under a finished assistant bubble.\n`;\n", "// The question card the agent asks the user through.\nexport const QUESTION_STYLES: string = `\n/* Question card \u2014 the built-in ask_user prompt (radios and/or free text). */\n.question {\n align-self: stretch;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px;\n background: var(--_bg);\n border: 1px solid var(--_accent);\n border-radius: 10px;\n}\n\n.question[data-resolved] {\n opacity: 0.7;\n border-color: var(--_border);\n}\n\n.question-body {\n font-weight: 600;\n}\n\n.question-options {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.question-choice {\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n\n.question-input {\n box-sizing: border-box;\n width: 100%;\n padding: 8px 10px;\n font: inherit;\n color: var(--_fg);\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: 8px;\n}\n\n.question-input:disabled {\n opacity: 0.6;\n}\n\n.question-actions {\n display: flex;\n justify-content: flex-end;\n}\n\n.question-btn {\n border: 1px solid var(--_accent);\n border-radius: 8px;\n padding: 8px 14px;\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n background: var(--_accent);\n color: var(--_on-accent);\n}\n\n.question-btn:disabled {\n cursor: default;\n opacity: 0.6;\n}\n`;\n", "// The place chip: where in the app the user is, drawn in the composer's tool\n// row between the attach and voice controls and Send.\nexport const PLACE_STYLES: string = `\n/* One quiet pill: a mark, the place, its detail, and the eye toggle. Muted at\n rest so it reads as a fact about the message rather than a control. It takes\n what the row's buttons leave and shrinks before Send can leave the row: the\n label truncates with an ellipsis and the chip's title carries it in full. */\n.place {\n display: inline-flex;\n align-items: center;\n flex: 0 1 auto;\n gap: 6px;\n min-width: 0;\n height: var(--_tool-btn-size);\n box-sizing: border-box;\n margin-inline-start: 4px;\n padding: 0 2px 0 8px;\n border: 1px solid var(--_border);\n border-radius: 999px;\n color: var(--_muted);\n font-size: 0.85em;\n line-height: 1;\n}\n\n.place-icon {\n display: inline-flex;\n flex: none;\n}\n\n.place-icon .glyph,\n.place-toggle .glyph,\n.place-icon img {\n width: 14px;\n height: 14px;\n}\n\n.place-icon img {\n border-radius: 3px;\n}\n\n.place-text {\n display: inline-flex;\n gap: 6px;\n min-width: 0;\n overflow: hidden;\n}\n\n.place-label,\n.place-detail {\n flex: 0 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.place-label {\n color: var(--_fg);\n}\n\n.place-detail::before {\n content: \"\\\\00B7\";\n margin-inline-end: 6px;\n}\n\n.place-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--_muted);\n cursor: pointer;\n}\n\n.place-toggle:hover {\n background: var(--_hover);\n color: var(--_fg);\n}\n\n/* An author display beats the user-agent rule for the hidden property, so each\n class above that sets one says it again for the hidden state: a chip with no\n place takes no space in the row. */\n.place[hidden],\n.place-icon[hidden],\n.place-text[hidden],\n.place-detail[hidden],\n.place-toggle[hidden] {\n display: none;\n}\n\n/* Withheld from the next message: dashed and struck through, so the chip still\n says where the user is while saying plainly the agent is not told. */\n.place[data-excluded] {\n border-style: dashed;\n}\n\n.place[data-excluded] .place-label,\n.place[data-excluded] .place-detail {\n color: var(--_muted);\n text-decoration: line-through;\n}\n`;\n", "// Collapsing and expanding: the animation toward the launcher, the in-flow\n// and page placements that collapse differently or not at all, and the two\n// collapse-to targets: the bottom bar, and the host's own (hidden here, with\n// the conversation list beside the host's button).\nexport const COLLAPSE_STYLES: string = `\n/* \u2500\u2500 Collapse \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Collapsing shrinks the widget to the round floating launcher: the panel\n scales toward the launcher's corner and fades, the launcher pops in from the\n same point. Both halves are transform and opacity only, so the morph runs on\n the compositor and never reflows the host page.\n\n The host box keeps its expanded size, since animating it would animate\n layout and a dragged --ag-ui-width would fight the launcher's own size.\n Nothing paints there once the panel is gone, so the box only has to stop\n swallowing clicks: pointer events go to none and the launcher takes them.\n\n Two placements do not use it: \"sidebar\" slides to its rail (below), and\n \"embedded\" keeps its header bar, having no corner for a floating circle that\n would escape the host's layout. \"page\" has no collapsed state at all. */\n:host([collapsed]) {\n pointer-events: none;\n /* A collapsed host has to be allowed to shrink, and in the layout hosts\n actually use it is not. Every collapse path here works by letting the host\n size to its content -- the in-flow ones set height: auto, the floating one\n leaves only the launcher -- and a flex or grid parent whose align-items is\n the default stretch value overrides all of it. The panel then hides and the box\n it occupied stays: a header bar over several hundred pixels of nothing.\n Every known consumer hit this, because putting the element in a flex column\n beside the page content is the obvious way to embed it. */\n align-self: start;\n}\n\n:host([collapsed]) .chat {\n opacity: 0;\n transform: scale(0.94);\n visibility: hidden;\n}\n\n/* visibility keeps the panel out of the tab order and the a11y tree at rest\n without display:none killing the transition. It interpolates so any progress\n below 1 still counts as visible: the panel stays on screen for the whole\n collapse, flips hidden exactly at the end, and on expand is visible from the\n first frame. */\n.chat {\n transform-origin: bottom right;\n transition:\n opacity var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease),\n visibility var(--_motion) var(--_ease);\n}\n\n:host([placement=\"bottom-left\"]) .chat {\n transform-origin: bottom left;\n}\n\n/* Once the launcher has been dragged the element places itself, and stamps the\n corner it chose to open away from. The morph has to start at that same\n corner: scaling out of the one the placement originally guessed reads as the\n panel leaping across the screen before it opens.\n\n Equal specificity to the placement rule above, so source order is what lets\n the stamped value win -- the same arrangement the resize grip uses, and the\n same trap. Write these with = on the whole hyphenated token; a ~= would match\n whitespace-separated words and so could never match at all. */\n:host([data-expand-corner=\"top-left\"]) .chat {\n transform-origin: top left;\n}\n\n:host([data-expand-corner=\"top-right\"]) .chat {\n transform-origin: top right;\n}\n\n:host([data-expand-corner=\"bottom-left\"]) .chat {\n transform-origin: bottom left;\n}\n\n:host([data-expand-corner=\"bottom-right\"]) .chat {\n transform-origin: bottom right;\n}\n\n/* The in-flow placement keeps the original collapse: hide the body, let the\n host shrink to the header bar. */\n:host([collapsed][placement=\"embedded\"]) {\n height: auto;\n max-height: none;\n pointer-events: auto;\n}\n\n:host([collapsed][placement=\"embedded\"]) .chat {\n opacity: 1;\n transform: none;\n visibility: visible;\n}\n\n/* It keeps the header bar, so the launcher must stay out of the way: an\n embedded host is position: static, which would let an absolutely-positioned\n circle escape the layout and land against whatever the page positions. */\n:host([collapsed][placement=\"embedded\"]) .launcher {\n visibility: hidden;\n opacity: 0;\n}\n\n:host([collapsed][placement=\"embedded\"]) .messages-wrap,\n:host([collapsed][placement=\"embedded\"]) .messages,\n:host([collapsed][placement=\"embedded\"]) .input-row,\n:host([collapsed][placement=\"embedded\"]) slot[name=\"above-composer\"],\n:host([collapsed][placement=\"embedded\"]) .skill-chips,\n:host([collapsed][placement=\"embedded\"]) .skill-palette,\n:host([collapsed][placement=\"embedded\"]) .skill-hint {\n display: none;\n}\n\n/* The above-composer slot is in the list above because it is the host's content\n against the composer: a bare slot has no box of its own, so hiding the input\n row alone left the slotted row showing under the header bar. Its sibling slot\n below the composer is a footer and is left to the host. */\n\n/* The page placement has no collapsed state, so it offers no control for one.\n A dedicated route has no \"away\" to go to: shrinking it left a strip of\n application chrome fixed over a route that no longer had an owner, and this\n is the one placement where the launcher that would bring it back is hidden.\n\n Hiding the control is only half of it. The state has another way in -- the\n attribute can be written straight onto the element, and a value stored under\n a different placement is restored on connect -- and the JS guards that catch\n those cannot see an attribute set directly. So the placement neutralises the\n state here as well: with the collapse rules above no longer naming \"page\", an\n unguarded collapsed attribute would otherwise fall through to the generic\n rule that scales the panel away and drops pointer events, leaving nothing on\n screen and no launcher to press. */\n:host([placement=\"page\"]) .header-btn--collapse {\n display: none;\n}\n\n:host([placement=\"page\"][collapsed]) {\n pointer-events: auto;\n align-self: auto;\n}\n\n:host([placement=\"page\"][collapsed]) .chat {\n opacity: 1;\n transform: none;\n visibility: visible;\n}\n\n/* \u2500\u2500 Bottom bar (collapse-to=\"bar\") \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The round launcher drawn as a strip along the bottom edge: the title, the\n unread badge and a running mark, with a history button beside it. The\n wrapper draws no box anywhere else, so the launcher lays out against the\n host as it always has; under the bar it is fixed to the bottom of the\n viewport, outside the host's box, which sits where the panel opens.\n\n Here rather than with the launcher because it restyles the launcher's\n collapsed and pressed states, which this module follows in the cascade.\n The strip stays drawn while the panel is open on a wide viewport, as the\n way to minimise it; the phone block hides it then. */\n.dock-bar {\n display: contents;\n}\n\n.bar-history,\n.bar-place {\n display: none;\n}\n\n:host([data-collapsed-to=\"bar\"]) .dock-bar {\n position: fixed;\n inset: auto var(--_viewport-inset-right) var(--_viewport-inset-bottom) var(--_viewport-inset-left);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 4px;\n box-sizing: border-box;\n min-height: 40px;\n padding: 4px 8px;\n border-top: 1px solid var(--_border);\n background: var(--_bg);\n color: var(--_fg);\n pointer-events: auto;\n}\n\n/* A left-hand chat keeps its side: its controls and its panel at the left end. */\n:host([data-collapsed-to=\"bar\"][placement=\"bottom-left\"]) .dock-bar {\n justify-content: flex-start;\n}\n\n/* The launcher as the strip's title button. Its resting state hides it behind\n an open panel; the bar keeps it on screen, so every part of that state is\n restated, and the hover and press scales are cancelled at the weight of the\n rules that set them. The title truncates rather than taking a fixed width,\n leaving room beside it for whatever a later release adds to the row. */\n:host([data-collapsed-to=\"bar\"]) .launcher {\n position: static;\n inset: auto;\n flex: 0 1 auto;\n justify-content: flex-start;\n gap: 8px;\n width: auto;\n min-width: 0;\n max-width: 100%;\n height: auto;\n min-height: 32px;\n padding: 4px 10px;\n border-radius: 8px;\n background: transparent;\n color: var(--_fg);\n box-shadow: none;\n touch-action: manipulation;\n opacity: 1;\n transform: none;\n visibility: visible;\n}\n\n:host([data-collapsed-to=\"bar\"]) .launcher:hover {\n background: var(--_wash);\n}\n\n/* Bare at rest, like the history button beside it. The themes frame the\n round launcher with a border or a shadow at the weight of the rule above\n and later in the cascade, so the child combinator on the bar is there for\n weight, not scope: the launcher is always the bar's direct child. */\n:host([data-collapsed-to=\"bar\"]) .dock-bar > .launcher {\n border: 0;\n box-shadow: none;\n}\n\n:host([data-collapsed-to=\"bar\"][collapsed]) .launcher:hover,\n:host([data-collapsed-to=\"bar\"][collapsed]) .launcher:active {\n transform: none;\n}\n\n:host([data-collapsed-to=\"bar\"]) .launcher .icon-holder {\n flex: none;\n width: 18px;\n height: 18px;\n}\n\n:host([data-collapsed-to=\"bar\"]) .rail-label {\n display: block;\n min-width: 0;\n overflow: hidden;\n font-size: 0.9em;\n font-weight: 600;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n/* The place beside the title, secondary text that truncates first so the\n history button never leaves the strip. Its shrink factor is large so that\n it gives way before the title does, which is the strip's first word.\n Withheld places keep the chip's\n dashed, struck-through look: the bar must not claim the page is sent. */\n:host([data-collapsed-to=\"bar\"]) .bar-place {\n display: inline-flex;\n flex: 0 100 auto;\n gap: 6px;\n min-width: 0;\n overflow: hidden;\n padding: 2px 0;\n border-bottom: 1px solid transparent;\n color: var(--_muted);\n font-size: 0.85em;\n line-height: 1.2;\n}\n\n:host([data-collapsed-to=\"bar\"]) .bar-place[hidden],\n:host([data-collapsed-to=\"bar\"]) .bar-place .place-detail[hidden] {\n display: none;\n}\n\n:host([data-collapsed-to=\"bar\"]) .bar-place[data-excluded] {\n border-bottom-style: dashed;\n border-bottom-color: var(--_border);\n}\n\n:host([data-collapsed-to=\"bar\"]) .bar-place[data-excluded] .place-label,\n:host([data-collapsed-to=\"bar\"]) .bar-place[data-excluded] .place-detail {\n text-decoration: line-through;\n}\n\n:host([data-collapsed-to=\"bar\"]) .launcher-badge {\n position: static;\n flex: none;\n box-shadow: none;\n}\n\n/* The running mark: the element already reflects a run as data-running, so\n the bar shows one without a state of its own. */\n:host([data-collapsed-to=\"bar\"][data-running]) .launcher::after {\n content: \"\";\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--_accent);\n animation: ag-ui-dock-running 1.2s ease-in-out infinite;\n}\n\n@keyframes ag-ui-dock-running {\n 50% {\n opacity: 0.35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([data-collapsed-to=\"bar\"][data-running]) .launcher::after {\n animation: none;\n }\n}\n\n:host([data-collapsed-to=\"bar\"]) .bar-history {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: var(--_muted);\n font: inherit;\n cursor: pointer;\n}\n\n:host([data-collapsed-to=\"bar\"]) .bar-history:hover {\n background: var(--_wash);\n color: var(--_fg);\n}\n\n/* Both declare a display of their own, so each needs its own hidden rule. */\n:host([data-collapsed-to]) .dock-bar[hidden],\n:host([data-collapsed-to]) .bar-history[hidden] {\n display: none;\n}\n\n/* A panel a host sized to the whole window stands on the strip, whose fixed box would\n draw over the composer's foot. So it goes as it does on a phone, by display, so the\n bar measures 0 and the host's padding goes with it, and the header's minimise\n control is the way back. Collapsed, the strip is the way back, so it stays. */\n:host([data-collapsed-to=\"bar\"][data-fills-window]:not([collapsed])) .dock-bar {\n display: none;\n}\n\n/* History from the bar: the panel's own drawer, moved beside the bar while\n the panel is away, drawn as a popover standing on the bar's end. There is\n no backdrop; a press outside the bar closes it, as Escape does.\n\n Its outer edge keeps the panel's gutter, so the popover and the panel line\n up on the side they share. The bar is already inset by the host's reserved\n edges, so the gutter alone is the whole offset from it, and the width cap\n leaves the gutter free on both sides. A phone keeps a narrow margin\n instead, in the block below: the panel there is the whole screen, so there\n is no edge to line up with. */\n:host([data-collapsed-to=\"bar\"]) .dock-bar > .drawer {\n inset: auto var(--_edge-gutter) calc(100% + 8px) auto;\n width: min(320px, calc(var(--_viewport-width) - 2 * var(--_edge-gutter)));\n height: min(440px, calc(var(--_viewport-height) - var(--_dock-bottom, 0px) - 16px));\n border-radius: var(--_panel-radius);\n box-shadow: var(--_shadow);\n overflow: hidden;\n}\n\n:host([data-collapsed-to=\"bar\"][placement=\"bottom-left\"]) .dock-bar > .drawer {\n inset: auto auto calc(100% + 8px) var(--_edge-gutter);\n}\n\n@media (max-width: 600px) {\n :host([data-collapsed-to=\"bar\"]:not([data-small-viewport=\"off\"])) .dock-bar > .drawer {\n inset: auto 8px calc(100% + 8px) auto;\n width: min(320px, calc(100vw - 16px));\n }\n\n :host([data-collapsed-to=\"bar\"][placement=\"bottom-left\"]:not([data-small-viewport=\"off\"])) .dock-bar > .drawer {\n inset: auto auto calc(100% + 8px) 8px;\n }\n}\n\n:host([data-collapsed-to=\"bar\"]) .dock-bar > .drawer .drawer-backdrop {\n display: none;\n}\n\n/* The popover closes in one step. The in-panel drawer slides its panel out\n and holds the overlay's visibility until the slide ends; here the overlay\n is the popover's own box, rounded and clipped, so the slide moved the list\n inside a box that stayed put (read as a shrink) and the box went only once\n the slide had finished. This outweighs the drawer's own hidden rule, so the\n box hides at once, and whatever the list inside does is out of sight. The\n way in needs no rule: the drawer is moved into the bar as it opens, and a\n moved element starts no transition. Nothing is left for reduced motion. */\n:host([data-collapsed-to=\"bar\"]) .dock-bar > .drawer {\n transition: none;\n}\n\n/* Border-box, so the list's own border sits inside the popover's clipped box\n rather than 2px past its bottom edge. */\n:host([data-collapsed-to=\"bar\"]) .dock-bar > .drawer .drawer-panel {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid var(--_border);\n border-radius: inherit;\n box-shadow: none;\n}\n\n/* \u2500\u2500 The host's own bar (collapse-to=\"none\") \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Collapsed is hidden: no launcher, no rail, no header bar. The host's control\n calls the public API, and the panel rises from its anchor (the dock module)\n or from the placement's corner. Each placement's own collapsed rule is\n overridden at its weight or above, later in the cascade. */\n:host([data-collapsed-to=\"none\"][collapsed]) {\n pointer-events: none;\n}\n\n:host([data-collapsed-to=\"none\"][collapsed]) .launcher {\n display: none;\n}\n\n:host([data-collapsed-to=\"none\"][collapsed][placement=\"sidebar\"]) {\n width: 0;\n}\n\n:host([data-collapsed-to=\"none\"][collapsed][placement=\"embedded\"]) {\n display: none;\n}\n\n/* The conversation list from the host's button: the panel's own drawer, moved\n out of the hidden panel and stood beside the button, below one in the top half\n of the viewport and above one in the bottom half. The element writes where,\n from the button's box. No backdrop: a press outside closes it, as Escape does.\n The wrapper draws no box; the host stops taking presses while collapsed, so\n the list takes its own back. A phone keeps a narrow margin on both sides. */\n.threads-popover {\n display: contents;\n}\n\n:host([data-collapsed-to=\"none\"]) .threads-popover > .drawer {\n position: fixed;\n inset: var(--_threads-top, auto) var(--_threads-right, 8px) var(--_threads-bottom, auto) auto;\n width: min(320px, calc(var(--_viewport-width) - 16px));\n height: min(440px, var(--_threads-room, 440px));\n border-radius: var(--_panel-radius);\n box-shadow: var(--_shadow);\n overflow: hidden;\n pointer-events: auto;\n transition: none;\n}\n\n:host([data-collapsed-to=\"none\"]) .threads-popover > .drawer[hidden] {\n pointer-events: none;\n}\n\n@media (max-width: 600px) {\n :host([data-collapsed-to=\"none\"]:not([data-small-viewport=\"off\"])) .threads-popover > .drawer {\n right: 8px;\n left: 8px;\n width: auto;\n }\n}\n\n:host([data-collapsed-to=\"none\"]) .threads-popover > .drawer .drawer-backdrop {\n display: none;\n}\n\n:host([data-collapsed-to=\"none\"]) .threads-popover > .drawer .drawer-panel {\n box-sizing: border-box;\n width: 100%;\n border: 1px solid var(--_border);\n border-radius: inherit;\n box-shadow: none;\n}\n`;\n", "// Where a docked panel stands: above the bottom bar under collapse-to=\"bar\",\n// above the host's anchor under collapse-to=\"none\". Token restatements only;\n// the bar's own shape is in the collapse module, after the launcher it\n// restyles.\nexport const DOCK_STYLES: string = `\n/* \u2500\u2500 Dock \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A docked panel rises from the bar along the bottom edge, or from the host's\n own control, instead of resting in a corner of its own. The element stamps\n what it collapses to as data-collapsed-to, and writes where the dock is as\n two private properties: --_dock-bottom, the bar's height or the distance\n from the layout viewport's bottom to the anchor's top, and --_dock-right,\n the anchor's distance from the right edge (a third, --_dock-top, for a\n panel below its anchor). Both are read with a 0px\n fallback, so a panel measured before the bar has laid out stands where a\n bar of no height would put it.\n\n The cap follows the token block's rule: what the host left free less the\n one gutter the anchored edge spends, so a panel grown to the cap runs from\n just above the bar to the far edge. A host therefore needs no inset to keep\n the panel off its bar; --ag-ui-inset still wins when set. A panel the user\n dragged off its dock is written there inline, which is how the dragged spot\n outranks every rule below, the anchor gap included; the element holds that\n spot above the bar or the anchor itself, and drops it on a phone, where the\n small-viewport block reads the same property first.\n\n These blocks restate tokens and nothing else, and sit ahead of the phone\n block at no more weight than it has, so on a phone the panel is the screen\n as every other placement is there. The bar measures 0 while it is not drawn\n (a phone with the panel open), which is what lets the side and full shapes\n below fall back to the whole height without a phone rule of their own.\n\n Each placement keeps its own side and shape; only the bottom edge moves. */\n:host([data-collapsed-to=\"bar\"]) {\n --_inset: var(\n --ag-ui-inset,\n auto calc(var(--_edge-gutter) + var(--_viewport-inset-right))\n calc(\n var(--_edge-gutter) + var(--_viewport-inset-bottom) +\n max(var(--_dock-bottom, 0px), var(--_keyboard-inset))\n )\n auto\n );\n --_max-height: var(--ag-ui-max-height, calc(var(--_viewport-height) - var(--_dock-bottom, 0px) - var(--_edge-gutter)));\n}\n\n:host([data-collapsed-to=\"bar\"][placement=\"bottom-left\"]) {\n --_inset: var(\n --ag-ui-inset,\n auto auto\n calc(\n var(--_edge-gutter) + var(--_viewport-inset-bottom) +\n max(var(--_dock-bottom, 0px), var(--_keyboard-inset))\n )\n calc(var(--_edge-gutter) + var(--_viewport-inset-left))\n );\n}\n\n/* The column and the full-screen panel stop at the bar rather than covering\n it, so the bar stays where the user minimises from. */\n:host([data-collapsed-to=\"bar\"][placement=\"side\"]) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)\n calc(var(--_viewport-inset-bottom) + var(--_dock-bottom, 0px)) auto\n );\n --_height: var(--ag-ui-height, calc(var(--_viewport-height) - var(--_dock-bottom, 0px)));\n --_max-height: var(--ag-ui-max-height, calc(var(--_viewport-height) - var(--_dock-bottom, 0px)));\n}\n\n:host([data-collapsed-to=\"bar\"][placement=\"full\"]) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)\n calc(var(--_viewport-inset-bottom) + var(--_dock-bottom, 0px)) var(--_viewport-inset-left)\n );\n --_height: var(--ag-ui-height, calc(var(--_viewport-height) - var(--_dock-bottom, 0px)));\n --_max-height: var(--ag-ui-max-height, calc(var(--_viewport-height) - var(--_dock-bottom, 0px)));\n}\n\n/* The host's own bar: the panel stands the anchor gap (8px unless the host\n says otherwise) above the anchor and lines up with its right edge. Only\n once the element found the anchor; until then, and when it never does, the\n placement's own corner stands.\n\n The cap spends the larger of the gap and the gutter. The gutter alone is\n what this always spent, so the default is unchanged; but a host that opens\n the gap past the gutter to clear a tall toolbar would otherwise push a\n panel grown to the cap off the top of the window by the difference.\n\n The width cap spends a gutter on each side: the panel is held off both\n window edges, so one gutter would leave a panel grown to the cap flush\n against the edge the anchor holds it to. */\n:host([data-collapsed-to=\"none\"][data-dock-anchored]) {\n --_inset: var(--ag-ui-inset, auto var(--_dock-right, 0px) calc(var(--_dock-bottom, 0px) + var(--_anchor-gap)) auto);\n --_max-width: var(--ag-ui-max-width, calc(var(--_viewport-width) - 2 * var(--_edge-gutter)));\n --_max-height: var(\n --ag-ui-max-height,\n calc(var(--_viewport-height) - var(--_dock-bottom, 0px) - max(var(--_edge-gutter), var(--_anchor-gap)))\n );\n}\n\n/* The same, below the anchor, for a host whose control sits in a header: the\n element stamps the side it resolved from anchor-side as the attribute's\n value and writes the anchor's bottom as --_dock-top. Keyed on that value\n rather than on another attribute, so the rule weighs what the one above\n weighs and the phone block after it still wins by order. --_dock-right is\n the anchor's right edge unless the panel would then cross the left gutter,\n on either side. */\n:host([data-collapsed-to=\"none\"][data-dock-anchored=\"below\"]) {\n --_inset: var(--ag-ui-inset, calc(var(--_dock-top, 0px) + var(--_anchor-gap)) var(--_dock-right, 0px) auto auto);\n --_max-height: var(\n --ag-ui-max-height,\n calc(var(--_viewport-height) - var(--_dock-top, 0px) - max(var(--_edge-gutter), var(--_anchor-gap)))\n );\n}\n`;\n", "// The embedded placement: no floating chrome, laid out by the host.\nexport const EMBEDDED_STYLES: string = `\n/* Embedded: drop the floating chrome and the high z-index stacking context so\n the widget lives in the host's own layout (fixes overlay/z-index clashes). */\n:host([placement=\"embedded\"]) {\n --_position: var(--ag-ui-position, static);\n --_width: var(--_drag-width, var(--ag-ui-width, 100%));\n --_height: var(--_drag-height, var(--ag-ui-height, 100%));\n --_max-width: var(--ag-ui-max-width, 100%);\n --_max-height: var(--ag-ui-max-height, 100%);\n --_shadow: var(--ag-ui-shadow, none);\n --_z-index: var(--ag-ui-z-index, auto);\n}\n`;\n", "// The launcher a collapsed widget shrinks to: the round button, its unread\n// badge, and the sidebar's edge rail, which is the same element styled again.\nexport const LAUNCHER_STYLES: string = `\n/* \u2500\u2500 Launcher \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n What a collapsed widget shrinks to: a round floating button by default, the\n sidebar's slim edge rail under that placement. A sibling of the panel, so it\n survives the panel being hidden, and the only part of a collapsed widget\n that takes pointer events. */\n.launcher {\n display: flex;\n position: absolute;\n inset: var(--_launcher-inset);\n align-items: center;\n justify-content: center;\n width: var(--_launcher-size);\n height: var(--_launcher-size);\n padding: 0;\n border: none;\n border-radius: var(--_launcher-radius);\n background: var(--_launcher-bg);\n color: var(--_launcher-fg);\n box-shadow: var(--_shadow);\n font: inherit;\n cursor: pointer;\n pointer-events: auto;\n /* A touch drag on the launcher moves it; without this the page scrolls under\n the finger instead and the launcher never moves at all. */\n touch-action: none;\n opacity: 0;\n transform: scale(0.4);\n visibility: hidden;\n transition:\n opacity var(--_motion) var(--_ease),\n transform var(--_motion) var(--_ease-pop),\n visibility var(--_motion) var(--_ease);\n}\n\n/* The launcher grows out of the corner the panel shrank into. It stays laid\n out at rest rather than display:none, which is what lets it animate both in\n and out: an unrendered element has no before-change style to transition\n from, and one flipping display to none cannot transition at all. visibility\n keeps it unpaintable, untabbable and unclickable in between, so the expanded\n panel's own controls underneath stay reachable. */\n:host([collapsed]) .launcher {\n opacity: 1;\n transform: none;\n visibility: visible;\n}\n\n:host([collapsed]) .launcher:hover {\n transform: scale(1.06);\n}\n\n:host([collapsed]) .launcher:active {\n transform: scale(0.94);\n}\n\n/* A drag is a press and a hover at the same time, so both scale rules above are\n live throughout it. Cancelling them is what keeps the launcher the size of\n the thing under the pointer while it travels; the position itself comes from\n inset, which nothing here transitions, so it tracks the pointer exactly. */\n:host([collapsed]) .launcher[data-dragging] {\n transform: none;\n cursor: grabbing;\n}\n\n.launcher .icon-holder {\n width: var(--_launcher-icon-size);\n height: var(--_launcher-icon-size);\n}\n\n/* The unread badge rides the launcher's top-right corner. The ring in the\n widget's own background is what separates it from the launcher underneath,\n whatever colour the host themes either one. */\n.launcher-badge {\n position: absolute;\n top: -2px;\n right: -2px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: var(--_badge-size);\n height: var(--_badge-size);\n padding: 0 5px;\n border-radius: 999px;\n background: var(--_badge-bg);\n color: var(--_badge-fg);\n font-size: var(--_badge-font-size);\n font-weight: 600;\n line-height: 1;\n box-shadow: 0 0 0 2px var(--_bg);\n}\n\n.launcher-badge[hidden] {\n display: none;\n}\n\n/* The sidebar collapses to an edge rail instead: full height, square, flush\n against the dock. It slides in with the panel rather than popping. */\n/* The edge rail. It reads as the docked edge of a panel rather than a coloured\n stripe: the surface the panel is made of, a border on the side it docks\n against, and the accent kept for the icon -- a full-height slab of accent is\n the loudest thing on the page and says the least about itself.\n\n Content sits at the top rather than centred, because a control floating in\n the middle of a screen-high column has nothing to belong to. */\n:host([placement=\"sidebar\"][collapsed]) .launcher {\n inset: 0;\n width: auto;\n height: auto;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n gap: 12px;\n padding-top: 14px;\n border: 0;\n border-inline-start: 1px solid var(--_border);\n border-radius: 0;\n background: var(--_bg);\n color: var(--_fg);\n box-shadow: none;\n transform: none;\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"][collapsed]) .launcher {\n border-inline-start: 0;\n border-inline-end: 1px solid var(--_border);\n}\n\n/* The icon keeps the accent, so there is one obvious thing to press.\n\n The glyph is sized here rather than left to fill the holder. A glyph in an\n icon holder takes the holder's whole box by default, which is right where the\n holder is only a box and wrong the moment it becomes a filled circle: the\n mark then runs edge to edge and reads as a square crammed into a disc. The\n proportion is the floating launcher's own -- a 26px glyph in a 56px bubble --\n so the two collapsed states look like the same widget. */\n:host([placement=\"sidebar\"][collapsed]) .launcher .icon-holder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n background: var(--_header-bg);\n color: var(--_header-fg);\n}\n\n:host([placement=\"sidebar\"][collapsed]) .launcher .icon-holder .glyph,\n:host([placement=\"sidebar\"][collapsed]) .launcher .icon-holder .icon-img {\n width: 16px;\n height: 16px;\n}\n\n/* Written down the rail, which is the only direction it fits. Reading upward\n is the convention for a right-hand edge and matches how a docked panel's\n label is set everywhere it appears. */\n.rail-label {\n display: none;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .rail-label {\n display: block;\n writing-mode: vertical-rl;\n transform: rotate(180deg);\n max-height: calc(100% - 96px);\n overflow: hidden;\n font-size: 0.9em;\n font-weight: 600;\n letter-spacing: 0.02em;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"][collapsed]) .rail-label {\n writing-mode: vertical-rl;\n transform: none;\n}\n\n/* Every transition in the stylesheet is timed by --_motion, so collapsing it to a\n frame is the whole reduced-motion story: states still change (and display\n still flips at the end of its discrete transition), nothing travels. */\n@media (prefers-reduced-motion: reduce) {\n :host {\n --_motion: var(--ag-ui-motion, 0.001s);\n }\n}\n`;\n", "// The page and full placements: a full-bleed surface with a reading column.\nexport const PAGE_STYLES: string = `\n/* Page: full-bleed background with a centred reading column capped at\n --ag-ui-content-max-width, where \"full\" is edge-to-edge and left-aligned.\n The column comes from symmetric auto padding on the scroll area and\n composer rather than a per-row wrapper, so user pills still right-align and\n the assistant well spans the column. */\n:host([placement=\"page\"]) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)\n var(--_viewport-inset-bottom) var(--_viewport-inset-left)\n );\n --_width: var(--ag-ui-width, var(--_viewport-width));\n --_height: var(--ag-ui-height, var(--_viewport-height));\n --_max-width: var(--ag-ui-max-width, var(--_viewport-width));\n --_max-height: var(--ag-ui-max-height, var(--_viewport-height));\n --_panel-radius: var(--ag-ui-panel-radius, 0);\n}\n\n:host([placement=\"page\"]) .messages {\n padding-inline: max(var(--_pad), calc((100% - var(--_content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .input-row {\n padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));\n}\n\n/* The rows between the message list and the composer line up with the column\n too. Chips and tray are padding-based while palette and hint are\n margin-based, so each gets its own inline axis nudged by the same gutter. */\n:host([placement=\"page\"]) .skill-chips,\n:host([placement=\"page\"]) .attachment-tray {\n padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));\n}\n\n:host([placement=\"page\"]) .skill-palette,\n:host([placement=\"page\"]) .skill-hint {\n margin-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));\n}\n\n/* In the reading column the assistant well uses the full width; the user\n message stays a right-aligned pill (its default align-self + max-width). */\n:host([placement=\"page\"]) .message--assistant {\n max-width: 100%;\n}\n`;\n", "// The token values the bottom-left, side and full placements start from;\n// the default bottom-right corner is the token defaults themselves.\nexport const PRESET_STYLES: string = `\n/* \u2500\u2500 Placement presets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* Maximized, from the header control: a corner or docked panel takes the\n maximized size on both axes. Set on the box rather than the size aliases, so\n the size the user dragged is not read and the aliases stay the host's. The\n element refuses the state on page, full, embedded and at 600px or less, so\n no rule here has to. A collapsed attribute written straight on, which the\n element is not told of, still draws the collapsed box. A side column grows\n its width only, below and in the sidebar module. */\n:host([maximized]:not([collapsed]):not([placement=\"side\"]):not([placement=\"sidebar\"])) {\n width: var(--_maximized-width);\n height: var(--_maximized-height);\n}\n\n:host([placement=\"bottom-left\"]) {\n --_inset: var(\n --ag-ui-inset,\n auto auto calc(var(--_edge-gutter) + var(--_viewport-inset-bottom) + var(--_keyboard-inset))\n calc(var(--_edge-gutter) + var(--_viewport-inset-left))\n );\n}\n\n:host([placement=\"side\"]) {\n --_inset: var(--ag-ui-inset, calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right) var(--_viewport-inset-bottom) auto);\n --_width: var(--_drag-width, var(--ag-ui-width, 420px));\n --_height: var(--ag-ui-height, var(--_viewport-height));\n --_max-height: var(--ag-ui-max-height, var(--_viewport-height));\n --_panel-radius: var(--ag-ui-panel-radius, 0);\n}\n\n:host([placement=\"side\"][maximized]:not([collapsed])) {\n width: var(--_maximized-width);\n}\n\n:host([placement=\"full\"]) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)\n var(--_viewport-inset-bottom) var(--_viewport-inset-left)\n );\n --_width: var(--ag-ui-width, var(--_viewport-width));\n --_height: var(--ag-ui-height, var(--_viewport-height));\n --_max-width: var(--ag-ui-max-width, var(--_viewport-width));\n --_max-height: var(--ag-ui-max-height, var(--_viewport-height));\n --_panel-radius: var(--ag-ui-panel-radius, 0);\n}\n`;\n", "// The resize grips on every edge and corner, and which placements keep them.\nexport const RESIZE_STYLES: string = `\n/* Resize grips: every edge and every corner, so the panel can be dragged from\n whichever side the reader is already near. Absent entirely where the\n placement is full-bleed, since there is nothing to drag.\n\n The whole set is always laid out. Which edges the *layout* pins is not a\n question the stylesheet needs to answer any more -- it decided where the one\n grip went, and there is no longer one grip. The element still measures and\n stamps data-resize-anchor, because it decides what a drag on a pinned edge\n costs in position and which grip carries the tab stop, but no rule here\n reads it. */\n.resize-handle {\n position: absolute;\n z-index: 2;\n background: transparent;\n touch-action: none;\n}\n\n/* No grips while maximized: the element refuses the resize, so restore always\n lands on the size stored before it. */\n:host([maximized]) .resize-handle {\n display: none;\n}\n\n.resize-handle:focus-visible {\n outline: 2px solid var(--_accent);\n outline-offset: -2px;\n}\n\n/* Corners first in the file and last in the DOM, so they take the pointer\n where they overlap an edge strip. */\n.resize-handle--top-left,\n.resize-handle--top-right,\n.resize-handle--bottom-left,\n.resize-handle--bottom-right {\n width: var(--_grip-corner);\n height: var(--_grip-corner);\n}\n\n.resize-handle--top-left {\n top: 0;\n left: 0;\n cursor: nwse-resize;\n}\n\n.resize-handle--top-right {\n top: 0;\n right: 0;\n cursor: nesw-resize;\n}\n\n.resize-handle--bottom-left {\n bottom: 0;\n left: 0;\n cursor: nesw-resize;\n}\n\n.resize-handle--bottom-right {\n bottom: 0;\n right: 0;\n cursor: nwse-resize;\n}\n\n/* Edge strips, held clear of the corners at both ends so a corner drag is\n never swallowed by the edge next to it. */\n.resize-handle--left,\n.resize-handle--right {\n top: var(--_grip-corner);\n bottom: var(--_grip-corner);\n width: var(--_grip-edge);\n cursor: ew-resize;\n}\n\n.resize-handle--left {\n left: 0;\n}\n\n.resize-handle--right {\n right: 0;\n}\n\n.resize-handle--top,\n.resize-handle--bottom {\n left: var(--_grip-corner);\n right: var(--_grip-corner);\n height: var(--_grip-edge);\n cursor: ns-resize;\n}\n\n.resize-handle--top {\n top: 0;\n}\n\n.resize-handle--bottom {\n bottom: 0;\n}\n\n/* A docked panel a host sized to the whole window has nothing to give a grip: its size\n is the host's, and a place a grip left would outlast that size with the bar back\n under it. They go as they do on a phone. A corner panel keeps them, since it has no\n bar to stand clear of and a grip's place is its own. */\n:host([data-collapsed-to=\"bar\"][data-fills-window]) .resize-handle,\n:host([data-collapsed-to=\"none\"][data-fills-window]) .resize-handle {\n display: none;\n}\n\n/* Docked: the placement owns the height, so the horizontal edges and every\n corner are inert and must not advertise a drag that does nothing. The two\n vertical edges remain, which is the same affordance these placements had\n when there was one grip -- now on both sides, since either may be the inner\n one depending on which side the rail is docked to. */\n:host([placement=\"sidebar\"]) .resize-handle--top,\n:host([placement=\"sidebar\"]) .resize-handle--bottom,\n:host([placement=\"sidebar\"]) .resize-handle--top-left,\n:host([placement=\"sidebar\"]) .resize-handle--top-right,\n:host([placement=\"sidebar\"]) .resize-handle--bottom-left,\n:host([placement=\"sidebar\"]) .resize-handle--bottom-right,\n:host([placement=\"side\"]) .resize-handle--top,\n:host([placement=\"side\"]) .resize-handle--bottom,\n:host([placement=\"side\"]) .resize-handle--top-left,\n:host([placement=\"side\"]) .resize-handle--top-right,\n:host([placement=\"side\"]) .resize-handle--bottom-left,\n:host([placement=\"side\"]) .resize-handle--bottom-right {\n display: none;\n}\n\n/* The vertical edges run the full height once no corner shares them. */\n:host([placement=\"sidebar\"]) .resize-handle--left,\n:host([placement=\"sidebar\"]) .resize-handle--right,\n:host([placement=\"side\"]) .resize-handle--left,\n:host([placement=\"side\"]) .resize-handle--right {\n top: 0;\n bottom: 0;\n width: var(--_grip-edge-docked);\n}\n\n/* Full-bleed: nothing to drag. */\n:host([placement=\"full\"]) .resize-handle,\n:host([placement=\"page\"]) .resize-handle {\n display: none;\n}\n\n/* The visible mark on a grip.\n\n Filling the whole strip was what the single corner grip did, and at 14px\n square nobody ever saw it. On a strip running the length of an edge the same\n fill reads as a border the panel grew -- square ended, stopping short of the\n corner radius at both ends, and easily mistaken for a rendering fault rather\n than for something to grab.\n\n So the hit area stays the full strip and the mark is a short pill centred on\n it, which cannot be read as an edge of anything and never meets the radius.\n\n It shows on hover and focus as well as during the drag. With eight grips, a\n mark that appears only once you are already dragging is a mark that never\n told anyone the grips were there. */\n.resize-handle::after {\n content: \"\";\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n border-radius: 999px;\n background: var(--_accent);\n opacity: 0;\n transition: opacity var(--_motion) var(--_ease);\n}\n\n.resize-handle--top::after,\n.resize-handle--bottom::after {\n width: var(--_grip-mark-length);\n height: var(--_grip-mark-thickness);\n}\n\n.resize-handle--left::after,\n.resize-handle--right::after {\n width: var(--_grip-mark-thickness);\n height: var(--_grip-mark-length);\n}\n\n/* A corner has no length to run along, so it gets a dot instead of a pill. */\n.resize-handle--top-left::after,\n.resize-handle--top-right::after,\n.resize-handle--bottom-left::after,\n.resize-handle--bottom-right::after {\n width: var(--_grip-mark-thickness);\n height: var(--_grip-mark-thickness);\n}\n\n.resize-handle:hover::after,\n.resize-handle:focus-visible::after {\n opacity: 0.5;\n}\n\n/* Equal specificity to the pair above, so source order is what makes the drag\n the stronger of the two states. */\n.resize-handle[data-dragging]::after {\n opacity: 0.9;\n}\n`;\n", "// The sidebar placement: a docked full-height panel that slides to a rail.\nexport const SIDEBAR_STYLES: string = `\n/* Sidebar: a full-height docked panel that slides open/closed and\n collapses to a slim icon rail (not the floating launcher). Docked right by\n default; data-side=\"left\" docks it left. Overlay by default \u2014 set\n --ag-ui-position: static (and place this element in your own layout) for a\n host-managed push instead. */\n:host([placement=\"sidebar\"]) {\n --_inset: var(--ag-ui-inset, calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right) var(--_viewport-inset-bottom) auto);\n --_width: var(--_drag-width, var(--ag-ui-width, 420px));\n --_height: var(--ag-ui-height, var(--_viewport-height));\n --_max-height: var(--ag-ui-max-height, var(--_viewport-height));\n --_panel-radius: var(--ag-ui-panel-radius, 0);\n transition: width var(--_motion) var(--_ease);\n}\n\n/* Maximized grows the column's width only: the host and the panel pinned\n inside it, which reads its own width. */\n:host([placement=\"sidebar\"][maximized]:not([collapsed])),\n:host([placement=\"sidebar\"][maximized]:not([collapsed])) .chat {\n width: var(--_maximized-width);\n}\n\n/* A side column leaves --ag-ui-min-page-width of the page beside it, whatever\n its width came from: a drag, the token or maximize. Unset, the host keeps its\n own cap (the fallback makes the second term endless) and the panel reads no\n cap at all. Above the phone width only, where the column is the screen. */\n@media (min-width: 601px) {\n :host([placement=\"sidebar\"]),\n :host([placement=\"side\"]) {\n max-width: min(\n var(--_max-width),\n calc(var(--_viewport-width) - var(--_min-page-width-set, calc(-1px * infinity)))\n );\n }\n\n :host([placement=\"sidebar\"]) .chat {\n max-width: calc(var(--_viewport-width) - var(--_min-page-width-set));\n }\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"]) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) auto var(--_viewport-inset-bottom)\n var(--_viewport-inset-left)\n );\n}\n\n/* The docked panel is pinned to the edge it docks against rather than filling\n the host as a flex child. Collapsing shrinks the host to the rail width, and\n a flex child would be squashed to 52px on the way out instead of sliding out\n at full width. */\n/* The panel is taken out of flow so the collapse can slide it out at full\n width; see the note above. That makes the host its containing block, and the\n host is only one by accident: it is position: fixed by default. A host that\n takes the documented route to a pushed layout instead of an overlay sets\n --ag-ui-position: static, and a static element establishes nothing -- so the\n panel resolved against the initial containing block, landed at the document\n origin, and scrolled away with the page. Docked left it pinned to the\n document's left edge rather than the host's.\n\n It looked correct wherever it was first tried, because a full-height column\n at the top of an unscrolled document is exactly where those two answers\n coincide. Containment makes the host a containing block whatever its\n position, so the panel stays in the box the host was given. It is a no-op in\n the default case, which is already positioned. */\n:host([placement=\"sidebar\"]) {\n contain: layout;\n}\n\n:host([placement=\"sidebar\"]) .chat {\n position: absolute;\n inset: 0 0 0 auto;\n width: var(--_width);\n transform-origin: right center;\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"]) .chat {\n inset: 0 auto 0 0;\n transform-origin: left center;\n}\n\n/* Collapsed sidebar: shrink the host to the rail width and slide the panel out\n through the edge it docks against. Higher specificity than the generic\n collapse rules, so it wins regardless of source order. */\n/* The rail is the full height of what the host left, not of the screen. It\n said 100vh and pinned its own bottom, which put it under any chrome the host\n had reserved -- and the icon lives at the top of the rail, so the one control\n that reopens the panel was the first thing to disappear behind a sticky\n header. */\n:host([placement=\"sidebar\"][collapsed]) {\n width: var(--_rail-width);\n height: var(--_viewport-height);\n max-height: var(--_viewport-height);\n pointer-events: auto;\n}\n\n:host([placement=\"sidebar\"][collapsed]) .chat {\n transform: translateX(100%);\n}\n\n:host([placement=\"sidebar\"][data-side=\"left\"][collapsed]) .chat {\n transform: translateX(-100%);\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([placement=\"sidebar\"]),\n :host([placement=\"sidebar\"]) .chat {\n transition: none;\n }\n}\n`;\n", "// The one shape every placement takes on a phone-sized viewport.\nexport const SMALL_VIEWPORT_STYLES: string = `\n/* Small viewports: one shape, reached from whichever placement the host chose.\n\n A phone is not an eighth placement, it is an override that collapses the\n others onto one of them. The host picked a placement for the desktop it was\n designing; a 380x560 panel with a 24px margin is not a smaller version of\n that decision, it is most of the screen with a frame drawn round it.\n\n The breakpoint is a literal because a custom property cannot be read in a\n media query -- which is exactly why there is an opt-out. Everything the block\n sets is a token a host can re-state, but the *trigger* is unreachable, so a\n host whose layout wants a different threshold, or none, sets\n data-small-viewport=\"off\" and keeps its desktop shape at every width. 600px is above every common phone in portrait and below every\n tablet in landscape, and it is a width rather than a pointer test on purpose:\n a touch laptop is coarse-pointered and wide, a narrow desktop window is\n fine-pointered and small, and conflating the two gets both wrong. What the\n pointer decides is which controls make sense, further down.\n\n The size the user dragged is deliberately not read here. The desktop\n placements read it before the host token, and this block restates the sizes\n without it, so a persisted or freshly dragged size cannot change the shape\n of a phone, and a window narrowed after a drag goes full-bleed.\n\n Two placements are left alone. \"page\" is already this shape. \"embedded\" sits\n in a box the host sized and placed, and taking that over would break the app\n shell it was embedded into -- the host is the only party that knows whether\n its column should become the whole screen. */\n@media (max-width: 600px) {\n :host([placement=\"floating\"]:not([data-small-viewport=\"off\"])),\n :host([placement=\"bottom-left\"]:not([data-small-viewport=\"off\"])),\n :host([placement=\"sidebar\"]:not([data-small-viewport=\"off\"])),\n :host([placement=\"side\"]:not([data-small-viewport=\"off\"])),\n :host(:not([placement]):not([data-small-viewport=\"off\"])),\n :host([placement=\"\"]:not([data-small-viewport=\"off\"])) {\n --_inset: var(\n --ag-ui-inset,\n calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)\n calc(var(--_viewport-inset-bottom) + var(--_keyboard-inset))\n var(--_viewport-inset-left)\n );\n --_width: var(--ag-ui-width, var(--_viewport-width));\n --_height: var(--ag-ui-height, var(--_viewport-height));\n --_max-width: var(--ag-ui-max-width, var(--_viewport-width));\n --_max-height: var(--ag-ui-max-height, var(--_viewport-height));\n --_panel-radius: var(--ag-ui-panel-radius, 0);\n --_shadow: var(--ag-ui-shadow, none);\n }\n\n /* Nothing to resize once the panel is the screen, and the grips would sit\n under the thumbs holding the phone. */\n :host([placement=\"floating\"]:not([data-small-viewport=\"off\"])) .resize-handle,\n :host([placement=\"bottom-left\"]:not([data-small-viewport=\"off\"])) .resize-handle,\n :host([placement=\"sidebar\"]:not([data-small-viewport=\"off\"])) .resize-handle,\n :host([placement=\"side\"]:not([data-small-viewport=\"off\"])) .resize-handle,\n :host(:not([placement]):not([data-small-viewport=\"off\"])) .resize-handle,\n :host([placement=\"\"]:not([data-small-viewport=\"off\"])) .resize-handle {\n display: none;\n }\n\n /* The bottom bar shows only while collapsed. With the panel open the panel\n is the screen, its header's minimise control is the way back, and a\n second strip fixed to the bottom edge would sit under the keyboard while\n the composer has focus. Hidden by display, so the bar measures 0 and the\n host's padding goes with it. */\n :host([data-collapsed-to=\"bar\"]:not([collapsed]):not([data-small-viewport=\"off\"])) .dock-bar {\n display: none;\n }\n}\n`;\n", "// The one-line notice a run leaves in the transcript, with its undo.\nexport const RUN_NOTICE_STYLES: string = `\n.run-notice {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n align-self: flex-start;\n max-width: 100%;\n margin: 2px 0;\n padding: 3px 10px;\n border: 1px dashed var(--_border);\n border-radius: 999px;\n background: transparent;\n color: var(--_muted);\n font-size: 0.8em;\n line-height: 1.4;\n}\n\n.run-notice-icon {\n flex: none;\n opacity: 0.75;\n}\n\n/* The one control a notice may carry. Quiet, because it reports something\n already done rather than asking for a decision. */\n.run-notice-undo {\n flex: 0 0 auto;\n margin-inline-start: auto;\n padding: 2px 8px;\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n background: var(--_bg);\n color: var(--_accent);\n font: inherit;\n font-size: 0.9em;\n cursor: pointer;\n}\n\n.run-notice-undo:hover:not(:disabled) {\n background: var(--_hover);\n}\n\n.run-notice-undo:disabled {\n opacity: 0.5;\n cursor: default;\n}\n\n.run-notice-text {\n min-width: 0;\n overflow-wrap: anywhere;\n}\n`;\n", "// The collapsible reasoning region over an assistant turn.\nexport const THOUGHTS_STYLES: string = `\n/* \u2500\u2500 Thoughts region \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A muted, collapsible chain-of-thought at the top of the answer group: open\n while the model reasons, folded once the answer text starts. A block with\n no text is a label alone, with no toggle and no body. */\n.thoughts {\n align-self: stretch;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 12px;\n color: var(--_muted);\n}\n\n.thoughts-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-size: 12px;\n font-weight: 600;\n color: var(--_muted);\n cursor: pointer;\n}\n\n.thoughts-toggle::before {\n content: var(--_disclosure-expanded) \" \";\n}\n\n.thoughts-toggle[aria-expanded=\"false\"]::before {\n content: var(--_disclosure-collapsed) \" \";\n}\n\n/* The label is the whole header while the reasoning has no text, a plain line\n with nothing to open; once there is text it sits inside the toggle, which\n sets the same weight. */\n.thoughts-label {\n align-self: flex-start;\n font-weight: 600;\n}\n\n/* A gentle pulse on the label while reasoning is still streaming. */\n.thoughts[data-streaming] .thoughts-label {\n animation: ag-ui-thoughts-pulse 1.4s ease-in-out infinite;\n}\n\n@keyframes ag-ui-thoughts-pulse {\n 0%, 100% { opacity: 0.55; }\n 50% { opacity: 1; }\n}\n\n.thoughts-body {\n margin: 0;\n padding: 4px 0 4px 10px;\n border-left: 2px solid var(--_border);\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n}\n\n.thoughts-body[hidden] {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .thoughts[data-streaming] .thoughts-label {\n animation: none;\n }\n}\n`;\n", "// The folded tool-step group: one row per run of consecutive tool calls,\n// with the per-call cards one click down.\n\n/** The four per-call card modes, as attribute selectors on the host. */\nconst CARD_MODES = [\n '[data-tool-display=\"inline\"]',\n '[data-tool-display=\"minimal\"]',\n '[data-tool-display=\"compact\"]',\n '[data-tool-display=\"full\"]',\n].join(\", \");\n\n/**\n * The host in grouped mode: any data-tool-display but the four card modes,\n * which is how the element's toolDisplay getter reads it, so an absent or\n * unknown value groups here as it does there. Wrapped in :where so it weighs\n * what a bare :host weighs, and a theme restating a group rule on its own\n * :host selector still wins at equal weight.\n */\nconst GROUPED = `:host(:where(:not(${CARD_MODES})))`;\n\n/** The host in one of the four card modes, where a group drawn earlier is flattened. */\nconst CARDS = `:host(:is(${CARD_MODES}))`;\n\n/**\n * A card inside an opened group, with the host in grouped mode and the given\n * data-tool-group-display. The inner attribute sits inside the same :host()\n * as the grouped test, since the host is featureless outside it, and being\n * grouped-only is what lets an outer card mode flatten the group into its own\n * cards: none of these rules match there. Full is no rule at all, so an absent\n * or unknown inner value draws the full card a group always drew.\n */\nfunction inner(mode: string): string {\n return `:host(:where(:not(${CARD_MODES}))[data-tool-group-display=\"${mode}\"]) .tool-group-list .tool-call`;\n}\n\nexport const TOOL_GROUP_STYLES: string = `\n/* \u2500\u2500 The folded tool-step group \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One quiet row per run of consecutive calls, the cards one click down as\n plain lines rather than boxes. Every rule is scoped to grouped mode, so\n none of it reaches a group drawn earlier once the host moves to a card\n mode. */\n${GROUPED} .tool-group {\n align-self: stretch;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n${GROUPED} .tool-group-head {\n appearance: none;\n align-self: flex-start;\n max-width: 100%;\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin: 0 0 0 -6px;\n padding: 4px 6px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--_muted);\n font: inherit;\n font-size: var(--_text-sm);\n line-height: 1.3;\n text-align: left;\n cursor: pointer;\n}\n\n${GROUPED} .tool-group-head:not(:disabled):hover {\n background: var(--_hover);\n color: var(--_fg);\n}\n\n/* A one-step row with nothing behind it -- a call with no arguments and no\n result yet, or a blank one -- is a label, not a control: the step group\n disables it and drops its expanded state, and this drops the pointer and\n the chevron. Disabled rather than enabled-and-inert, so it takes no focus. */\n${GROUPED} .tool-group-head:disabled {\n cursor: default;\n}\n\n${GROUPED} .tool-group-head:disabled .tool-group-chevron {\n display: none;\n}\n\n${GROUPED} .tool-group-head:focus-visible {\n outline: 2px solid var(--_ring);\n outline-offset: 1px;\n}\n\n${GROUPED} .tool-group-label {\n min-width: 0;\n font-weight: 500;\n color: var(--_ink-2);\n overflow-wrap: anywhere;\n}\n\n${GROUPED} .tool-group-meta {\n min-width: 0;\n color: var(--_muted);\n overflow-wrap: anywhere;\n}\n\n/* Each note opens with a middle dot, which also parts the first note from\n the label. */\n${GROUPED} .tool-group-note::before {\n content: \"\\\\00B7\";\n margin: 0 6px 0 2px;\n}\n\n${GROUPED} .tool-group[data-state=\"error\"] .tool-group-meta {\n color: var(--_danger);\n}\n\n${GROUPED} .tool-group-icon {\n flex: none;\n box-sizing: border-box;\n width: 14px;\n height: 14px;\n background: currentColor;\n mask: var(--_ico-check) center / contain no-repeat;\n color: var(--_success);\n}\n\n${GROUPED} .tool-group[data-state=\"error\"] .tool-group-icon {\n mask-image: var(--_ico-error);\n color: var(--_danger);\n}\n\n${GROUPED} .tool-group[data-state=\"running\"] .tool-group-icon {\n mask: none;\n background: none;\n border: 2px solid var(--_muted);\n border-top-color: transparent;\n border-radius: 50%;\n animation: ag-ui-tool-spin var(--_tool-spin-duration) linear infinite;\n}\n\n/* Waiting on the user: a steady accent dot rather than a spinner, and the\n count in the accent's ink. */\n${GROUPED} .tool-group[data-state=\"waiting\"] .tool-group-icon {\n mask: none;\n border-radius: 50%;\n transform: scale(0.6);\n background: var(--_accent);\n}\n\n${GROUPED} .tool-group[data-state=\"waiting\"] .tool-group-meta {\n color: var(--_accent-ink);\n font-weight: 500;\n}\n\n${GROUPED} .tool-group-chevron {\n flex: none;\n width: 12px;\n height: 12px;\n background: currentColor;\n mask: var(--_ico-chevron) center / contain no-repeat;\n opacity: 0.7;\n transition: transform var(--_motion) var(--_ease);\n}\n\n${GROUPED} .tool-group[data-open=\"true\"] .tool-group-chevron {\n transform: rotate(90deg);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ${GROUPED} .tool-group[data-state=\"running\"] .tool-group-icon {\n animation: none;\n }\n}\n\n${GROUPED} .tool-group-list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin: 2px 0 4px 6px;\n padding-left: 13px;\n border-left: 1px solid var(--_border);\n}\n\n${GROUPED} .tool-group[data-open=\"false\"] .tool-group-list {\n display: none;\n}\n\n/* A card inside the group is one line of the list: icon, name, and its\n Details control at the end, with the arguments and result opening under\n the whole row. Its ink is the second ink in every theme, unless the host\n set the tool token, which then reaches the grouped calls too. */\n${GROUPED} .tool-group .tool-call {\n max-width: 100%;\n align-self: stretch;\n flex-flow: row wrap;\n align-items: center;\n gap: 2px 10px;\n padding: 3px 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--_tool-fg-set, var(--_ink-2));\n font-family: inherit;\n font-size: var(--_text-sm);\n}\n\n${GROUPED} .tool-group .tool-call-head {\n flex: 1 1 auto;\n justify-content: flex-start;\n}\n\n${GROUPED} .tool-group .tool-call-name {\n flex: 0 1 auto;\n font-weight: 450;\n}\n\n/* The repeat ordinal on a step whose label an earlier step has. */\n${GROUPED} .tool-call-repeat {\n color: var(--_muted);\n font-variant-numeric: tabular-nums;\n}\n\n${GROUPED} .tool-group .tool-call-toggle {\n font-family: inherit;\n font-size: var(--_text-xs);\n color: var(--_muted);\n}\n\n${GROUPED} .tool-group .tool-call-body,\n${GROUPED} .tool-group .tool-call-approval,\n${GROUPED} .tool-group .tool-call-subagent {\n flex-basis: 100%;\n}\n\n/* The inner display mode: how an opened group draws its calls. The same\n visibility rules the card modes apply to a flat card, so a call inside the\n group shows the regions the flat card of that mode shows. The flat inline\n mode's chrome rule is left out on purpose: a card in the group has already\n lost its box and is laid out as a row of the list, and that rule's padding\n and gap would undo the row. Selected from the host attribute, so changing it\n restyles groups already on screen. */\n${inner(\"compact\")}[data-expanded=\"false\"] .tool-call-section {\n display: none;\n}\n\n${inner(\"inline\")} .tool-call-section--args {\n display: none;\n}\n\n${inner(\"minimal\")} .tool-call-toggle,\n${inner(\"minimal\")} .tool-call-body {\n display: none;\n}\n\n/* The toggle over nothing, as the card modes refuse it: under every inner mode\n but compact the arguments are not behind the toggle, so a call whose result\n is missing or blank has nothing for it to open. */\n:host(:where(:not(${CARD_MODES})):not([data-tool-group-display=\"compact\"])) .tool-group-list .tool-call:not([data-has-result]) .tool-call-toggle {\n display: none;\n}\n\n/* A call waiting on an approval shows its arguments in every inner mode, as it\n does in every card mode, and for the same reason: the arguments are what\n tell three gated calls of one tool apart. These come after the hides above,\n which they tie with on weight. The arguments region only, never every\n section, since the result region carries the hidden attribute until a\n result exists and a display value here would override it. The arguments\n region carries it too when the call has none, so it is excluded while\n hidden rather than framed empty. */\n${inner(\"minimal\")}[data-status=\"deferred\"] .tool-call-body {\n display: flex;\n}\n\n${inner(\"compact\")}[data-status=\"deferred\"] .tool-call-section--args:not([hidden]),\n${inner(\"inline\")}[data-status=\"deferred\"] .tool-call-section--args:not([hidden]) {\n display: flex;\n}\n\n/* A one-step group already names its call in the row, so the card's own head\n is not drawn inside it. Under the minimal inner mode a card is only its head,\n so the row has nothing to open onto and draws no chevron. Grouped-only, so a\n card mode keeps the head. data-count is rewritten live as a run grows. */\n${GROUPED} .tool-group[data-count=\"1\"] .tool-call-head {\n display: none;\n}\n\n:host(:where(:not(${CARD_MODES}))[data-tool-group-display=\"minimal\"]) .tool-group[data-count=\"1\"] .tool-group-chevron {\n display: none;\n}\n\n/* Grouping is decided as each card is built, so a card mode set afterwards\n finds groups already drawn. It flattens them: the group and its list stop\n generating boxes, the row and the repeat ordinals go, and every card lays\n out as a direct child of the answer, exactly as a card built in that mode\n does. */\n${CARDS} .tool-group,\n${CARDS} .tool-group-list {\n display: contents;\n}\n\n${CARDS} .tool-group-head,\n${CARDS} .tool-call-repeat {\n display: none;\n}\n\n/* Each of these declares its own display, which beats the user-agent rule for\n the hidden attribute, so each needs its own. The host prefix is there for\n weight, not scope: it lifts these over the card-mode rules above that set\n display, which are heavier than a bare class and attribute. */\n:host .tool-group[hidden],\n:host .tool-group-head[hidden],\n:host .tool-group-list[hidden] {\n display: none;\n}\n`;\n", "// Tool steps: the per-call card in each display mode, its status glyphs, and\n// the sub-agent progress a delegating card holds. The skill palette's token\n// mark sits among them only because no rule moved in the split.\nexport const TOOL_STEP_STYLES: string = `\n.tool-call {\n align-self: flex-start;\n max-width: 80%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-size: 12px;\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n padding: 8px 10px;\n border-radius: 8px;\n background: var(--_tool-bg);\n border: 1px solid var(--_border);\n color: var(--_tool-fg);\n}\n\n/* Wraps, because the name is the only flexible child and every badge the row\n gains is taken out of it. An approved call adds a third fixed badge, which in\n a sidebar-width panel left the name 37px and broke it mid-word. Badges drop to\n their own row instead. */\n.tool-call-head {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.tool-call-name {\n /* An auto basis, and a min-width floor rather than zero: the name may shrink,\n but not below something readable, so wrapping moves a badge instead of\n shredding a word. Breaking anywhere still applies to a name that cannot fit\n on a line of its own, which is what keeps a long unbroken tool name inside\n the card. */\n flex: 1 1 auto;\n min-width: 6ch;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n/* Leading status icon. Empty in the DOM \u2014 the glyph/spinner is drawn\n here from the card's data-status, so it stays themeable. */\n.tool-call-icon {\n flex: none;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n font-size: 12px;\n line-height: 1;\n}\n\n/* Pending: a real spinning ring. Speed is tunable; reduced motion stops it. */\n.tool-call[data-status=\"pending\"] .tool-call-icon {\n border: 2px solid var(--_muted);\n border-top-color: transparent;\n border-radius: 50%;\n animation: ag-ui-tool-spin var(--_tool-spin-duration) linear infinite;\n}\n\n@keyframes ag-ui-tool-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Deferred: no spinner, because nothing is spinning. A steady accent dot, since\n the state is waiting-on-you rather than an outcome. */\n.tool-call[data-status=\"deferred\"] .tool-call-icon {\n border-radius: 50%;\n background: var(--_accent);\n}\n\n/* Settled: a themeable glyph coloured by outcome. */\n.tool-call[data-status=\"done\"] .tool-call-icon::before {\n content: var(--_tool-icon-done);\n color: var(--_success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-icon::before {\n content: var(--_tool-icon-error);\n color: var(--_danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-icon::before {\n content: var(--_tool-icon-declined);\n color: var(--_muted);\n}\n\n/* Not finished: muted like declined, since nothing failed, but its own glyph,\n since nobody refused it either. */\n.tool-call[data-status=\"interrupted\"] .tool-call-icon::before {\n content: var(--_tool-icon-interrupted);\n color: var(--_muted);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .tool-call[data-status=\"pending\"] .tool-call-icon {\n animation: none;\n }\n}\n\n/* Inline display mode: the lightest card. Drop the box chrome so the status row\n reads as one line of the answer; the result toggle still expands below it. */\n:host([data-tool-display=\"inline\"]) .tool-call {\n max-width: 100%;\n background: transparent;\n border: none;\n padding: 2px 0;\n gap: 2px;\n}\n\n.tool-call-status {\n flex: none;\n padding: 1px 8px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n background: rgba(127, 127, 127, 0.16);\n color: var(--_muted);\n}\n\n.tool-call[data-status=\"deferred\"] .tool-call-status {\n color: var(--_accent);\n}\n\n.tool-call[data-status=\"done\"] .tool-call-status {\n color: var(--_success);\n}\n\n.tool-call[data-status=\"error\"] .tool-call-status {\n color: var(--_danger);\n}\n\n.tool-call[data-status=\"declined\"] .tool-call-status,\n.tool-call[data-status=\"interrupted\"] .tool-call-status {\n color: var(--_muted);\n}\n\n.tool-call-body {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tool-call-section {\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n/* A call with no arguments drops the region rather than framing an empty\n object, and a settled card drops the result region until it has one -- both\n by setting the hidden property, and an author display beats the user-agent\n rule for that attribute. Without this the region kept laying out: 42px of\n card holding the ARGUMENTS heading over nothing, on every call the agent\n made with no arguments, in the display mode that shows arguments by\n default. */\n.tool-call-section[hidden] {\n display: none;\n}\n\n/* The heading that tells the two payloads apart. Without it the arguments and\n the result were one run of text and a reader had to guess the boundary. */\n.tool-call-section-label {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--_muted);\n}\n\n.skill-item-token {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n font-size: 0.92em;\n color: var(--_accent);\n margin-right: 6px;\n}\n\n/* The lasting record of a human decision on a gated call \u2014 without it an\n approved call looks exactly like one that was never gated. */\n.tool-call-decision {\n flex: none;\n font-size: 11px;\n font-style: italic;\n color: var(--_muted);\n}\n\n.tool-call-args,\n.tool-call-result {\n margin: 0;\n padding: 6px 8px;\n max-height: 160px;\n overflow: auto;\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: 6px;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--_fg);\n}\n\n/* A region a host formatter took over, marked by the card. Preformatted\n whitespace is what makes the built-in block read as written, and it is the one\n thing a host cannot want: a table inherits it as mangled cell spacing, and a\n sentence as line breaks nobody typed.\n\n Whitespace only. The card's own face, frame, padding and scroll cap stay,\n because the card is one visual object -- the head row and the status pill are\n monospaced too -- and a region that dropped the family would be the only part\n of it wearing a different one. A host that wants that restyles the\n tool-card-result part, which does not need the formatter at all. */\n.tool-call-args[data-formatted],\n.tool-call-result[data-formatted] {\n white-space: normal;\n}\n\n/* Display modes are pure visibility over one DOM shape, selected from the host\n attribute rather than a value stamped on the card at build time, so flipping\n data-tool-display re-styles cards already on screen. See ToolCallCard.\n\n Default (no attribute) is the full mode: arguments always visible, result\n behind the toggle. */\n.tool-call[data-expanded=\"false\"] .tool-call-section--result {\n display: none;\n}\n\n/* Compact: one toggle over both regions, so a settled card is a single line\n until asked. */\n:host([data-tool-display=\"compact\"]) .tool-call[data-expanded=\"false\"] .tool-call-section {\n display: none;\n}\n\n/* Inline: the result only; the call's arguments are noise at this density. */\n:host([data-tool-display=\"inline\"]) .tool-call .tool-call-section--args {\n display: none;\n}\n\n/* Minimal: the status row and nothing else, so there is no toggle to press. */\n:host([data-tool-display=\"minimal\"]) .tool-call .tool-call-toggle,\n:host([data-tool-display=\"minimal\"]) .tool-call .tool-call-body {\n display: none;\n}\n\n/* A pending card has no result yet, and in the modes where the arguments are\n hidden too there is nothing behind the toggle. Hide the control rather than\n offer one that expands onto nothing. A deferred card is the same, and its\n arguments are shown unconditionally by the rules below. */\n.tool-call[data-status=\"pending\"] .tool-call-toggle,\n.tool-call[data-status=\"deferred\"] .tool-call-toggle,\n:host([data-tool-display=\"inline\"]) .tool-call[data-status=\"pending\"] .tool-call-toggle {\n display: none;\n}\n\n/* A settled card offers the toggle only over something. The card marks\n non-empty arguments with data-has-args and a non-blank result with\n data-has-result, and a call with neither has nothing behind it in any\n mode. Full shows the arguments without the toggle and inline never shows\n them, so there only a result is worth opening; compact folds both. A\n step group restates the full and inline half for the calls inside it. */\n.tool-call:not([data-has-args]):not([data-has-result]) .tool-call-toggle,\n:host([data-tool-display=\"full\"]) .tool-call:not([data-has-result]) .tool-call-toggle,\n:host([data-tool-display=\"inline\"]) .tool-call:not([data-has-result]) .tool-call-toggle {\n display: none;\n}\n\n/* The approval prompt for a gated call, rendered inside that call's own card.\n Empty on every card nobody is being asked about, so it collapses instead of\n adding a gap to each one. */\n.tool-call-approval:empty {\n display: none;\n}\n\n.tool-call-approval {\n margin-top: 8px;\n}\n\n/* A card that is asking a question shows what it is asking about, in every\n display mode. Three gated calls of one tool ask the same words, so the\n arguments are the only thing telling them apart, and a density setting must\n not be able to hide the answer to \"which one is this\". */\n:host([data-tool-display=\"minimal\"]) .tool-call[data-status=\"deferred\"] .tool-call-body {\n display: flex;\n}\n\n/* The arguments region only, never every section: the result region carries the\n hidden attribute until a result exists, and a display value here overrides it,\n framing an empty RESULT heading under the question. The arguments region is\n hidden too when the call has none, and is left alone then, or it would frame\n an empty ARGUMENTS heading. */\n:host([data-tool-display=\"compact\"]) .tool-call[data-status=\"deferred\"] .tool-call-section--args:not([hidden]),\n:host([data-tool-display=\"inline\"]) .tool-call[data-status=\"deferred\"] .tool-call-section--args:not([hidden]) {\n display: flex;\n}\n\n/* A delegated sub-agent's progress, inside the card that delegated. Empty on\n every card that delegated nothing, so it collapses rather than adding a gap\n to each one -- the same shape the approval slot uses. */\n.tool-call-subagent:empty {\n display: none;\n}\n\n.tool-call-subagent {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.subagent {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n\n/* The collapsed row is the status and the expander at once, which is what keeps\n a ten-step child one row until somebody opens it. Full width and left-aligned,\n because it is a line of the card rather than a button on it. */\n.subagent-row {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n box-sizing: border-box;\n padding: 2px 0;\n border: none;\n background: none;\n font: inherit;\n text-align: left;\n color: var(--_muted);\n cursor: pointer;\n}\n\n/* Nothing behind the row yet -- a delegation that failed before calling\n anything. Drop the affordances rather than offer a control that expands onto\n an empty region, which is the refusal the card's own toggle already makes. */\n.subagent-row:disabled {\n cursor: default;\n}\n\n.subagent-row::after {\n content: var(--_disclosure-collapsed);\n flex: none;\n margin-left: auto;\n color: var(--_accent);\n}\n\n.subagent-row[aria-expanded=\"true\"]::after {\n content: var(--_disclosure-expanded);\n}\n\n.subagent-row:disabled::after {\n display: none;\n}\n\n/* Empty in the DOM; the glyph is drawn here from the panel's data-phase, so a\n host re-themes it through the same tool-icon custom properties the card uses. */\n.subagent-icon {\n flex: none;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 10px;\n height: 10px;\n font-size: 10px;\n line-height: 1;\n}\n\n/* Anything that is not a terminal phase is the child still working. Selected by\n what it is not, so a phase this client has not heard of still spins rather\n than rendering as a blank. */\n.subagent[data-phase]:not([data-phase=\"finished\"]):not([data-phase=\"failed\"]) .subagent-icon {\n border: 2px solid var(--_muted);\n border-top-color: transparent;\n border-radius: 50%;\n animation: ag-ui-tool-spin var(--_tool-spin-duration) linear infinite;\n}\n\n.subagent[data-phase=\"finished\"] .subagent-icon::before {\n content: var(--_tool-icon-done);\n color: var(--_success);\n}\n\n.subagent[data-phase=\"failed\"] .subagent-icon::before {\n content: var(--_tool-icon-error);\n color: var(--_danger);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .subagent .subagent-icon {\n animation: none;\n }\n}\n\n/* The server's own pre-rendered line. Shrinks and wraps rather than pushing the\n chevron out of the card, which is what a fixed-width sibling in a flex row\n does to a panel at sidebar width. */\n.subagent-status {\n flex: 1 1 auto;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n/* The child's own calls. Indented and ruled, so the nesting is visible without\n a second card frame around it. */\n.subagent-steps {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-left: 4px;\n padding-left: 10px;\n border-left: 1px solid var(--_border);\n}\n\n.subagent-steps[hidden] {\n display: none;\n}\n\n.subagent-step {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n color: var(--_muted);\n}\n\n.subagent-step-icon {\n flex: none;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 8px;\n height: 8px;\n font-size: 9px;\n line-height: 1;\n}\n\n/* No outcome yet: the wire says null while the call is in flight, and the\n absence of the attribute is how that arrives here. A hollow ring, not a\n spinner -- several can be on screen at once and the row above already spins. */\n.subagent-step:not([data-ok]) .subagent-step-icon {\n border: 1px solid var(--_muted);\n border-radius: 50%;\n}\n\n.subagent-step[data-ok=\"true\"] .subagent-step-icon::before {\n content: var(--_tool-icon-done);\n color: var(--_success);\n}\n\n.subagent-step[data-ok=\"false\"] .subagent-step-icon::before {\n content: var(--_tool-icon-error);\n color: var(--_danger);\n}\n\n.subagent-step-name {\n flex: 1 1 auto;\n min-width: 0;\n overflow-wrap: anywhere;\n}\n\n.tool-call-toggle {\n align-self: flex-start;\n border: none;\n padding: 0;\n background: none;\n font: inherit;\n font-weight: 600;\n color: var(--_accent);\n cursor: pointer;\n}\n\n.tool-call-toggle::before {\n content: var(--_disclosure-collapsed) \" \";\n}\n\n.tool-call-toggle[aria-expanded=\"true\"]::before {\n content: var(--_disclosure-expanded) \" \";\n}\n`;\n", "// The panel itself and its header: title, icon holder and header controls.\nexport const FRAME_STYLES: string = `\n.chat {\n position: relative;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: var(--_panel-radius);\n box-shadow: var(--_shadow);\n overflow: hidden;\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--_border);\n background: var(--_header-bg);\n color: var(--_header-fg);\n}\n\n/* The header is the panel's title bar: on the placements that let the widget\n be moved it drags the whole thing, matching the launcher's own drag. The\n selector lists those placements rather than asking JS to stamp an attribute,\n because a cursor that appears one frame late reads as a control that only\n sometimes exists. touch-action keeps a finger drag here moving the panel\n instead of scrolling the page behind it. */\n:host(:not([placement])) .header,\n:host([placement=\"\"]) .header,\n:host([placement=\"floating\"]) .header,\n:host([placement=\"bottom-left\"]) .header {\n cursor: move;\n touch-action: none;\n}\n\n/* A host that turned the drag off keeps a header that says so. */\n:host([data-launcher-drag=\"false\"]) .header {\n cursor: auto;\n touch-action: auto;\n}\n\n/* A panel that is the screen has nowhere to go, so its header refuses the drag\n and must not offer it. No selector can see that a host has sized the panel to\n the window, so the placement stamps this from the measurement that refuses the\n drag. :host is carried for the specificity, not the scope, as below. Before the\n dragging rule, so a drag the header did take keeps its grabbing cursor. */\n:host .header[data-fills-screen] {\n cursor: auto;\n}\n\n/* :host is carried for the specificity, not the scope: the placement rules\n above are a host selector plus a class plus an attribute, and a bare\n .header[data-dragging] loses to them -- silently, because the drag still\n works and only the cursor is wrong. */\n:host .header[data-dragging] {\n cursor: grabbing;\n}\n\n/* The cursor inherits, so a control a host slots into the header would show\n the drag cursor over something the drag deliberately ignores. Named to\n match the controls panel_drag steps aside for. */\n.header ::slotted(:is(button, a, input, select, textarea)) {\n cursor: pointer;\n}\n\n.header-title {\n flex: 1;\n min-width: 0;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Header / launcher icon holder: a slot, with a data-icon-url <img>\n fallback, sized via --ag-ui-icon-size. */\n.icon-holder {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: var(--_icon-size);\n height: var(--_icon-size);\n line-height: 1;\n}\n\n.icon-img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n border-radius: var(--_icon-radius);\n}\n\n.header-controls {\n display: flex;\n gap: var(--_header-gap);\n flex: none;\n}\n\n/* Under every theme: once the host sets the header text, the header behind the\n buttons is the host's colour, so their rest opacity goes. The frame's 0.85\n lets the header through the glyph, which took white on a mid-blue header from\n 5.1:1 to 4.2:1. With the header text set, the opacity below reads a colour,\n which no opacity can be, so it is invalid at computed-value time and falls to\n the initial 1; unset, it reads the fallback. The glyph is each theme's own\n business: this inherits the header text, and a theme that draws the buttons\n in another ink reads the same switch to yield. */\n.header-btn {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: var(--_header-btn-size);\n height: var(--_header-btn-size);\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1;\n padding: 0;\n border-radius: 6px;\n cursor: pointer;\n opacity: var(--_header-fg-set, 0.85);\n}\n\n/* The square is the host's own when it set one; otherwise it is mixed from the\n header text when the host set that, so it reads on any header the host\n painted; otherwise it is the theme's own. See the alias in the token defaults. */\n.header-btn:hover {\n opacity: 1;\n background: var(--_header-btn-hover);\n}\n\n/* Every built-in header mark is a drawn glyph at the composer's size; the theme\n toggle's holder takes that size too, so its moon matches its neighbours. */\n.header-btn .glyph,\n.header-btn .icon-holder {\n width: var(--_glyph-size);\n height: var(--_glyph-size);\n}\n`;\n", "// The density presets: token overrides only. The themes live in ui/themes.\nexport const THEME_STYLES: string = `\n/* \u2500\u2500 Density \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host([density=\"compact\"]) {\n --_font-size: var(--ag-ui-font-size, 13px);\n --_space: var(--ag-ui-space, 6px);\n --_pad: var(--ag-ui-pad, 10px);\n --_msg-pad: var(--ag-ui-msg-pad, 5px 9px);\n --_msg-radius: var(--ag-ui-msg-radius, 10px);\n}\n`;\n", "// Every public --ag-ui-* token read into its private --_* alias on :host.\n// This is where the token defaults are declared; see the block comment below.\nexport const TOKEN_STYLES: string = `\n/* \u2500\u2500 Token defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Every public --ag-ui-* token is read here into a private --_* alias, and\n only the alias is used by the rules below.\n\n The indirection is what makes ancestor theming work. Declaring the public\n name on :host would set it on the host element, and a value on an element\n always beats one inherited from an ancestor, so tokens put on a wrapper\n would have no effect. Reading the public name with the default as a var()\n fallback leaves it undeclared on the element, so an ancestor's value\n inherits normally while one aimed at the element still wins.\n\n Two invariants hold this together:\n 1. No rule outside a :host block may reference a public name\n directly. A public name read outside these blocks resolves to nothing and\n silently drops its declaration rather than erroring, so the miss shows up\n as a missing colour, not a failure.\n 2. Every --_* alias in use is declared here. Aliases inherit like any custom\n property, so an undeclared one would pick up a same-named property from\n the host page; declaring it on :host shields the shadow tree from that. */\n:host {\n /* Colors. The default theme, Quiet: three seeds, and every other shade\n mixed from them in oklch, so a host that sets only --ag-ui-accent (or\n only the background and text) gets a whole widget rethemed. The seeds use\n light-dark, so the scheme word on the theme attribute picks the half;\n see scheme_styles in the themes directory. Every derived shade still\n reads its own public token first, so each stays an override point. */\n color-scheme: light;\n --_bg: var(--ag-ui-bg, light-dark(#ffffff, #161618));\n --_fg: var(--ag-ui-fg, light-dark(#1b1b1d, #ececee));\n --_accent: var(--ag-ui-accent, light-dark(#232326, #f0f0f2));\n --_ink-2: var(--ag-ui-ink-2, color-mix(in oklch, var(--_fg) 78%, var(--_bg)));\n --_ink-3: var(--ag-ui-ink-3, color-mix(in oklch, var(--_fg) 64%, var(--_bg)));\n --_line: var(--ag-ui-line, color-mix(in oklch, var(--_fg) 11%, var(--_bg)));\n --_line-strong: var(--ag-ui-line-strong, color-mix(in oklch, var(--_fg) 20%, var(--_bg)));\n --_wash: var(--ag-ui-wash, color-mix(in oklch, var(--_fg) 4.5%, var(--_bg)));\n --_accent-ink: var(--ag-ui-accent-ink, color-mix(in oklch, var(--_accent) 82%, var(--_fg)));\n /* The focus ring is drawn on the panel, so it has to hold 3:1 against\n --_bg whatever accent a host brings (WCAG 2.4.13). Two parts accent to\n three parts ink does that at the worst case, an accent at the far end\n from the ink (white on a light panel, black on a dark one): the ink\n alone sits far above 3:1, and three fifths of it keeps the mix there\n while the hue still reads as the accent. Half and half fell to 2.3:1\n for black on the code theme. The accent over transparent, as before,\n measured only the accent, and a light host accent fell to 1.6:1. */\n --_ring: var(--ag-ui-ring, color-mix(in oklch, var(--_accent) 40%, var(--_fg)));\n /* The user's turn is the accent at a whisper. With Quiet's graphite accent\n that is a neutral wash; once a host sets a brand accent it becomes a tint\n of the brand, which is the one thing Soft does that Quiet keeps. */\n --_user-bg: var(--ag-ui-user-bg, color-mix(in oklch, var(--_accent) 12%, var(--_bg)));\n --_user-fg: var(--ag-ui-user-fg, var(--_fg));\n --_assistant-bg: var(--ag-ui-assistant-bg, transparent);\n --_hover: var(--ag-ui-hover, color-mix(in oklch, var(--_fg) 6%, var(--_bg)));\n --_input-bg: var(--ag-ui-input-bg, var(--_bg));\n --_tool-bg: var(--ag-ui-tool-bg, transparent);\n --_tool-fg: var(--ag-ui-tool-fg, var(--_ink-2));\n --_header-bg: var(--ag-ui-header-bg, var(--_bg));\n --_header-fg: var(--ag-ui-header-fg, var(--_fg));\n /* Switches: a public token read with no fallback, named for it with -set.\n With the token unset the switch computes to the guaranteed-invalid value,\n so a rule that reads it with a fallback gets the fallback; that is how a\n rule tells a token the host set from the theme's default for it. Every\n theme's header buttons follow the header text only once a host sets it,\n and a step group's calls follow the tool token only once a host sets it\n (classic defaults --_tool-fg to the accent, which a group never drew). */\n --_header-fg-set: var(--ag-ui-header-fg);\n --_tool-fg-set: var(--ag-ui-tool-fg);\n /* The header buttons' hover square, by default, once the header text is\n set. Here it is the text at about a fifth, which every browser can mix;\n where relative colour syntax is supported (see the block at the end) it\n is the text's opposite instead. It reads the switch, so it is unset with\n it, and the square below falls to the theme's own: the panel's hover shade\n here, restated by each theme that draws another, so one rule in the frame\n paints them all. */\n --_header-btn-hover-auto: color-mix(in srgb, var(--_header-fg-set) 18%, transparent);\n --_header-btn-hover: var(--ag-ui-header-btn-hover, var(--_header-btn-hover-auto, var(--_hover)));\n --_border: var(--ag-ui-border, var(--_line));\n --_radius: var(--ag-ui-radius, 12px);\n /* The panel's own frame, which is the one corner a placement can put against\n the edge of the viewport. The placements that do (page, sidebar, side, full,\n and all but embedded on a small viewport) square this and leave --_radius alone, so\n the answer well and the controls inside the panel stay as round as the\n theme says: none of them meets that edge. */\n /* What a theme sets for the frame; the effective value below is what a\n placement squares, so the two never fight over one property. A host's\n --ag-ui-radius still rounds the frame, as it did before themes gave the\n frame a radius of its own; only the theme's own default differs. */\n --_frame-radius: var(--ag-ui-frame-radius, var(--ag-ui-radius, 14px));\n --_panel-radius: var(--ag-ui-panel-radius, var(--_frame-radius));\n\n /* Body text and raised chrome, read only by the code-block copy button.\n The defaults restate what it inherits, so a host that sets neither sees\n no repaint \u2014 see the note on .code-copy. */\n --_text: var(--ag-ui-text, var(--_fg));\n --_surface: var(--ag-ui-surface, transparent);\n\n /* Message action row: the control box and the mark inside it. The box has a\n floor of 24px so it stays a reliable target at every density. */\n --_action-size: var(--ag-ui-action-size, 28px);\n /* The header's own controls. Sized rather than left to their contents: a row\n of buttons each as wide as the glyph inside it comes out uneven, and uneven\n buttons two pixels apart read as one smudge rather than five controls. */\n --_header-btn-size: var(--ag-ui-header-btn-size, 30px);\n --_header-gap: var(--ag-ui-header-gap, 4px);\n --_action-icon-size: var(--ag-ui-action-icon-size, 15px);\n --_tooltip-bg: var(--ag-ui-tooltip-bg, var(--_fg));\n --_tooltip-fg: var(--ag-ui-tooltip-fg, var(--_bg));\n\n /* Text and marks drawn on top of the accent and danger fills. Separate\n tokens because they are not free: a host that themes the accent to a pale\n colour has white-on-pale with no way to correct it, which is the one\n theming change that makes a control unreadable rather than merely off. */\n /* Picked from the accent's own luminance where relative colour syntax is\n supported (the first block after this rule). Without it, this value: the\n scheme's colour, which is the right side for each newer theme's own\n accent in both schemes. Classic and code take white instead, in the\n second block. */\n --_on-accent: var(--ag-ui-on-accent, light-dark(#ffffff, #111111));\n --_on-danger: var(--ag-ui-on-danger, #ffffff);\n\n /* Resize grips: the corner squares and the edge strips between them. Wide\n enough to hit without being wide enough to swallow a click on the content\n underneath, and adjustable for a host with a coarser pointer. */\n --_grip-corner: var(--ag-ui-grip-corner, 14px);\n --_grip-edge: var(--ag-ui-grip-edge, 6px);\n --_grip-edge-docked: var(--ag-ui-grip-edge-docked, 8px);\n /* The mark drawn inside a grip, as opposed to the area it answers to. */\n --_grip-mark-length: var(--ag-ui-grip-mark-length, 28px);\n --_grip-mark-thickness: var(--ag-ui-grip-mark-thickness, 3px);\n\n /* Status accents for tool-call cards. */\n --_success: var(--ag-ui-success, light-dark(#15803d, #4ade80));\n --_danger: var(--ag-ui-danger, light-dark(#b91c1c, #f87171));\n --_muted: var(--ag-ui-muted, var(--_ink-3));\n\n /* Tool-call status icon glyphs (override to re-theme) + spinner speed.\n The pending state is the animated ring; the settled states use these. */\n --_tool-icon-done: var(--ag-ui-tool-icon-done, \"\u2713\");\n --_tool-icon-error: var(--ag-ui-tool-icon-error, \"\u2715\");\n --_tool-icon-declined: var(--ag-ui-tool-icon-declined, \"\u2298\");\n --_tool-icon-interrupted: var(--ag-ui-tool-icon-interrupted, \"\u25CC\");\n\n /* Disclosure marks on every expandable row. Tokenised for the same reason\n the status icons above are: a host re-theming one set and not the other\n ends up with two vocabularies in one transcript. */\n --_disclosure-collapsed: var(--ag-ui-disclosure-collapsed, \"\u25B8\");\n --_disclosure-expanded: var(--ag-ui-disclosure-expanded, \"\u25BE\");\n --_tool-spin-duration: var(--ag-ui-tool-spin-duration, 0.7s);\n\n /* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */\n --_well-bg: var(--ag-ui-well-bg, transparent);\n --_well-border: var(--ag-ui-well-border, var(--_border));\n --_well-radius: var(--ag-ui-well-radius, var(--_radius));\n\n /* Surface \u2014 set --ag-ui-shadow: none for a flush, embedded panel. */\n --_frame-shadow: var(--ag-ui-frame-shadow, 0 1px 2px light-dark(rgb(0 0 0 / 0.05), rgb(255 255 255 / 0.04)), 0 12px 32px -16px light-dark(rgb(0 0 0 / 0.22), rgb(0 0 0 / 0.7)));\n --_shadow: var(--ag-ui-shadow, var(--_frame-shadow));\n --_font: var(--ag-ui-font, Inter, ui-sans-serif, system-ui, sans-serif);\n --_serif: var(--ag-ui-serif, Charter, \"Bitstream Charter\", \"Iowan Old Style\", Georgia, serif);\n --_font-size: var(--ag-ui-font-size, var(--_text-md));\n /* The type scale. */\n --_text-xs: var(--ag-ui-text-xs, 11.5px);\n --_text-sm: var(--ag-ui-text-sm, 12.5px);\n --_text-md: var(--ag-ui-text-md, 14px);\n --_text-lg: var(--ag-ui-text-lg, 16px);\n --_leading: var(--ag-ui-leading, 1.55);\n --_code-font: var(--ag-ui-code-font, ui-monospace, \"SF Mono\", Menlo, monospace);\n\n /* Header / launcher icon box. */\n --_icon-size: var(--ag-ui-icon-size, 22px);\n --_icon-radius: var(--ag-ui-icon-radius, 4px);\n\n /* Composer \u2014 one bordered surface holding the field and its tool row. */\n --_composer-radius: var(--ag-ui-composer-radius, 12px);\n --_composer-max-height: var(--ag-ui-composer-max-height, 40vh);\n --_tool-btn-size: var(--ag-ui-tool-btn-size, 30px);\n --_send-size: var(--ag-ui-send-size, 30px);\n --_glyph-size: var(--ag-ui-glyph-size, 18px);\n --_glyph-stroke: var(--ag-ui-glyph-stroke, 1.75);\n\n /* How wide a chart is allowed to get. A cap rather than a width: below it\n the chart fills its column, and above it a wider panel is just a wider\n panel. */\n --_chart-max-width: var(--ag-ui-chart-max-width, 480px);\n /* Chart series. Quiet draws in ink and keeps hues for the series past two. */\n --_chart-1: var(--ag-ui-chart-1, var(--_fg));\n --_chart-2: var(--ag-ui-chart-2, color-mix(in oklch, var(--_fg) 32%, var(--_bg)));\n --_chart-3: var(--ag-ui-chart-3, #e0803c);\n --_chart-4: var(--ag-ui-chart-4, #b563d8);\n --_chart-5: var(--ag-ui-chart-5, #d84f6e);\n --_chart-6: var(--ag-ui-chart-6, #3ba7c4);\n\n /* Unread badge on the launcher. */\n --_badge-bg: var(--ag-ui-badge-bg, var(--_danger));\n --_badge-fg: var(--ag-ui-badge-fg, #ffffff);\n --_badge-size: var(--ag-ui-badge-size, 18px);\n --_badge-font-size: var(--ag-ui-badge-font-size, 11px);\n\n /* The floating launcher a collapsed widget shrinks to. */\n --_launcher-size: var(--ag-ui-launcher-size, 48px);\n --_launcher-bg: var(--ag-ui-launcher-bg, var(--_bg));\n --_launcher-fg: var(--ag-ui-launcher-fg, var(--_fg));\n --_launcher-radius: var(--ag-ui-launcher-radius, 14px);\n --_launcher-icon-size: var(--ag-ui-launcher-icon-size, 22px);\n --_launcher-inset: var(--ag-ui-launcher-inset, auto 0 0 auto);\n\n /* Motion. One duration and two curves drive every collapse, expand and\n slide-over, so the widget accelerates and settles as one thing. The\n default curve decelerates into place; the pop curve overshoots slightly,\n for something arriving. */\n --_motion: var(--ag-ui-motion, 0.28s);\n --_ease: var(--ag-ui-ease, cubic-bezier(0.32, 0.72, 0, 1));\n --_ease-pop: var(--ag-ui-ease-pop, cubic-bezier(0.34, 1.36, 0.64, 1));\n\n /* Spacing \u2014 the density preset overrides these. */\n --_space: var(--ag-ui-space, 10px);\n --_pad: var(--ag-ui-pad, 16px);\n --_msg-pad: var(--ag-ui-msg-pad, 8px 12px);\n --_msg-radius: var(--ag-ui-msg-radius, 12px);\n\n /* Edges of the viewport the host has already spent, and that a fixed\n placement must therefore stay out of: a sticky nav bar, a docked toolbar,\n a device's safe area. Four longhands rather than one shorthand because a\n custom property is a token stream and CSS cannot index one -- the height\n arithmetic below needs the vertical pair on its own.\n\n Every fixed placement derives from these, and the heights subtract them in\n one place. A host that reserved its chrome by restating --ag-ui-inset per\n placement had to keep --ag-ui-height in step by hand, and forgetting it\n overflowed the panel past the bottom of the screen with nothing to say so.\n\n These take env(safe-area-inset-*) verbatim, which is what a full-bleed\n placement wants on a device with a notch. */\n --_viewport-inset-top: var(--ag-ui-viewport-inset-top, 0px);\n --_viewport-inset-right: var(--ag-ui-viewport-inset-right, 0px);\n --_viewport-inset-bottom: var(--ag-ui-viewport-inset-bottom, 0px);\n --_viewport-inset-left: var(--ag-ui-viewport-inset-left, 0px);\n /* What is left of the viewport once the host's chrome is taken out, on both\n axes, so a placement never composes this itself and no host can subtract\n an edge from the position and forget it in the height.\n\n Settable in their own right, and that is not only convention: an on-screen\n keyboard changes no viewport-percentage length -- not vh, not dvh, not svh\n -- so a full-bleed panel on a phone has to be told the height rather than\n deriving it. The value to publish there is the visual viewport's. */\n --_viewport-height: var(\n --ag-ui-viewport-height,\n calc(\n min(var(--_visual-viewport-inset-top) + var(--_visual-viewport-height), 100dvh - var(--_viewport-inset-bottom)) -\n var(--_viewport-inset-top) - var(--_keyboard-inset-top)\n )\n );\n /* That default is the host's box cut to the part of the screen the user can\n see: from the top the panel starts at, the host's reserved top moved down\n by the keyboard inset below, to whichever is further up, the bottom of the\n visible area or the host's reserved bottom. Where nothing has measured, the\n visible area is the layout viewport with no pan, and this is the host's\n box exactly.\n\n Cut rather than replaced. A measured height used as the whole answer kept\n a bar the host reserved at the top in the position and out of the height,\n so the panel ran that far past the bottom of the visible area, with its\n composer behind the keyboard. */\n /* The measured height of the part of the screen the user can actually see,\n written by the element from the visual viewport and falling back to the\n layout viewport where nothing has measured yet.\n\n This is the on-screen keyboard, and it needs measuring because no CSS\n length describes it: an on-screen keyboard has no effect on any\n viewport-percentage unit, so 100vh, 100dvh and 100svh are all the same\n number with the keyboard up as without it. A full-bleed panel sized from\n any of them puts its composer behind the keyboard the user is typing into.\n\n Separate from the token above so a host that states the usable height\n outright still wins: the element writes this one inline, and an inline\n value would otherwise outrank the host's own rule.\n\n The fallback is dvh rather than vh because the browser's own bars do move\n it, where a keyboard does not. iOS Safari resolves vh to the viewport with\n its bars collapsed, so on a page that does not scroll them away a panel\n sized from it ran under the address bar by the bars' height -- 40px on\n the phone measured -- with a docked composer underneath. dvh is the\n viewport with the bars as they are. */\n --_visual-viewport-height: var(--ag-ui-visual-viewport-height, 100dvh);\n /* How much of the layout viewport is hidden below the visible one, measured\n and written by the element alongside the height above.\n\n A shorter panel is not enough on its own for anything anchored to the\n bottom. A floating widget is positioned against the layout viewport, so\n with a keyboard up its bottom edge -- and the launcher that lives at that\n corner -- sits behind the keyboard however tall the panel is. This is what\n lifts it clear. */\n /* Two tokens, for the same reason the height above has two: the element\n writes the measurement inline, and a host that states its own value needs\n a knob that outranks that write rather than one the next write replaces.\n A host wanting no keyboard lift at all sets --ag-ui-keyboard-inset: 0px. */\n --_keyboard-inset: var(--ag-ui-keyboard-inset, var(--_visual-viewport-inset-bottom));\n --_visual-viewport-inset-bottom: var(--ag-ui-visual-viewport-inset-bottom, 0px);\n /* How far a panel anchored at the top moves down for a keyboard, below the\n top the host reserved. With the same two-token shape as the lift above;\n 0px keeps the panel at the host's top.\n\n To show the field being typed into, a browser pans the visible area down\n the layout viewport, and a fixed element stays against the layout top, so\n a panel that did not move showed only its lower part, from the pan down,\n with its header off the screen and an empty band under it. It moves by\n what the pan goes past the host's reserved top, not by the whole pan: the\n pan scrolls a bar reserved there away with the rest of the page rather\n than pushing it down, and adding the two put the panel a whole bar below\n the visible area. A corner panel anchored at the bottom does not use this,\n because the band below already accounts for the pan. */\n --_keyboard-inset-top: var(--ag-ui-keyboard-inset-top, max(0px, var(--_visual-viewport-inset-top) - var(--_viewport-inset-top)));\n /* How much of the layout viewport is hidden above the visible one: how far\n the browser panned. Measured and written by the element with the two\n above. */\n --_visual-viewport-inset-top: var(--ag-ui-visual-viewport-inset-top, 0px);\n --_viewport-width: var(\n --ag-ui-viewport-width,\n calc(100vw - var(--_viewport-inset-left) - var(--_viewport-inset-right))\n );\n\n /* Layout \u2014 override from outside to dock the widget anywhere.\n Set --ag-ui-position: static (and place this element in your own\n grid/flex layout) to embed it in the page flow instead of floating. */\n --_position: var(--ag-ui-position, fixed);\n --_z-index: var(--ag-ui-z-index, 2147483000);\n /* A size the user dragged, written inline on the host by the placement\n code, and read ahead of the host's tokens so the drag wins. There is no\n public token behind it; it is declared initial here only so a chat that\n was never dragged does not inherit one, from a dragged chat it is\n slotted into or from any page rule naming it. The inline value still\n beats this default. */\n --_drag-width: initial;\n --_drag-height: initial;\n /* Where a docked panel stands, written inline the same way by the placement\n code: the bottom bar's height, or the host anchor's distance from the\n bottom and right edges, or from the top to its bottom for a panel opening\n below it. Read only by the dock rules, each with a 0px fallback; declared\n initial so it never inherits any of them. */\n --_dock-bottom: initial;\n --_dock-right: initial;\n --_dock-top: initial;\n /* Where the conversation list stands beside the host's button under\n collapse-to=\"none\", written inline by the element from the button's box.\n Declared initial for the same reason. */\n --_threads-top: initial;\n --_threads-bottom: initial;\n --_threads-right: initial;\n --_threads-room: initial;\n /* The gap between a panel and the host's own button it rises from under\n collapse-to=\"none\". The button usually sits inside a taller toolbar, so a\n host sets this to the button's distance from the toolbar's top plus the\n clearance it wants, and the panel stands clear of the toolbar. */\n --_anchor-gap: var(--ag-ui-anchor-gap, 8px);\n --_width: var(--_drag-width, var(--ag-ui-width, 380px));\n --_height: var(--_drag-height, var(--ag-ui-height, 560px));\n /* The gutter a resting floating panel keeps between itself and the edge of\n the box the host left free. One number, because the inset below spends it\n and the cap beneath has to know it was spent. */\n --_edge-gutter: var(--ag-ui-edge-gutter, 24px);\n --_inset: var(\n --ag-ui-inset,\n auto calc(var(--_edge-gutter) + var(--_viewport-inset-right))\n calc(var(--_edge-gutter) + var(--_viewport-inset-bottom) + var(--_keyboard-inset)) auto\n );\n /* The cap is what the host left free, less the *one* gutter the inset above\n spends on the anchored edge -- not two, and not none.\n\n Two was the first answer and it was felt on one axis only. The arithmetic\n says why: the default panel is 560 tall against a cap of the viewport\n minus 48, which on an 800px screen with a header reserved is 72px of\n headroom, so the height reaches its cap almost immediately; the default\n width is 380 against a cap near 1230, which is 850px nothing ever reaches.\n Once the size is capped a grip cannot grow the panel, so a pull on the\n anchored edge is written as position instead and the panel travels, and a\n pull on the free edge stops a whole gutter short of an edge a drag can\n reach.\n\n None was the correction, and it overshot: the panel is anchored bottom-\n right with a gutter already spent there, so a cap of the full usable\n height puts the far edge exactly one gutter outside it. On an 800px screen\n with nothing reserved that is a top of -24 -- the header, and every\n control in it, off the top of the window. Reserve a 120px header and it\n sits inside that instead, which is the one thing the reservation exists to\n prevent.\n\n One is the fixed point of both complaints. A resting panel grown to the\n cap runs from the usable near edge to its gutter on the far one, so the\n near edge is reachable by a resize exactly as it is by a drag, and neither\n can put any part of the panel outside the box. */\n --_max-width: var(--ag-ui-max-width, calc(var(--_viewport-width) - var(--_edge-gutter)));\n --_max-height: var(--ag-ui-max-height, calc(var(--_viewport-height) - var(--_edge-gutter)));\n /* The size the header's maximize control grows the panel to: the cap above\n unless the host names one. A side column reads the width only. */\n --_maximized-width: var(--ag-ui-maximized-width, var(--_max-width));\n --_maximized-height: var(--ag-ui-maximized-height, var(--_max-height));\n /* The page a side column must leave beside it. A switch, as above: unset, a\n cap that reads it with no fallback drops out and caps nothing. */\n --_min-page-width-set: var(--ag-ui-min-page-width);\n /* Reading-column width for placement=\"page\" (full-bleed, centred content). */\n --_content-max-width: var(--ag-ui-content-max-width, 820px);\n /* The greeting over an empty full-page conversation. The size scales with\n the viewport between a phone and a desktop rather than stepping at a\n breakpoint. */\n --_greeting-font: var(--ag-ui-greeting-font, var(--_font));\n --_greeting-size: var(--ag-ui-greeting-size, clamp(1.5rem, 4vw, 2.25rem));\n /* Slim rail the sidebar placement collapses to. Only that placement reads\n it, but it is declared here so every alias has a default in one place. */\n --_rail-width: var(--ag-ui-rail-width, 52px);\n\n position: var(--_position);\n inset: var(--_inset);\n z-index: var(--_z-index);\n width: var(--_width);\n max-width: var(--_max-width);\n height: var(--_height);\n max-height: var(--_max-height);\n display: flex;\n font-family: var(--_font);\n font-size: var(--_font-size);\n color: var(--_fg);\n\n /* Surfaces a theme can tint; Quiet leaves them neutral. */\n --_tint: var(--ag-ui-tint, var(--_wash));\n --_tint-2: var(--ag-ui-tint-2, var(--_user-bg));\n\n /* Status marks drawn as masks, so they take the colour of their state. */\n --_ico-check: var(--ag-ui-ico-check, url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E\"));\n --_ico-error: var(--ag-ui-ico-error, url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M8 4.9v3.7M8 11.1v.1'/%3E%3C/svg%3E\"));\n --_ico-declined: var(--ag-ui-ico-declined, url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M3.8 12.2l8.4-8.4'/%3E%3C/svg%3E\"));\n --_ico-chevron: var(--ag-ui-ico-chevron, url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5l4.5 4.5L6 12.5'/%3E%3C/svg%3E\"));\n}\n\n/* The colour drawn on the accent, from the accent's own luminance: white on\n an accent darker than WCAG relative luminance 0.179, black on a lighter\n one. That is the crossover where the two give the same contrast, so the\n pick is always the better of the two and never under 4.58:1. A threshold on\n oklch lightness was tried first and missed: indigo 500 sits under the\n threshold that works for greys and took white at 4.47:1. Each channel is\n the same expression over the linear channels, so the result is pure black\n or pure white. A host that sets a mid-tone brand accent in the dark scheme\n would otherwise get the scheme's near-black on it. Relative colour syntax\n with channel arithmetic is Chrome 119, Firefox 128 and Safari 18. Of the\n browsers at or above this package's floor (Chrome 123, Firefox 120, Safari\n 17.5), Firefox 120 to 127 lack it, and Safari 17.5 and 17.6 parse an older\n draft that rejects this expression, so the test below asks for the exact\n expression and those engines keep the fallback above. light-dark needs no\n such test: the floor is set where every engine has it. */\n@supports (color: color(from red srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) 0 0)) {\n :host {\n --_on-accent: var(--ag-ui-on-accent, color(from var(--_accent) srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1)));\n }\n}\n\n/* Without relative colour syntax, classic and code keep the white they drew\n before the theme set, not the scheme's colour: their accents are dark in\n both schemes. Only on that path, so where the pick can be computed it is.\n The condition is the one above, negated, and must stay its exact twin. */\n@supports not (color: color(from red srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) 0 0)) {\n :host([theme~=\"classic\"]),\n :host([theme~=\"code\"]) {\n --_on-accent: var(--ag-ui-on-accent, #ffffff);\n }\n}\n\n/* The header buttons' default hover square as the header text's opposite,\n so white text gets a darker square and dark text a lighter one. A square\n mixed from the text itself moves the ground toward the glyph: white on a\n mid-blue header fell from 5.1:1 to 3.75:1 under the pointer. Moving away\n from it can only raise what the host's own pair reads. Gated on this\n exact expression, so a browser that cannot compute it keeps the square\n mixed from the text rather than losing the square altogether. */\n@supports (color: rgb(from red calc(255 - r) calc(255 - g) calc(255 - b))) {\n :host {\n --_header-btn-hover-auto: color-mix(in srgb, rgb(from var(--_header-fg-set) calc(255 - r) calc(255 - g) calc(255 - b)) 18%, transparent);\n }\n}\n`;\n", "// The classic theme's contrast fixes. Classic's structure is the base\n// stylesheet, so this holds only what it took to bring the old look to AA.\nexport const CLASSIC_STYLES: string = `\n/* \u2500\u2500 Classic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The status pill draws its state's colour on a grey wash, which measured\n 3.75:1 for done in the light scheme and under 2.5:1 in the dark one. Each\n state's ink is pulled halfway to the text colour: darker on the light\n panel, lighter on the dark one, still recognisably its state. Scoped to\n classic, so code keeps the pill it always had. */\n:host([theme~=\"classic\"]) .tool-call-status {\n color: color-mix(in oklch, var(--_muted) 50%, var(--_fg));\n}\n\n:host([theme~=\"classic\"]) .tool-call[data-status=\"deferred\"] .tool-call-status {\n color: color-mix(in oklch, var(--_accent) 50%, var(--_fg));\n}\n\n:host([theme~=\"classic\"]) .tool-call[data-status=\"done\"] .tool-call-status {\n color: color-mix(in oklch, var(--_success) 50%, var(--_fg));\n}\n\n:host([theme~=\"classic\"]) .tool-call[data-status=\"error\"] .tool-call-status {\n color: color-mix(in oklch, var(--_danger) 50%, var(--_fg));\n}\n\n/* The browser's default placeholder measured 3.93:1 on the dark composer.\n The muted ink clears 4.5:1 in both schemes. */\n:host([theme~=\"classic\"]) .input::placeholder {\n color: var(--_muted);\n opacity: 1;\n}\n`;\n", "// The classic theme: the look before the revamp, kept so a host can pin it.\n// Tokens only; classic's structure is the base stylesheet itself.\nexport const CLASSIC_TOKENS: string = `\n/* \u2500\u2500 Classic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Today's indigo header, accent user bubble, round launcher and heavy\n shadow, in both schemes. The code theme starts from these as well, since\n it was always this structure in a terminal palette. */\n:host([theme~=\"classic\"]),\n:host([theme~=\"code\"]) {\n --_bg: var(--ag-ui-bg, light-dark(#ffffff, #15151f));\n --_fg: var(--ag-ui-fg, light-dark(#1a1a2e, #e8e8f2));\n --_accent: var(--ag-ui-accent, #4f46e5);\n --_user-bg: var(--ag-ui-user-bg, #4f46e5);\n --_user-fg: var(--ag-ui-user-fg, #ffffff);\n --_assistant-bg: var(--ag-ui-assistant-bg, light-dark(#f1f1f6, #25253a));\n --_hover: var(--ag-ui-hover, light-dark(#e7e7ee, #303049));\n --_tool-bg: var(--ag-ui-tool-bg, var(--_assistant-bg));\n --_tool-fg: var(--ag-ui-tool-fg, var(--_accent));\n --_header-bg: var(--ag-ui-header-bg, light-dark(var(--_accent), #1f1f30));\n --_header-fg: var(--ag-ui-header-fg, light-dark(#ffffff, #e8e8f2));\n --_header-btn-hover: var(--ag-ui-header-btn-hover, var(--_header-btn-hover-auto, rgba(255, 255, 255, 0.18)));\n --_border: var(--ag-ui-border, light-dark(#e2e2ec, #33334a));\n --_muted: var(--ag-ui-muted, light-dark(#6b7280, #9aa0b4));\n --_success: var(--ag-ui-success, #15803d);\n --_danger: var(--ag-ui-danger, #b91c1c);\n --_tooltip-bg: var(--ag-ui-tooltip-bg, #1f2430);\n --_tooltip-fg: var(--ag-ui-tooltip-fg, #f5f6fa);\n --_font: var(--ag-ui-font, inherit);\n --_frame-radius: var(--ag-ui-frame-radius, var(--_radius));\n --_frame-shadow: var(--ag-ui-frame-shadow, 0 12px 32px light-dark(rgba(20, 20, 50, 0.18), rgba(0, 0, 0, 0.5)));\n --_composer-radius: var(--ag-ui-composer-radius, 14px);\n --_msg-radius: var(--ag-ui-msg-radius, 14px);\n --_launcher-size: var(--ag-ui-launcher-size, 56px);\n --_launcher-bg: var(--ag-ui-launcher-bg, var(--_header-bg));\n --_launcher-fg: var(--ag-ui-launcher-fg, var(--_header-fg));\n --_launcher-radius: var(--ag-ui-launcher-radius, 50%);\n --_launcher-icon-size: var(--ag-ui-launcher-icon-size, 26px);\n --_chart-1: var(--ag-ui-chart-1, #4f7cff);\n --_chart-2: var(--ag-ui-chart-2, #21b573);\n}\n\n/* Classic's contrast fixes, which code does not share. The indigo accent\n measured 2.38:1 as tool-name text on the dark card, and the old success\n green 2.38:1 as the done mark there; in the dark scheme the tool name\n takes the accent mixed halfway to the text colour, and success the\n lighter green the other themes use. The light half is unchanged. */\n:host([theme~=\"classic\"]) {\n --_tool-fg: var(--ag-ui-tool-fg, light-dark(var(--_accent), color-mix(in oklch, var(--_accent) 50%, var(--_fg))));\n --_success: var(--ag-ui-success, light-dark(#15803d, #4ade80));\n}\n`;\n", "// The code theme: classic's structure in a dark terminal palette. Kept for\n// hosts that already wear it; Ledger is where a monospace look goes next.\nexport const CODE_TOKENS: string = `\n/* \u2500\u2500 Code \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Dark only, monospace, green accent. Restates the colours classic sets,\n after it, so code wins wherever the two would both apply. */\n:host([theme~=\"code\"]) {\n --_bg: var(--ag-ui-bg, #0d1117);\n --_fg: var(--ag-ui-fg, #c9d1d9);\n --_accent: var(--ag-ui-accent, #3fb950);\n --_user-bg: var(--ag-ui-user-bg, #238636);\n --_assistant-bg: var(--ag-ui-assistant-bg, #161b22);\n --_hover: var(--ag-ui-hover, #21262d);\n --_header-bg: var(--ag-ui-header-bg, #010409);\n --_header-fg: var(--ag-ui-header-fg, #c9d1d9);\n --_border: var(--ag-ui-border, #30363d);\n --_muted: var(--ag-ui-muted, #8b949e);\n --_font: var(--ag-ui-font, var(--_code-font));\n --_frame-shadow: var(--ag-ui-frame-shadow, 0 12px 32px rgba(0, 0, 0, 0.6));\n}\n`;\n", "// The ledger theme's structure: rules, square corners, serif and monospace.\nexport const LEDGER_STYLES: string = `\n/* \u2500\u2500 Ledger \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Structure only; the tokens are in ledger_tokens. Serif for what the\n agent says, monospace for what the machine did. */\n\n:host([theme~=\"ledger\"]) .chat {\n line-height: var(--_leading);\n border-color: var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .header {\n padding: 8px 10px 8px 14px;\n border-bottom-color: var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .header-title {\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n:host([theme~=\"ledger\"]) .header-title::before {\n content: \"\";\n display: inline-block;\n width: 7px;\n height: 7px;\n margin-right: 8px;\n background: var(--_accent);\n vertical-align: 1px;\n}\n\n/* Both inks yield once the host sets the header text, since the header behind\n them is then the host's colour (see the switches in the token defaults). */\n:host([theme~=\"ledger\"]) .header-btn {\n color: var(--_header-fg-set, var(--_ink-3));\n border-radius: 3px;\n}\n\n:host([theme~=\"ledger\"]) .header-btn:hover {\n color: var(--_header-fg-set, var(--_fg));\n}\n\n:host([theme~=\"ledger\"]) .message--user {\n align-self: stretch;\n max-width: 100%;\n margin-top: 6px;\n padding: 2px 0 2px 12px;\n border-left: 2px solid var(--_fg);\n font-weight: 500;\n}\n\n:host([theme~=\"ledger\"]) .message--user + .answer,\n:host([theme~=\"ledger\"]) .answer + .message--user {\n margin-top: 4px;\n}\n\n:host([theme~=\"ledger\"]) .answer + .message--user {\n border-top: 0;\n}\n\n:host([theme~=\"ledger\"]) .message--assistant {\n padding: 0;\n max-width: 100%;\n font-family: var(--_serif);\n font-size: var(--_text-lg);\n line-height: 1.5;\n}\n\n:host([theme~=\"ledger\"]) .message--assistant a {\n color: var(--_accent-ink);\n}\n\n:host([theme~=\"ledger\"]) .thoughts-toggle {\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n letter-spacing: 0.01em;\n}\n\n/* The step group's row reads as a ledger heading. Unscoped to grouped mode:\n a card mode hides the row and drops the list's box, so neither reaches a\n flattened card. */\n:host([theme~=\"ledger\"]) .tool-group-head {\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n border-radius: 2px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n:host([theme~=\"ledger\"]) .tool-group-list {\n border-left: 1px dashed var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .chart-block {\n border-top: 1px solid var(--_line-strong);\n border-bottom: 1px solid var(--_line);\n padding: 8px 0;\n}\n\n:host([theme~=\"ledger\"]) .chart-title {\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n:host([theme~=\"ledger\"]) .input-row {\n padding-block: 10px;\n border-top: 1px solid var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .composer {\n border-color: var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .composer:focus-within {\n border-color: var(--_fg);\n}\n\n:host([theme~=\"ledger\"]) .send {\n border-radius: 3px;\n}\n\n:host([theme~=\"ledger\"]) :is(.suggestion-chip, .skill-chip) {\n background: transparent;\n border: 1px solid var(--_line-strong);\n color: var(--_ink-2);\n border-radius: 2px;\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n padding: 3px 8px;\n}\n\n:host([theme~=\"ledger\"]) :is(.suggestion-chip, .skill-chip):hover {\n border-color: var(--_fg);\n color: var(--_fg);\n}\n\n:host([theme~=\"ledger\"]) .confirm {\n border: 1px solid var(--_fg);\n border-left: 3px solid var(--_accent);\n border-radius: 2px;\n padding: 10px 12px;\n gap: 10px;\n background: var(--_bg);\n}\n\n:host([theme~=\"ledger\"]) .confirm-btn {\n border-radius: 2px;\n padding: 5px 12px;\n font-family: var(--_code-font);\n font-size: var(--_text-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n border-color: var(--_line-strong);\n}\n\n:host([theme~=\"ledger\"]) .confirm-btn--confirm {\n border-color: var(--_accent);\n}\n\n:host([theme~=\"ledger\"]) .launcher {\n border: 0;\n}\n`;\n", "// The ledger theme's tokens: dense and editorial, paper and ink.\nexport const LEDGER_TOKENS: string = `\n/* \u2500\u2500 Ledger \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n A smaller type scale than the other themes, because density is the point.\n Set before the density presets, so density=\"compact\" still wins. */\n:host([theme~=\"ledger\"]) {\n --_bg: var(--ag-ui-bg, light-dark(#fbfaf6, #151513));\n --_fg: var(--ag-ui-fg, light-dark(#1d1c19, #e8e6df));\n --_accent: var(--ag-ui-accent, light-dark(#b8410e, #f08a4b));\n --_code-font: var(--ag-ui-code-font, \"JetBrains Mono\", ui-monospace, Menlo, monospace);\n --_text-xs: var(--ag-ui-text-xs, 10.5px);\n --_text-sm: var(--ag-ui-text-sm, 12px);\n --_text-md: var(--ag-ui-text-md, 13px);\n --_text-lg: var(--ag-ui-text-lg, 14.5px);\n --_leading: var(--ag-ui-leading, 1.5);\n --_space: var(--ag-ui-space, 8px);\n --_pad: var(--ag-ui-pad, 14px);\n --_radius: var(--ag-ui-radius, 3px);\n --_frame-radius: var(--ag-ui-frame-radius, var(--ag-ui-radius, 6px));\n --_msg-radius: var(--ag-ui-msg-radius, 0px);\n --_composer-radius: var(--ag-ui-composer-radius, 4px);\n --_user-bg: var(--ag-ui-user-bg, transparent);\n --_header-btn-hover: var(--ag-ui-header-btn-hover, var(--_header-btn-hover-auto, var(--_hover)));\n --_frame-shadow: var(--ag-ui-frame-shadow, 0 0 0 1px var(--_line-strong), 0 20px 40px -28px rgb(0 0 0 / 0.45));\n --_launcher-bg: var(--ag-ui-launcher-bg, var(--_fg));\n --_launcher-fg: var(--ag-ui-launcher-fg, var(--_bg));\n --_launcher-radius: var(--ag-ui-launcher-radius, 6px);\n --_launcher-size: var(--ag-ui-launcher-size, 44px);\n --_launcher-icon-size: var(--ag-ui-launcher-icon-size, 20px);\n --_chart-1: var(--ag-ui-chart-1, var(--_fg));\n --_chart-2: var(--ag-ui-chart-2, var(--_accent));\n}\n`;\n", "/**\n * The host selectors theme rules hang off, as one record so every theme\n * module spells them the same way.\n *\n * Classic and code keep today's structure, so the structural rules the newer\n * themes share apply to every element that wears neither. Quiet is the\n * default, so its own structure applies to every element that wears no other\n * built-in theme -- including one whose theme is a word the library does not\n * know, which is how a host's own named theme starts from Quiet.\n */\nexport const THEME_HOST = {\n modern: ':host(:not([theme~=\"classic\"], [theme~=\"code\"]))',\n quiet: ':host(:not([theme~=\"classic\"], [theme~=\"code\"], [theme~=\"soft\"], [theme~=\"ledger\"]))',\n} as const;\n", "import { THEME_HOST } from \"./theme_hosts.js\";\n\n// The structure every theme but classic and code shares: status as an icon,\n// one chip row, one action row per answer, and a readable placeholder.\nexport const MODERN_STYLES: string = `\n/* \u2500\u2500 status as an icon, never a pill \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The word stays for assistive technology through the card's own label; the\n pill only ever repeated what the icon said. */\n${THEME_HOST.modern} .tool-call-status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n${THEME_HOST.modern} .tool-call:is([data-status=\"done\"], [data-status=\"error\"], [data-status=\"declined\"]) .tool-call-icon::before {\n content: \"\";\n width: 14px;\n height: 14px;\n background: currentColor;\n mask: var(--_ico-check) center / contain no-repeat;\n}\n\n${THEME_HOST.modern} .tool-call[data-status=\"done\"] .tool-call-icon {\n color: var(--_success);\n}\n\n${THEME_HOST.modern} .tool-call[data-status=\"error\"] .tool-call-icon {\n color: var(--_danger);\n}\n\n${THEME_HOST.modern} .tool-call[data-status=\"error\"] .tool-call-icon::before {\n mask-image: var(--_ico-error);\n}\n\n/* An interrupted call is muted like a declined one but keeps the base glyph\n rather than taking the declined mark: nobody refused it, it only did not\n finish. */\n${THEME_HOST.modern} .tool-call:is([data-status=\"declined\"], [data-status=\"interrupted\"]) .tool-call-icon {\n color: var(--_muted);\n}\n\n${THEME_HOST.modern} .tool-call[data-status=\"declined\"] .tool-call-icon::before {\n mask-image: var(--_ico-declined);\n}\n\n/* The settled icon inherits colour from the icon box, so the box's own glyph\n colour from the base rules must not win. */\n${THEME_HOST.modern} .tool-call .tool-call-icon::before {\n color: inherit;\n}\n\n/* \u2500\u2500 one chip row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Follow-up suggestions are the row once a conversation has started; the\n skill chips stay on the empty state only and otherwise live in the slash\n palette, so two rows never compete above the composer. */\n:host(:not([theme~=\"classic\"], [theme~=\"code\"], [data-empty])) .skill-chips {\n display: none;\n}\n\n/* \u2500\u2500 one action row per answer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Copy and retry under every interim sentence of a long turn read as noise;\n only the row after the last bubble of a turn stays. */\n${THEME_HOST.modern} .message-actions:has(~ .message--assistant) {\n display: none;\n}\n\n${THEME_HOST.modern} .chart-block {\n box-sizing: border-box;\n}\n\n/* The baseline placeholder is the browser default, which measured under\n 4.5:1 on every dark surface. A derived ink clears it in both schemes. */\n${THEME_HOST.modern} .input::placeholder {\n color: var(--_ink-3);\n opacity: 1;\n}\n`;\n", "import { THEME_HOST } from \"./theme_hosts.js\";\n\n// The default theme's structure. Applies to every element wearing no other\n// built-in theme, so a host's own named theme starts from it.\nexport const QUIET_STYLES: string = `\n/* \u2500\u2500 Quiet \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n The default. Its tokens are the token defaults; this is the little\n structure it adds on top: no bubble for the agent, hairlines, and a\n composer that sits on the panel rather than in a band. */\n\n${THEME_HOST.quiet} .chat {\n font-feature-settings: \"cv11\", \"ss01\";\n letter-spacing: -0.003em;\n line-height: var(--_leading);\n}\n\n${THEME_HOST.quiet} .header {\n padding: 12px 14px 12px 18px;\n}\n\n${THEME_HOST.quiet} .header-title {\n font-size: var(--_text-md);\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n/* The buttons sit back in the third ink on the panel. Once the host sets the\n header text they draw in it instead, since the header behind them is then\n the host's colour (see the switches in the token defaults). */\n${THEME_HOST.quiet} .header-btn {\n color: var(--_header-fg-set, var(--_ink-3));\n border-radius: 8px;\n}\n\n/* The glyph takes the header text, which is the full ink when that is unset. */\n${THEME_HOST.quiet} .header-btn:hover {\n color: var(--_header-fg);\n}\n\n${THEME_HOST.quiet} .message--user {\n border-radius: var(--_msg-radius);\n padding: 8px 12px;\n}\n\n${THEME_HOST.quiet} .message--assistant {\n padding: 0;\n max-width: 100%;\n}\n\n${THEME_HOST.quiet} .message--assistant a {\n color: inherit;\n text-decoration: underline;\n text-decoration-color: var(--_line-strong);\n text-underline-offset: 3px;\n}\n\n${THEME_HOST.quiet} .thoughts-toggle {\n color: var(--_muted);\n font-size: var(--_text-sm);\n}\n\n${THEME_HOST.quiet} .input-row {\n border-top: 0;\n padding-top: 4px;\n}\n\n${THEME_HOST.quiet} .composer {\n border-color: var(--_line-strong);\n box-shadow: 0 1px 2px rgb(0 0 0 / 0.04);\n}\n\n${THEME_HOST.quiet} .composer:focus-within {\n border-color: var(--_ink-3);\n box-shadow: 0 0 0 3px var(--_wash);\n}\n\n${THEME_HOST.quiet} .send {\n border-radius: 9px;\n}\n\n${THEME_HOST.quiet} :is(.suggestion-chip, .skill-chip) {\n background: transparent;\n border: 1px solid var(--_line);\n color: var(--_ink-2);\n border-radius: 999px;\n}\n\n${THEME_HOST.quiet} :is(.suggestion-chip, .skill-chip):hover {\n background: var(--_hover);\n color: var(--_fg);\n}\n\n${THEME_HOST.quiet} .confirm {\n border: 1px solid var(--_line-strong);\n border-radius: var(--_radius);\n padding: 14px;\n gap: 12px;\n box-shadow: 0 1px 2px rgb(0 0 0 / 0.04);\n}\n\n${THEME_HOST.quiet} .confirm-btn {\n border-radius: 8px;\n padding: 7px 14px;\n font-weight: 500;\n font-size: var(--_text-sm);\n border-color: var(--_line-strong);\n}\n\n${THEME_HOST.quiet} .confirm-btn--confirm {\n border-color: var(--_accent);\n font-weight: 600;\n}\n\n${THEME_HOST.quiet} .launcher {\n border: 1px solid var(--_line-strong);\n box-shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 8px 24px -10px rgb(0 0 0 / 0.25);\n}\n`;\n", "// The scheme word of the theme attribute: light (the default), dark or auto.\nexport const SCHEME_STYLES: string = `\n/* \u2500\u2500 Scheme \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Every theme declares its colours with light-dark, so the scheme is one\n property. Matched as a word, so dark works alone (the default theme,\n dark) and beside a theme name (soft dark). auto follows the operating\n system through color-scheme itself, with no media query to keep in step.\n code is a dark-only theme and has no light half. */\n/* Important, so a scheme word holds against a host rule that sets the\n element's color-scheme (a page that follows its own dark mode). A rule\n from outside the shadow tree beats every :host rule at normal weight, and\n the theme toggle writes the word; without this its press changed nothing.\n code stays last, so code light is still dark. */\n:host([theme~=\"light\"]) {\n color-scheme: light !important;\n}\n\n:host([theme~=\"dark\"]),\n:host([theme~=\"code\"]) {\n color-scheme: dark !important;\n}\n\n:host([theme~=\"auto\"]) {\n color-scheme: light dark;\n}\n`;\n", "// The soft theme's structure: pills, tinted surfaces, rounded cards.\nexport const SOFT_STYLES: string = `\n/* \u2500\u2500 Soft \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Structure only; the tokens are in soft_tokens, set before the density\n presets. */\n\n:host([theme~=\"soft\"]) .chat {\n line-height: var(--_leading);\n background: var(--_bg);\n}\n\n:host([theme~=\"soft\"]) .header {\n border-bottom-color: transparent;\n padding: 14px 16px 12px 20px;\n}\n\n:host([theme~=\"soft\"]) .header-title {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n font-size: var(--_text-lg);\n font-weight: 600;\n letter-spacing: -0.015em;\n}\n\n:host([theme~=\"soft\"]) .header-title::before {\n content: \"\";\n width: 22px;\n height: 22px;\n border-radius: 8px;\n background: linear-gradient(140deg, color-mix(in oklch, var(--_accent) 55%, var(--_bg)), var(--_accent));\n}\n\n/* Both inks yield once the host sets the header text, since the header behind\n them is then the host's colour (see the switches in the token defaults). */\n:host([theme~=\"soft\"]) .header-btn {\n color: var(--_header-fg-set, var(--_ink-3));\n border-radius: 10px;\n}\n\n:host([theme~=\"soft\"]) .header-btn:hover {\n color: var(--_header-fg-set, var(--_accent-ink));\n}\n\n:host([theme~=\"soft\"]) .messages {\n background: linear-gradient(var(--_tint), var(--_bg) 120px);\n}\n\n:host([theme~=\"soft\"]) .message--user {\n border-radius: var(--_msg-radius) var(--_msg-radius) 6px var(--_msg-radius);\n padding: 9px 14px;\n}\n\n:host([theme~=\"soft\"]) .message--assistant {\n padding: 0 2px;\n max-width: 100%;\n}\n\n:host([theme~=\"soft\"]) .message--assistant a {\n color: var(--_accent-ink);\n}\n\n/* The step group's row as a tinted pill. Unscoped to grouped mode: a card\n mode hides the row and drops the list's box, so neither reaches a\n flattened card. */\n:host([theme~=\"soft\"]) .tool-group-head {\n background: var(--_tint);\n border: 1px solid var(--_border);\n border-radius: 999px;\n padding: 5px 12px 5px 9px;\n margin-left: 0;\n}\n\n:host([theme~=\"soft\"]) .tool-group-head:hover {\n background: var(--_tint-2);\n}\n\n:host([theme~=\"soft\"]) .tool-group-list {\n border-left-color: var(--_tint-2);\n margin-left: 14px;\n}\n\n:host([theme~=\"soft\"]) .chart-block {\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: var(--_radius);\n padding: 12px 14px;\n}\n\n:host([theme~=\"soft\"]) .input-row {\n border-top: 0;\n padding-block: 6px 16px;\n}\n\n:host([theme~=\"soft\"]) .composer {\n padding: 8px 8px 8px 14px;\n border-color: var(--_border);\n box-shadow: 0 6px 20px -10px color-mix(in oklch, var(--_accent) 35%, transparent);\n}\n\n:host([theme~=\"soft\"]) .composer:focus-within {\n border-color: color-mix(in oklch, var(--_accent) 50%, var(--_bg));\n box-shadow: 0 0 0 4px var(--_tint-2);\n}\n\n:host([theme~=\"soft\"]) .send {\n border-radius: 999px;\n}\n\n:host([theme~=\"soft\"]) :is(.suggestion-chip, .skill-chip) {\n background: var(--_tint-2);\n border: 1px solid transparent;\n color: var(--_accent-ink);\n border-radius: 999px;\n font-weight: 500;\n}\n\n:host([theme~=\"soft\"]) :is(.suggestion-chip, .skill-chip):hover {\n border-color: color-mix(in oklch, var(--_accent) 35%, var(--_bg));\n}\n\n:host([theme~=\"soft\"]) .confirm {\n background: var(--_tint);\n border: 1px solid var(--_border);\n border-radius: 18px;\n padding: 16px;\n gap: 14px;\n}\n\n:host([theme~=\"soft\"]) .confirm-btn {\n border-radius: 999px;\n padding: 8px 16px;\n font-weight: 500;\n background: var(--_bg);\n border-color: var(--_border);\n}\n\n:host([theme~=\"soft\"]) .confirm-btn--confirm {\n background: var(--_accent);\n border-color: var(--_accent);\n color: var(--_on-accent);\n font-weight: 600;\n}\n\n:host([theme~=\"soft\"]) .launcher {\n border: 0;\n box-shadow: 0 14px 30px -12px color-mix(in oklch, var(--_accent) 70%, transparent);\n}\n`;\n", "// The soft theme's tokens: rounded, with surfaces tinted from the accent.\nexport const SOFT_TOKENS: string = `\n/* \u2500\u2500 Soft \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Seeds, plus two surfaces mixed from the accent: a faint wash for the panel\n chrome and a stronger tint for the user's turns. */\n:host([theme~=\"soft\"]) {\n --_bg: var(--ag-ui-bg, light-dark(#fdfcff, #17161d));\n --_fg: var(--ag-ui-fg, light-dark(#1f1d2b, #ebe9f5));\n --_accent: var(--ag-ui-accent, light-dark(#6a4fd8, #a593ff));\n --_tint: var(--ag-ui-tint, color-mix(in oklch, var(--_accent) 5%, var(--_bg)));\n --_tint-2: var(--ag-ui-tint-2, color-mix(in oklch, var(--_accent) 13%, var(--_bg)));\n --_header-bg: var(--ag-ui-header-bg, var(--_tint));\n --_header-btn-hover: var(--ag-ui-header-btn-hover, var(--_header-btn-hover-auto, var(--_tint-2)));\n --_user-bg: var(--ag-ui-user-bg, var(--_tint-2));\n --_border: var(--ag-ui-border, color-mix(in oklch, var(--_accent) 14%, var(--_bg)));\n --_radius: var(--ag-ui-radius, 16px);\n --_frame-radius: var(--ag-ui-frame-radius, var(--ag-ui-radius, 24px));\n --_msg-radius: var(--ag-ui-msg-radius, 18px);\n --_composer-radius: var(--ag-ui-composer-radius, 22px);\n --_frame-shadow: var(--ag-ui-frame-shadow, 0 2px 6px light-dark(rgb(30 20 60 / 0.05), rgb(0 0 0 / 0.3)), 0 30px 60px -28px light-dark(color-mix(in oklch, var(--_accent) 45%, transparent), rgb(0 0 0 / 0.75)));\n --_launcher-size: var(--ag-ui-launcher-size, 56px);\n --_launcher-bg: var(--ag-ui-launcher-bg, var(--_accent));\n --_launcher-fg: var(--ag-ui-launcher-fg, var(--_on-accent));\n --_launcher-radius: var(--ag-ui-launcher-radius, 20px);\n --_launcher-icon-size: var(--ag-ui-launcher-icon-size, 24px);\n --_chart-1: var(--ag-ui-chart-1, var(--_accent));\n --_chart-2: var(--ag-ui-chart-2, color-mix(in oklch, var(--_accent) 38%, var(--_bg)));\n}\n`;\n", "// An attachment chip, in the tray and in a sent message alike, the drop\n// outline, and the note a cancelled run leaves, which sits here only\n// because no rule moved in the split.\nexport const ATTACHMENT_CHIP_STYLES: string = `\n/* A chip carries its own text colour because it carries its own background.\n The same chip renders in two places with opposite inherited colours: the\n composer tray gives it the panel's, a sent user bubble gives it the user\n foreground, which is white on the stock light theme and near-invisible\n against the chip. Pairing the colour with the background it belongs to makes\n both placements read alike. Overridden below for an errored chip, which\n keeps its red. */\n.attachment-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Without this the 100% below caps the content box, so the chip still\n overflows its container by its own padding and border. Invisible while a\n character cap kept names short; routine once the container is what bounds\n the name. */\n box-sizing: border-box;\n max-width: 100%;\n padding: 4px 8px;\n border: 1px solid var(--_border);\n border-radius: 999px;\n background: var(--_assistant-bg);\n color: var(--_text);\n font-size: 0.85em;\n position: relative;\n}\n\n.attachment-chip--error {\n border-color: var(--_danger);\n color: var(--_danger);\n}\n\n/* The type mark. Painted from currentColor, so it carries the chip's state\n with it and turns red along with an errored one; muted by opacity rather\n than a colour, which is what keeps that true. Sized from the chip's own text\n rather than --ag-ui-glyph-size, the way an icon holder's glyph takes the\n holder's size: the composer's 18px buttons would make a chip button-height. */\n.attachment-chip-icon {\n display: inline-flex;\n flex: none;\n opacity: 0.75;\n}\n\n.attachment-chip-icon .glyph {\n width: 1.25em;\n height: 1.25em;\n}\n\n/* No character cap: the chip is already max-width 100%, so its container is\n what bounds the name, and a fixed cap only truncated names the chip had room\n for. min-width: 0 is what lets the flex item shrink past its content, so the\n ellipsis appears at the container edge instead of the chip overflowing. */\n.attachment-chip-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.attachment-chip-size {\n color: var(--_muted);\n white-space: nowrap;\n}\n\n.attachment-chip--error .attachment-chip-size {\n color: var(--_danger);\n}\n\n/* The progress bar fills as the file uploads. */\n.attachment-chip-bar {\n flex-basis: 100%;\n height: 3px;\n border-radius: 2px;\n background: var(--_border);\n overflow: hidden;\n}\n\n.attachment-chip-bar-fill {\n height: 100%;\n background: var(--_accent);\n transition: width 0.15s ease;\n}\n\n.attachment-chip-remove,\n.attachment-chip-retry {\n border: none;\n background: none;\n color: inherit;\n cursor: pointer;\n padding: 0;\n line-height: 1;\n opacity: 0.7;\n}\n\n.attachment-chip-remove:hover,\n.attachment-chip-retry:hover {\n opacity: 1;\n}\n\n/* A subtle outline while a file is dragged over the shell. */\n.chat--dragover {\n outline: 2px dashed var(--_accent);\n outline-offset: -4px;\n}\n\n/* Muted \"\u23F9 Stopped\" line after a cancelled run \u2014 a note, not an error bubble. */\n.stopped-note {\n align-self: flex-start;\n color: var(--_muted);\n font-size: 12px;\n padding: 2px 4px;\n}\n`;\n", "// The empty state: the greeting over an empty conversation, and the\n// composer's travel from the centre to the foot on the first send.\nexport const GREETING_STYLES: string = `\n/* Empty-state region (slot): centred while it's the only thing in the\n list, hidden as soon as a message, card, or pending indicator renders. */\n.empty {\n margin: auto;\n text-align: center;\n color: var(--_muted);\n}\n\n.empty[hidden] {\n display: none;\n}\n\n/* The greeting layout: a greeting over an empty conversation, and the\n composer centred beneath it until the conversation has something in it.\n\n On by default for the page placement, where a conversation is the whole\n route; data-greeting=\"off\" turns it off there. An embedded panel opts in\n with any other data-greeting value. No other placement has it: a panel\n opened from a launcher is already mid-task, and a greeting in a corner\n panel costs space and says little.\n\n The greeting itself renders under every placement and is hidden here, so a\n placement switch at runtime needs nothing from script. */\n.greeting {\n display: none;\n}\n\n:host([placement=\"page\"]:not([data-greeting=\"off\"])) .greeting,\n:host([placement=\"embedded\"][data-greeting]:not([data-greeting=\"off\"])) .greeting {\n display: block;\n margin-block-end: calc(var(--_space) * 2);\n font-family: var(--_greeting-font);\n font-size: var(--_greeting-size);\n font-weight: 500;\n line-height: 1.2;\n color: var(--_fg);\n overflow-wrap: anywhere;\n}\n\n/* Centring is two equal flexible boxes either side of the composer rows: the\n transcript above, which already grows, and this one below. Equal zero bases\n make the two halves the same height whatever they hold, so the rows sit in\n the middle of the panel below its header, and stay there as a draft, an\n attachment tray or a hint grows them, because growth splits into both\n halves at once.\n\n A pseudo element rather than a node, so no host layout and nothing that\n counts children can see it. It exists whether or not the conversation is\n empty and only its growth changes, because a box that appears and\n disappears is a box nothing can ever transition.\n\n Only the rule that generates it names the placements. The one that grows it\n needs nothing but the state: where the first rule does not apply there is no\n box to grow. The box is empty, so its automatic basis is already zero, the\n same as the transcript's; nothing here writes the flex shorthand, because\n this selector is the more specific of the two and a shorthand would win\n over the growth. */\n:host([placement=\"page\"]:not([data-greeting=\"off\"])) .chat::after,\n:host([placement=\"embedded\"][data-greeting]:not([data-greeting=\"off\"])) .chat::after {\n content: \"\";\n}\n\n/* Not while a restore is in flight: a conversation a remote store is still\n fetching is more likely to have messages than not, and centring it first\n would drop the composer the moment they land. */\n:host([data-empty]:not([data-restoring])) .chat::after {\n flex-grow: 1;\n}\n\n/* Only the send that leaves the empty state travels. The element arms this for\n that one change and disarms it whenever the transcript is cleared, so a\n restored conversation, a thread switch and a new chat all snap. Growth rather\n than a transform, because the rows between the transcript and the composer\n move with it, and growth is continuous where a reorder is not. Reduced motion\n needs no rule of its own: the motion token already collapses to a frame\n there.\n\n The rule over the composer fades in over the same stretch. Appearing at once,\n it was drawn across the page at the composer's destination while the\n composer was still on its way there. */\n:host([data-composer-settling]) .chat::after {\n transition: flex-grow var(--_motion) var(--_ease);\n}\n\n:host([data-composer-settling]) .input-row {\n transition: border-color var(--_motion) var(--_ease);\n}\n\n/* The greeting and whatever the host slotted sit at the foot of the upper\n half, directly over the composer, rather than floating in its middle. The\n region is hidden once the conversation has content, so this needs no state\n of its own. */\n:host([placement=\"page\"]:not([data-greeting=\"off\"]):not([data-restoring])) .empty,\n:host([placement=\"embedded\"][data-greeting]:not([data-greeting=\"off\"]):not([data-restoring])) .empty {\n margin: auto auto 0;\n}\n\n/* The rule over the composer separates it from a transcript. Over nothing it\n is a line drawn across the middle of the page. */\n:host([placement=\"page\"][data-empty]:not([data-greeting=\"off\"]):not([data-restoring])) .input-row,\n:host([placement=\"embedded\"][data-greeting][data-empty]:not([data-greeting=\"off\"]):not([data-restoring])) .input-row {\n border-block-start-color: transparent;\n}\n\n/* On a phone the composer stays at the foot and the greeting takes the room\n above it, which is the other way round from everything above.\n\n Centring is a shape for a screen with room to spare: the composer reads as\n the one thing on the page, and whichever way the rows grow there is space\n left on both sides of them. A phone has no space to spare, and the keyboard\n is what takes it -- opening one leaves a 426px-tall visible area with the\n composer halfway up it and an empty band underneath, which is the half of\n the screen a thumb is already resting on. Docked, the field sits directly\n over the keyboard, where every chat on the platform puts it, and the\n greeting keeps the rest.\n\n Both rules restate the selector they override, with the breakpoint's own\n opt-out added: this is part of the shape a host keeps its desktop layout\n instead of, so it goes the same way as the rest of that shape. Restating\n rather than adding conditions to the originals keeps each of those rules\n readable as one decision, and source order settles the pair. */\n@media (max-width: 600px) {\n :host([data-empty]:not([data-restoring]):not([data-small-viewport=\"off\"])) .chat::after {\n flex-grow: 0;\n }\n\n /* The empty region fills the transcript instead of being centred in it as a\n block, so the two things in it can go to different places: the prompts the\n host offers to the foot, against the composer, and the greeting to the\n middle of what they leave.\n\n A prompt chip is a way into the conversation. Against the field it starts,\n it reads as one; under the greeting halfway up the panel, with the field\n at the foot, it reads as decoration next to something else. Nothing here\n moves them on a screen where the composer is still centred: there the\n whole region hangs at the foot of the upper half, directly over the\n composer, and the prompts are already against it.\n\n Auto block margins on the greeting are what centre it, and they take the\n free space whether or not there are prompts below to leave any, so a host\n that offers none gets a greeting in the middle of the transcript rather\n than one clinging to the composer.\n The region declares a display here, which outranks the rule collapsing a\n hidden one, so it says it is not hidden itself. Nothing sets the two\n apart today -- the transcript writes the hidden property and the host's\n data-empty from one expression -- and that is exactly why: a rule holding\n because of how a method in another file happens to be written is a rule\n holding by luck. */\n :host([placement=\"page\"][data-empty]:not([data-greeting=\"off\"]):not([data-restoring]):not([data-small-viewport=\"off\"])) .empty:not([hidden]),\n :host([placement=\"embedded\"][data-greeting][data-empty]:not([data-greeting=\"off\"]):not([data-restoring]):not([data-small-viewport=\"off\"])) .empty:not([hidden]) {\n margin: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n\n :host([placement=\"page\"][data-empty]:not([data-greeting=\"off\"]):not([data-restoring]):not([data-small-viewport=\"off\"])) .greeting,\n :host([placement=\"embedded\"][data-greeting][data-empty]:not([data-greeting=\"off\"]):not([data-restoring]):not([data-small-viewport=\"off\"])) .greeting {\n margin-block: auto;\n }\n}\n\n/* Nor does the greeting paint while a restore is in flight. Hidden rather than\n removed, so it keeps its place and nothing around it moves when it shows. */\n:host([data-restoring]) .greeting {\n visibility: hidden;\n}\n`;\n", "// The action row under a message: copy, retry, feedback and the rest.\n// Guest: the whole coarse-pointer block near the end (the resize handle hidden,\n// the 44px touch-target tokens on :host, the 16px composer font floor).\nexport const MESSAGE_ACTION_STYLES: string = `\n The wrap is insurance rather than a fix: these buttons are glyph-only, so at\n every width tested they fit on one line and removing the wrap changes\n nothing. It is here because the confirmation row one release earlier did\n overflow when it gained a third button, off the left edge and outside its own\n card, and the difference between the two rows is only that this one's labels\n are icons today. */\n.message-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n /* Negative, and that is the point. The answer group is a flex column with its\n own gap, so a positive margin here pushes the row further from the message\n it acts on than the next card is below it -- the buttons then read as\n belonging to whatever follows. Pulling back inside the gap is what makes\n them the message's own. */\n margin-top: -6px;\n}\n\n/* The row's controls are icon-only, so the box is the whole target. Sized from\n a variable a host can raise, with a floor rather than a fixed height: the\n compact density shrinks the font, and a target that shrinks with it lands\n under the 24px minimum that makes a control reliably tappable. It used to,\n at roughly 20px square. */\n.message-action {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n min-width: var(--_action-size);\n min-height: var(--_action-size);\n padding: 4px;\n border: none;\n border-radius: 6px;\n font: inherit;\n line-height: 1.2;\n cursor: pointer;\n background: transparent;\n color: var(--_muted);\n opacity: 0.75;\n /* The tooltip below is positioned against this box. */\n position: relative;\n}\n\n.message-action:hover,\n.message-action:focus-visible {\n opacity: 1;\n background: var(--_border);\n}\n\n.message-action-icon {\n display: inline-flex;\n width: var(--_action-icon-size);\n height: var(--_action-icon-size);\n}\n\n.message-action-icon .glyph {\n width: 100%;\n height: 100%;\n}\n\n/* The label, drawn rather than left to the browser.\n\n A title attribute is the usual answer and covers only half the readers: it\n never appears on keyboard focus, so tabbing onto an icon-only control shows\n nothing at all. The attribute stays for the pointer users who expect it, and\n this shows the same words on hover and on focus alike.\n\n Left-aligned rather than centred because the row sits at the left edge of an\n answer inside a scrolling column, and a centred tooltip on the first control\n is clipped by that column. Growing rightward keeps it inside.\n\n Not exposed to assistive technology: the button already carries the same\n string as its accessible name, and this would be a second copy of it. */\n.message-action::after {\n content: attr(data-tooltip);\n position: absolute;\n bottom: calc(100% + 4px);\n left: 0;\n z-index: 3;\n padding: 3px 6px;\n border-radius: 4px;\n background: var(--_tooltip-bg);\n color: var(--_tooltip-fg);\n font-size: 11px;\n line-height: 1.4;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n transition: opacity var(--_motion) var(--_ease);\n}\n\n.message-action:hover::after,\n.message-action:focus-visible::after {\n opacity: 1;\n}\n\n/* Touch has no hover to reveal it, and a tooltip that latches open under a\n finger covers the answer it belongs to. */\n@media (hover: none) {\n .message-action::after {\n content: none;\n }\n}\n\n/* Touch. Separate from the width breakpoint in the small-viewport placement\n rules on purpose: width decides the layout, the pointer decides which\n controls make sense, and a touch laptop is coarse-pointered and wide while a\n narrow desktop window is fine-pointered and small. */\n@media (pointer: coarse) {\n /* A 6px edge strip is not a control, it is a trap that eats a scroll. The\n corners are 14px, still under the 24px floor a target is meant to clear,\n and the panel has other ways to be resized on a device that has a pointer\n precise enough to grab one. */\n .resize-handle {\n display: none;\n }\n\n /* Platform guidance is 44pt on iOS and 48dp on Android. These sit at 28-30px,\n which clears the WCAG minimum and misses both. */\n :host {\n --_action-size: var(--ag-ui-action-size, 44px);\n --_tool-btn-size: var(--ag-ui-tool-btn-size, 44px);\n --_send-size: var(--ag-ui-send-size, 44px);\n /* Missed the first time these were raised, which left the header -- the\n widget's primary controls, and the only way to reach history, a new chat\n or the collapse -- at half the size of everything beside it. */\n --_header-btn-size: var(--ag-ui-header-btn-size, 44px);\n --_header-gap: var(--ag-ui-header-gap, 6px);\n }\n\n /* iOS Safari zooms the page when a control under 16px takes focus, which\n drags the whole fixed panel with it and leaves the user pinching back out\n of a chat they only wanted to type into. The composer inherits the widget\n font, which is 14px by default and 13px at compact density, so it has to\n say 16 outright -- and only ever upward, so a host that has deliberately\n set something larger keeps it. */\n .input {\n font-size: max(16px, var(--_font-size));\n }\n}\n\n.message-action[aria-pressed=\"true\"] {\n opacity: 1;\n color: var(--_accent);\n}\n\n.message-action--confirmed {\n opacity: 1;\n color: var(--_accent);\n}\n`;\n", "// Messages: the answer well, incoming-text animations, rendered markdown,\n// code blocks and their copy button, tables, and the pending dots.\nexport const MESSAGE_STYLES: string = `\n/* \u2500\u2500 Answer group / well \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One .answer per assistant turn wraps the streamed text, its tool cards,\n and the pending indicator so a whole answer reads (and can be boxed) as one\n unit. A flex column on the message-list gap, stretched to the list width so\n its children keep their own left/right alignment. data-answer-well opts into\n the bordered \"well\"; without it the turn renders as a flat stack. */\n.answer {\n display: flex;\n flex-direction: column;\n gap: var(--_space);\n align-self: stretch;\n min-width: 0;\n}\n\n:host([data-answer-well]) .answer {\n padding: var(--_pad);\n background: var(--_well-bg);\n border: 1px solid var(--_well-border);\n border-radius: var(--_well-radius);\n}\n\n.message {\n max-width: 80%;\n padding: var(--_msg-pad);\n border-radius: var(--_msg-radius);\n line-height: 1.4;\n white-space: pre-wrap;\n /* overflow-wrap, not word-break, and the difference is the whole reason a\n markdown table used to be unreadable.\n\n Both stop one long unbroken token blowing out the bubble, which is all this\n is for. But word-break: break-word is the legacy spelling of \"break\n anywhere\", and breaking anywhere drops the *min-content* width of every\n descendant to one character. A table's column algorithm takes min-content\n as an input, so the table always fitted max-width: 100%, the overflow-x:\n auto below it never had anything to scroll, and the columns absorbed the\n pressure by rendering one letter per line instead. A seven-column header\n came out 162px tall.\n\n overflow-wrap: break-word breaks a word only when it would otherwise\n overflow its line, and leaves min-content alone -- so the bubble is still\n protected and the table is free to be wider than the panel and scroll. */\n overflow-wrap: break-word;\n}\n\n/* \u2500\u2500 Incoming-text animations (data-text-animation) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* .message--restored (rehydrated history) is excluded: entrance animations are\n for freshly-arriving messages, not the whole transcript replaying on reload.\n Word mode is excluded implicitly \u2014 restored bubbles aren't wrapped. */\n:host([data-text-animation=\"fade\"]) .message--assistant:not(.message--restored) {\n animation: ag-ui-msg-fade 0.25s ease both;\n}\n\n@keyframes ag-ui-msg-fade {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: none; }\n}\n\n.message--assistant .word {\n animation: ag-ui-word-in 0.3s ease both;\n animation-delay: calc(var(--ag-ui-word-index, 0) * 35ms);\n}\n\n@keyframes ag-ui-word-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n :host([data-text-animation=\"fade\"]) .message--assistant,\n .message--assistant .word {\n animation: none;\n }\n}\n\n.message--user {\n align-self: flex-end;\n background: var(--_user-bg);\n color: var(--_user-fg);\n border-bottom-right-radius: 4px;\n}\n\n.message--assistant {\n align-self: flex-start;\n background: var(--_assistant-bg);\n border-bottom-left-radius: 4px;\n /* Assistant bubbles hold rendered markdown/HTML, so collapse the source\n whitespace the renderer leaves between block tags. */\n white-space: normal;\n}\n\n/* Rendered-markdown elements inside an assistant bubble. */\n.message--assistant > :first-child {\n margin-top: 0;\n}\n\n.message--assistant > :last-child {\n margin-bottom: 0;\n}\n\n.message--assistant p,\n.message--assistant ul,\n.message--assistant ol,\n.message--assistant blockquote,\n.message--assistant pre {\n margin: 0.5em 0;\n}\n\n.message--assistant ul,\n.message--assistant ol {\n padding-left: 1.3em;\n}\n\n.message--assistant a {\n color: var(--_accent);\n text-decoration: underline;\n}\n\n.message--assistant code {\n font-family: ui-monospace, \"SF Mono\", Menlo, monospace;\n font-size: 0.92em;\n background: rgba(127, 127, 127, 0.16);\n padding: 1px 4px;\n border-radius: 4px;\n}\n\n.message--assistant pre {\n padding: 8px 10px;\n overflow: auto;\n background: var(--_bg);\n border: 1px solid var(--_border);\n border-radius: 6px;\n}\n\n.message--assistant pre code {\n background: none;\n padding: 0;\n}\n\n/* The copy button sits inside the block, so it scrolls with wide code rather\n than floating over the bubble. Positioning is on the pre; the button only\n appears once one has been attached. */\n.message--assistant pre.has-copy {\n position: relative;\n}\n\n/* The only reader of --ag-ui-surface and --ag-ui-text. Their defaults are\n transparent and the body foreground, which is what this button rendered as\n before either token existed; changing them repaints only this control. */\n.code-copy {\n position: absolute;\n top: 4px;\n right: 4px;\n padding: 2px 8px;\n font: inherit;\n font-size: 0.75em;\n line-height: 1.6;\n color: var(--_muted);\n background: var(--_surface);\n border: 1px solid var(--_border);\n border-radius: 4px;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.12s ease;\n}\n\n/* Revealed on hover or keyboard focus. Focus matters as much as hover here:\n hidden-until-hover is invisible to a keyboard user otherwise. */\n.message--assistant pre.has-copy:hover .code-copy,\n.code-copy:focus-visible {\n opacity: 1;\n}\n\n.code-copy:hover {\n color: var(--_text);\n background: var(--_hover);\n}\n\n.code-copy[data-state=\"copied\"] {\n opacity: 1;\n color: var(--_text);\n}\n\n.code-copy[data-state=\"failed\"] {\n opacity: 1;\n color: var(--_danger, var(--_text));\n}\n\n.message--assistant blockquote {\n padding-left: 10px;\n border-left: 3px solid var(--_border);\n color: var(--_muted);\n}\n\n/* Markdown tables. table/thead/tbody/tr/th/td are all in the sanitizer's\n ALLOWED_TAGS, so an agent can emit one. A wide table must scroll inside its\n own box rather than stretch the message: the bubble is width-constrained, so\n without this the columns either crush or push the layout sideways. */\n.message--assistant table {\n display: block;\n width: fit-content;\n max-width: 100%;\n overflow-x: auto;\n border-collapse: collapse;\n font-size: 0.95em;\n}\n\n.message--assistant th,\n.message--assistant td {\n padding: 6px 10px;\n border: 1px solid var(--_border);\n text-align: left;\n vertical-align: top;\n}\n\n.message--assistant th {\n background: var(--_hover);\n font-weight: 600;\n}\n\n.pending {\n align-self: flex-start;\n display: inline-flex;\n gap: 4px;\n align-items: center;\n padding: 12px 14px;\n background: var(--_assistant-bg);\n border-radius: 14px;\n border-bottom-left-radius: 4px;\n}\n\n.pending-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--_muted);\n animation: ag-ui-pending 1.2s infinite ease-in-out both;\n}\n\n.pending-dot:nth-child(2) {\n animation-delay: 0.16s;\n}\n\n.pending-dot:nth-child(3) {\n animation-delay: 0.32s;\n}\n\n@keyframes ag-ui-pending {\n 0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }\n 40% { opacity: 1; transform: translateY(-3px); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .pending-dot {\n animation: none;\n opacity: 0.6;\n }\n}\n`;\n", "// The scrolling message list and what is positioned against it: jump to\n// latest, the quote-selection offer, the live region and the inset probe.\nexport const TRANSCRIPT_STYLES: string = `\n/* Jump-to-latest: shown only once the reader has scrolled away *and* missed\n something. Anchored to the panel rather than the list so it does not scroll\n with the content it is offering to scroll to. */\n/* The transcript's own box, and the only one whose foot is the transcript's\n foot. The panel's foot is below the composer, the chips and the footer. */\n.messages-wrap {\n position: relative;\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.jump-latest {\n position: absolute;\n left: 50%;\n transform: translateX(-50%);\n bottom: var(--_pad);\n z-index: 2;\n display: none;\n align-items: center;\n gap: 0.35em;\n padding: 0.4em 0.9em;\n border: 1px solid var(--_border);\n border-radius: 999px;\n /* A raised surface, not the panel's own background. Reusing --_bg made the\n pill the same colour as everything behind it, leaving a 1px border and a\n shadow to carry the whole affordance -- and a dark-on-dark shadow carries\n nothing. --_hover is the token that already means \"lifted off the panel\",\n and it separates in both themes without competing with the accent the send\n button owns. */\n background: var(--_hover);\n color: var(--_text);\n font: inherit;\n font-size: 0.85em;\n cursor: pointer;\n box-shadow: 0 2px 10px rgb(0 0 0 / 0.18);\n}\n\n.jump-latest[data-missed=\"true\"] {\n display: flex;\n}\n\n.jump-latest:hover {\n border-color: var(--_accent);\n}\n\n/* The offer to quote a selection. Positioned in script against the transcript\n box, which is the only ancestor whose top and foot are the transcript's --\n the same reason .jump-latest lives here. The translate is the half the\n script does not do: script sets the point the offer hangs from, CSS decides\n which corner of the offer that point is. */\n.quote-selection {\n position: absolute;\n z-index: 2;\n transform: translate(-50%, -100%);\n padding: 0.25em 0.7em;\n border: 1px solid var(--_border);\n border-radius: 999px;\n background: var(--_hover);\n color: var(--_text);\n font: inherit;\n font-size: 0.8em;\n line-height: 1.6;\n white-space: nowrap;\n cursor: pointer;\n box-shadow: 0 2px 10px rgb(0 0 0 / 0.18);\n}\n\n/* Flipped under the selection when there was no room above it. Only the\n vertical half of the translate changes: it still hangs from its own centre\n horizontally. */\n.quote-selection[data-below=\"true\"] {\n transform: translate(-50%, 0);\n}\n\n.quote-selection:hover {\n border-color: var(--_accent);\n}\n\n/* Screen-reader-only status region. Off-screen rather than display:none or\n visibility:hidden, both of which take the element out of the accessibility\n tree entirely -- a hidden live region announces nothing at all, which is the\n classic way this pattern is written wrong.\n\n The 1px box with clip-path, rather than width/height 0, is the shape that\n survives: a zero-sized element is dropped from the tree by some engines. */\n/* A used-value reader for the four viewport-inset tokens, and the only\n reliable one. getComputedStyle().getPropertyValue() on an unregistered\n custom property hands back the substituted token stream, not a length: it\n returns \"4rem\" verbatim, and \"calc(56px + env(safe-area-inset-top))\" as\n \"calc(56px + 0px)\" -- which parses as NaN and takes the whole inset with it.\n Padding is a real property, so the same tokens come back resolved to px.\n\n visibility rather than display: none, because a box that generates no\n layout has no used values to read. Zero-sized, absolutely positioned and\n inert, so it costs nothing but the read.\n\n The padding gives that box the size of the tokens, which a card narrower than\n one of them would scroll to reach. Scrollable overflow counts a box as its\n transform draws it, so a scale of nothing takes it out of that count on every\n side and in either direction, and leaves what is read: the padding's used values,\n and the containing block a percentage resolves against. Position fixed would add\n no scroll either, and would change that block.\n\n From its own corner, which is inside whatever holds it where the centre of the\n padding need not be: kept for an engine that counts a point with no area. Chromium\n does not, so the suite cannot pin the origin. */\n.viewport-probe {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n visibility: hidden;\n pointer-events: none;\n transform: scale(0);\n transform-origin: 0 0;\n padding: var(--_viewport-inset-top) var(--_viewport-inset-right)\n var(--_viewport-inset-bottom) var(--_viewport-inset-left);\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n overflow: hidden;\n white-space: nowrap;\n clip-path: inset(50%);\n}\n\n.messages {\n flex: 1;\n overflow-y: auto;\n /* Scrolling past the end of this must not scroll the page behind it. */\n overscroll-behavior: contain;\n /* The browser's own scroll anchoring competes with the scroller for the same\n job and wins unpredictably -- it can hold the view still exactly when we\n want to follow. Turned off so following is decided in one place. Safari\n does not implement it, which is itself a reason not to depend on it. */\n overflow-anchor: none;\n padding: var(--_pad);\n display: flex;\n flex-direction: column;\n gap: var(--_space);\n}\n`;\n", "// The shadow stylesheet, composed from one module per concern. Each module is\n// a plain string constant so the element can adopt the whole sheet without a\n// build-time CSS pipeline, and the shadow boundary scopes every class name.\n//\n// The list below is in cascade order, and that order is load-bearing: two\n// rules of equal specificity resolve by which comes later, and several\n// modules restate a state another module set at rest. A module moves in this\n// list only with a browser test that pins what the move changes. The split\n// that produced these modules moved no rule, so the composed sheet is the\n// single stylesheet it replaced: the rules and their order are unchanged and\n// only comments differ, which is also why a few small rules still sit in a\n// neighbouring concern's module.\n//\n// Every module is a template literal: a backtick or a dollar-brace inside a\n// CSS comment ends it, and tsc reports the error far from the edit.\n\nimport { CHART_STYLES } from \"./charts/chart_styles.js\";\nimport { ATTACHMENT_STYLES } from \"./composer/attachment_styles.js\";\nimport { COMPOSER_STYLES } from \"./composer/composer_styles.js\";\nimport { SKILL_STYLES } from \"./composer/skill_styles.js\";\nimport { HISTORY_STYLES } from \"./history/history_styles.js\";\nimport { APPROVAL_STYLES } from \"./interrupts/approval_styles.js\";\nimport { CONFIRMATION_STYLES } from \"./interrupts/confirmation_styles.js\";\nimport { QUESTION_STYLES } from \"./interrupts/question_styles.js\";\nimport { PLACE_STYLES } from \"./place/place_styles.js\";\nimport { COLLAPSE_STYLES } from \"./placement/collapse_styles.js\";\nimport { DOCK_STYLES } from \"./placement/dock_styles.js\";\nimport { EMBEDDED_STYLES } from \"./placement/embedded_styles.js\";\nimport { LAUNCHER_STYLES } from \"./placement/launcher_styles.js\";\nimport { PAGE_STYLES } from \"./placement/page_styles.js\";\nimport { PRESET_STYLES } from \"./placement/preset_styles.js\";\nimport { RESIZE_STYLES } from \"./placement/resize_styles.js\";\nimport { SIDEBAR_STYLES } from \"./placement/sidebar_styles.js\";\nimport { SMALL_VIEWPORT_STYLES } from \"./placement/small_viewport_styles.js\";\nimport { RUN_NOTICE_STYLES } from \"./progress/run_notice_styles.js\";\nimport { THOUGHTS_STYLES } from \"./progress/thoughts_styles.js\";\nimport { TOOL_GROUP_STYLES } from \"./progress/tool_group_styles.js\";\nimport { TOOL_STEP_STYLES } from \"./progress/tool_step_styles.js\";\nimport { FRAME_STYLES } from \"./shell/frame_styles.js\";\nimport { THEME_STYLES } from \"./shell/theme_styles.js\";\nimport { TOKEN_STYLES } from \"./shell/token_styles.js\";\nimport { CLASSIC_STYLES } from \"./themes/classic_styles.js\";\nimport { CLASSIC_TOKENS } from \"./themes/classic_tokens.js\";\nimport { CODE_TOKENS } from \"./themes/code_tokens.js\";\nimport { LEDGER_STYLES } from \"./themes/ledger_styles.js\";\nimport { LEDGER_TOKENS } from \"./themes/ledger_tokens.js\";\nimport { MODERN_STYLES } from \"./themes/modern_styles.js\";\nimport { QUIET_STYLES } from \"./themes/quiet_styles.js\";\nimport { SCHEME_STYLES } from \"./themes/scheme_styles.js\";\nimport { SOFT_STYLES } from \"./themes/soft_styles.js\";\nimport { SOFT_TOKENS } from \"./themes/soft_tokens.js\";\nimport { ATTACHMENT_CHIP_STYLES } from \"./transcript/attachment_chip_styles.js\";\nimport { GREETING_STYLES } from \"./transcript/greeting_styles.js\";\nimport { MESSAGE_ACTION_STYLES } from \"./transcript/message_action_styles.js\";\nimport { MESSAGE_STYLES } from \"./transcript/message_styles.js\";\nimport { TRANSCRIPT_STYLES } from \"./transcript/transcript_styles.js\";\n\nexport const STYLES: string = [\n // Quiet's tokens are the defaults; each theme's tokens follow, then the\n // scheme, then density, so density=\"compact\" outranks a theme's own scale.\n TOKEN_STYLES,\n CLASSIC_TOKENS,\n CODE_TOKENS,\n SOFT_TOKENS,\n LEDGER_TOKENS,\n SCHEME_STYLES,\n THEME_STYLES,\n PRESET_STYLES,\n PAGE_STYLES,\n // Ahead of the phone block and no heavier than it: a docked panel is still\n // full-bleed on a phone.\n DOCK_STYLES,\n SMALL_VIEWPORT_STYLES,\n SIDEBAR_STYLES,\n LAUNCHER_STYLES,\n EMBEDDED_STYLES,\n FRAME_STYLES,\n COLLAPSE_STYLES,\n TRANSCRIPT_STYLES,\n GREETING_STYLES,\n MESSAGE_STYLES,\n THOUGHTS_STYLES,\n TOOL_STEP_STYLES,\n RESIZE_STYLES,\n COMPOSER_STYLES,\n PLACE_STYLES,\n ATTACHMENT_STYLES,\n CHART_STYLES,\n RUN_NOTICE_STYLES,\n ATTACHMENT_CHIP_STYLES,\n CONFIRMATION_STYLES,\n MESSAGE_ACTION_STYLES,\n APPROVAL_STYLES,\n QUESTION_STYLES,\n SKILL_STYLES,\n HISTORY_STYLES,\n // The step group restates, inside a group, card rules the modules above set\n // at rest; it outweighs them rather than relying on order, and sits ahead\n // of the themes so a theme restating a group rule at equal weight wins.\n TOOL_GROUP_STYLES,\n // Each theme's structure comes last: it restates rules the modules above\n // set at rest, at equal weight. Classic and code have no structural\n // module; they are the base stylesheet, and classic adds only its\n // contrast fixes.\n CLASSIC_STYLES,\n MODERN_STYLES,\n QUIET_STYLES,\n SOFT_STYLES,\n LEDGER_STYLES,\n].join(\"\");\n", "import { STYLES } from \"../styles.js\";\n\n/**\n * Attach the stylesheet to `root` without an inline `<style>` element.\n *\n * A host with a strict `style-src` and no `'unsafe-inline'` drops an injected\n * `<style>` silently: the component mounts, functions, and renders completely\n * unstyled, with nothing in the console to point at. `adoptedStyleSheets`\n * carries no inline-style origin, so it is unaffected by that policy.\n *\n * The sheet is constructed **per call**, which is once per mounted element,\n * rather than shared at module scope. A shared sheet would additionally avoid\n * re-parsing the stylesheet once per mounted element, which is what\n * `adoptedStyleSheets` is usually reached for -- but a module-level singleton\n * is exactly what this package forbids, and the CSP defect is fixed either way.\n * Per instance is no worse than the `<style>` element it replaces, which also\n * parsed once per mount.\n *\n * `extra` is the element's `extraStyles`, adopted after the built-in sheet so\n * a host's rules win at equal specificity. They are constructed sheets too, so\n * they inherit the same CSP immunity.\n *\n * No fallback: constructible `CSSStyleSheet` is Chrome 73, Firefox 101 and\n * Safari 16.4, all below this package's browser floor (Chrome 123, Firefox\n * 120, Safari 17.5). A guard here would be code no supported browser can\n * reach, and the only way to keep it would be to exempt it from the coverage\n * gate.\n */\nexport function adoptStyles(root: ShadowRoot, extra: readonly CSSStyleSheet[] = []): CSSStyleSheet {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(STYLES);\n root.adoptedStyleSheets = [sheet, ...extra];\n return sheet;\n}\n", "/**\n * Build a header control button: a named slot a host can project markup into,\n * with the built-in glyph (static SVG markup from `constants.ts`) as the slot's\n * fallback.\n *\n * The slot is what lets a host replace the mark with its own `<img>` or\n * `<svg>` rather than only restyle it through the `part`; the same\n * slot-with-fallback idiom the header icon uses.\n */\nexport function headerButton(modifier: string, label: string, glyph: string): HTMLButtonElement {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.className = `header-btn header-btn--${modifier}`;\n button.setAttribute(\"part\", `header-button ${modifier}-button`);\n button.title = label;\n button.setAttribute(\"aria-label\", label);\n const slot = document.createElement(\"slot\");\n slot.name = `icon-${modifier}`;\n slot.innerHTML = glyph;\n button.append(slot);\n return button;\n}\n", "/**\n * An icon holder wrapping a `<slot>` so a host can project custom markup;\n * with an `<img>` as the slot's fallback when an icon URL is configured, or\n * the given glyph markup when it is not.\n *\n * `iconUrl` is the caller's to read rather than defaulted here, because the\n * three marks answer it differently: the header's is `data-icon-url`, the\n * launcher's falls back to it from an attribute of its own, and the theme\n * toggle never takes an image at all.\n */\nexport function iconElement(\n slotName: string,\n part: string,\n fallbackGlyph: string | null,\n iconUrl: string | null,\n): HTMLSpanElement {\n const holder = document.createElement(\"span\");\n holder.className = \"icon-holder\";\n holder.setAttribute(\"part\", part);\n const slot = document.createElement(\"slot\");\n slot.name = slotName;\n if (iconUrl !== null) {\n const img = document.createElement(\"img\");\n img.className = \"icon-img\";\n img.src = iconUrl;\n img.alt = \"\";\n slot.append(img);\n } else if (fallbackGlyph !== null) {\n slot.innerHTML = fallbackGlyph;\n }\n holder.append(slot);\n return holder;\n}\n", "import {\n ICON_CHECKPOINTS,\n ICON_CHEVRON_DOWN,\n ICON_HISTORY,\n ICON_MAXIMIZE,\n ICON_NEW_CHAT,\n} from \"../../constants.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { headerButton } from \"./header_button.js\";\nimport { iconElement } from \"./icon_element.js\";\n\n/** What {@link buildHeader} needs from the element that owns the header. */\nexport interface HeaderOptions {\n /** The element itself, asked whether a host slotted an icon. */\n readonly host: HTMLElement;\n /** The title node, kept by the element so a later `title-text` can update it. */\n readonly title: HTMLElement;\n readonly titleText: string;\n readonly iconUrl: string | null;\n readonly strings: UiStrings;\n /** Whether the server indexes runs, so there is anything to continue. */\n readonly withCheckpoints: boolean;\n /** The opt-in theme toggle, or `null` when the host did not ask for one. */\n readonly themeToggle: HTMLButtonElement | null;\n readonly signal: AbortSignal;\n readonly onHistory: () => void;\n readonly onCheckpoints: () => void;\n readonly onNewChat: () => void;\n readonly onCollapse: () => void;\n readonly onMaximize: () => void;\n readonly onToggleTheme: () => void;\n}\n\n/** The header, and the one control the element still needs a handle on. */\nexport interface BuiltHeader {\n readonly header: HTMLElement;\n /**\n * The checkpoints button, built whether or not it is shown: the click-away\n * handler for the checkpoints popover has to exclude it either way.\n */\n readonly checkpoints: HTMLButtonElement;\n /** The maximize control, built detached: the element adds it where a placement offers it. */\n readonly maximize: HTMLButtonElement;\n /** The collapse control, which the maximize control is placed before. */\n readonly collapse: HTMLButtonElement;\n}\n\n/**\n * Build the panel's title bar: the optional icon, the title, the host's\n * header-actions slot, and the controls.\n *\n * Every control calls back into the element's public methods, so a host\n * chrome driving them imperatively takes exactly the path the built-in button\n * takes.\n */\nexport function buildHeader(options: HeaderOptions): BuiltHeader {\n const { strings } = options;\n const header = document.createElement(\"div\");\n header.className = \"header\";\n header.setAttribute(\"part\", \"header\");\n\n const title = options.title;\n title.className = \"header-title\";\n title.setAttribute(\"part\", \"title\");\n title.textContent = options.titleText;\n\n // Optional header icon: a slot (any markup) with a `data-icon-url` <img>\n // fallback. Rendered only when one of the two is provided, so the header has\n // no phantom gap otherwise.\n if (options.host.querySelector('[slot=\"icon\"]') !== null || options.iconUrl !== null) {\n header.append(iconElement(\"icon\", \"icon\", null, options.iconUrl));\n }\n\n // A coarse slot for host-provided header actions, between title and controls.\n const headerActions = document.createElement(\"slot\");\n headerActions.name = \"header-actions\";\n\n const controls = document.createElement(\"div\");\n controls.className = \"header-controls\";\n controls.setAttribute(\"part\", \"header-controls\");\n\n const history = headerButton(\"history\", strings.chatHistory, ICON_HISTORY);\n history.addEventListener(\"click\", options.onHistory);\n\n const checkpoints = headerButton(\"checkpoints\", strings.checkpoints, ICON_CHECKPOINTS);\n checkpoints.addEventListener(\"click\", options.onCheckpoints);\n\n const newChat = headerButton(\"new\", strings.newChat, ICON_NEW_CHAT);\n newChat.addEventListener(\"click\", options.onNewChat);\n\n // The element repaints this mark for its placement and data-collapse-icon.\n const collapse = headerButton(\"collapse\", strings.collapse, ICON_CHEVRON_DOWN);\n collapse.addEventListener(\"click\", options.onCollapse);\n\n const maximize = headerButton(\"maximize\", strings.maximize, ICON_MAXIMIZE);\n maximize.addEventListener(\"click\", options.onMaximize);\n\n // Only offered when the server actually indexes runs \u2014 without\n // `data-runs-url` there is nothing to continue and the button would open\n // a permanently empty panel.\n if (options.withCheckpoints) {\n controls.append(history, checkpoints, newChat);\n } else {\n controls.append(history, newChat);\n }\n // Optional built-in theme toggle: off unless the host opts in, so\n // it never competes with a host-supplied switch in `slot=\"header-actions\"`.\n const toggle = options.themeToggle;\n if (toggle !== null) {\n toggle.type = \"button\";\n toggle.className = \"header-btn header-btn--theme\";\n toggle.setAttribute(\"part\", \"header-button theme-toggle\");\n toggle.title = strings.toggleTheme;\n toggle.setAttribute(\"aria-label\", strings.toggleTheme);\n toggle.addEventListener(\"click\", options.onToggleTheme, { signal: options.signal });\n controls.append(toggle);\n }\n controls.append(collapse);\n header.append(title, headerActions, controls);\n return { header, checkpoints, maximize, collapse };\n}\n", "import { ICON_LAUNCHER } from \"../../constants.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { iconElement } from \"./icon_element.js\";\n\n/** The launcher's parts, owned by the element, and what fills them. */\nexport interface LauncherOptions {\n readonly launcher: HTMLButtonElement;\n readonly badge: HTMLElement;\n readonly railLabel: HTMLElement;\n /** The bottom bar's wrapper, which holds the launcher and the history button. */\n readonly bar: HTMLElement;\n /** The bottom bar's history button, a sibling of the launcher in the bar. */\n readonly barHistory: HTMLButtonElement;\n /** The place beside the title, which its owner shows and hides. */\n readonly barPlace: HTMLElement;\n readonly titleText: string;\n readonly iconUrl: string | null;\n readonly strings: UiStrings;\n readonly signal: AbortSignal;\n readonly onOpen: () => void;\n readonly onHistory: () => void;\n}\n\n/**\n * Build what a collapsed widget shrinks to: a round floating button, the slim\n * edge rail under `placement=\"sidebar\"`, or the strip along the bottom edge\n * under `collapse-to=\"bar\"` -- one element, shaped by the stylesheet. The\n * element mounts the bar wrapper as a sibling of the panel, so it survives the\n * panel being hidden.\n *\n * The wrapper is there for the bar's history button: a button cannot nest in\n * a button, so the strip is the launcher and the history button side by side.\n * Outside the bar the wrapper draws no box and the history button is not\n * drawn, so the launcher lays out against the host exactly as it did alone.\n */\nexport function buildLauncher(options: LauncherOptions): void {\n const { launcher, badge, railLabel, bar, barHistory, barPlace } = options;\n launcher.className = \"launcher\";\n launcher.type = \"button\";\n launcher.setAttribute(\"part\", \"launcher\");\n launcher.setAttribute(\"aria-label\", options.strings.expand);\n badge.className = \"launcher-badge\";\n badge.setAttribute(\"part\", \"launcher-badge\");\n // The count is announced through the launcher's own label, so the badge is\n // decoration to a screen reader rather than a second, context-free number.\n badge.setAttribute(\"aria-hidden\", \"true\");\n badge.hidden = true;\n // Only the edge rail shows this. A full-height column carrying one small\n // icon reads as a coloured stripe rather than a way back into a\n // conversation -- it is the widest collapsed state there is and the one\n // that says least about itself. Written here and hidden in CSS everywhere\n // else, because the launcher is one element shaped by placement.\n railLabel.className = \"rail-label\";\n railLabel.setAttribute(\"part\", \"rail-label\");\n railLabel.setAttribute(\"aria-hidden\", \"true\");\n railLabel.textContent = options.titleText;\n launcher.replaceChildren(\n iconElement(\"launcher\", \"launcher-icon\", ICON_LAUNCHER, options.iconUrl),\n railLabel,\n badge,\n );\n launcher.addEventListener(\"click\", options.onOpen, { signal: options.signal });\n bar.className = \"dock-bar\";\n bar.setAttribute(\"part\", \"bar\");\n barHistory.className = \"bar-history\";\n barHistory.type = \"button\";\n barHistory.setAttribute(\"part\", \"bar-history\");\n barHistory.title = options.strings.chatHistory;\n barHistory.setAttribute(\"aria-label\", options.strings.chatHistory);\n // A glyph rather than the header's icon slot: a slot name may appear once\n // per shadow root, and the header's history button already holds it.\n const glyph = document.createElement(\"span\");\n glyph.className = \"bar-history-glyph\";\n glyph.setAttribute(\"aria-hidden\", \"true\");\n glyph.textContent = \"\\u2630\";\n barHistory.replaceChildren(glyph);\n barHistory.addEventListener(\"click\", options.onHistory, { signal: options.signal });\n bar.replaceChildren(launcher, barPlace, barHistory);\n}\n", "import {\n ICON_CHEVRON_DOWN,\n ICON_CHEVRON_LEFT,\n ICON_CHEVRON_RIGHT,\n ICON_CHEVRON_UP,\n ICON_PANEL_CLOSE_LEFT,\n ICON_PANEL_CLOSE_RIGHT,\n} from \"../../constants.js\";\n\n/**\n * The collapse control's mark for the element's `data-collapse-icon`,\n * `placement` and `data-side`, read live by the caller.\n *\n * Unset, or a value it does not name, follows the placement: a docked column\n * (`sidebar`, and the undocumented `side`) hides sideways into its edge, so it\n * takes the panel mark, and everything else -- the corners, `full`,\n * `embedded`, an unknown placement -- keeps the chevron down. The panel mark\n * points into the edge the panel docks to, so it is mirrored for either docked\n * placement on `data-side=\"left\"`, whether it was chosen or defaulted. The\n * chevrons are absolute.\n */\nexport function collapseGlyph(\n choice: string | null,\n placement: string | null,\n side: string | null,\n): string {\n switch (choice) {\n case \"chevron-up\":\n return ICON_CHEVRON_UP;\n case \"chevron-down\":\n return ICON_CHEVRON_DOWN;\n case \"chevron-left\":\n return ICON_CHEVRON_LEFT;\n case \"chevron-right\":\n return ICON_CHEVRON_RIGHT;\n }\n const docked = placement === \"sidebar\" || placement === \"side\";\n if (choice !== \"panel-close\" && !docked) {\n return ICON_CHEVRON_DOWN;\n }\n return docked && side === \"left\" ? ICON_PANEL_CLOSE_LEFT : ICON_PANEL_CLOSE_RIGHT;\n}\n", "/**\n * Whether the launcher's unread badge is shown.\n *\n * The unread badge, unlike every other affordance here, is on by default:\n * a collapsed widget is the one state where an answer can arrive with nothing\n * on screen to say so. `data-unread-badge=\"false\"` turns it off for a host\n * that drives its own chrome from the `ag-ui-unread` event.\n */\nexport function isUnreadBadgeEnabled(element: Element): boolean {\n return element.getAttribute(\"data-unread-badge\") !== \"false\";\n}\n", "/**\n * The launcher's own image URL. `data-launcher-icon-url` lets the collapsed\n * button carry a different mark from the header's \u2014 a product logo reads at\n * 22px in a header bar but rarely at 26px in a circle \u2014 and falls back to the\n * header icon so a single `data-icon-url` still feeds both.\n */\nexport function readLauncherIconUrl(element: Element): string | null {\n return element.getAttribute(\"data-launcher-icon-url\") ?? element.getAttribute(\"data-icon-url\");\n}\n", "/** What a copied message puts on the clipboard, in both flavours. */\nexport interface CopyPayload {\n /** The plain-text flavour, structured so a table survives a paste. */\n readonly text: string;\n /** The rich flavour, so a table pastes as a table. */\n readonly html: string;\n}\n\n/** Elements whose content starts on a line of its own. */\nconst BLOCK_TAGS = new Set([\n \"ADDRESS\",\n \"ARTICLE\",\n \"ASIDE\",\n \"BLOCKQUOTE\",\n \"DD\",\n \"DIV\",\n \"DL\",\n \"DT\",\n \"FIGCAPTION\",\n \"FIGURE\",\n \"FOOTER\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n \"HEADER\",\n \"HR\",\n \"MAIN\",\n \"NAV\",\n \"OL\",\n \"P\",\n \"SECTION\",\n \"UL\",\n]);\n\n/**\n * What to copy from one rendered message, in both clipboard flavours.\n *\n * `textContent` was the obvious answer and the wrong one. It concatenates every\n * descendant with no separator at all, so a markdown table arrives as one run\n * of digits with the headers welded to the first row -- unusable in a\n * spreadsheet, and unreadable anywhere. Lists lose their bullets the same way,\n * and paragraphs run together.\n *\n * So the plain flavour is serialised structurally: table rows become tab\n * separated lines, which is the format spreadsheets parse on paste, and blocks\n * and list items get their own lines. The rich flavour carries the markup, so a\n * target that understands it -- a document, a chat client, a spreadsheet --\n * gets the real table rather than a reconstruction of one.\n *\n * Both are taken from a **clone with the component's own buttons removed**. The\n * code-block copy buttons are appended inside their own `pre`, so they are\n * descendants of the bubble and `textContent` was picking their label up: a\n * message containing a code block copied with the word for Copy sitting in the\n * middle of it.\n */\nexport function copyPayload(root: Element): CopyPayload {\n const clone = root.cloneNode(true) as Element;\n // The component's own affordances, not the message. Markdown cannot produce\n // a button, so anything matching here is chrome this element added.\n for (const control of Array.from(clone.querySelectorAll(\"button\"))) {\n control.remove();\n }\n return { text: normalise(serialise(clone)), html: clone.innerHTML };\n}\n\n/**\n * Walk a subtree into text, inserting newlines where the layout implies them.\n *\n * Nothing recurses into a `pre` or a table: both are handled whole, because\n * their text is their layout. That is also why this needs no notion of being\n * inside preformatted content -- there is no such position to be in.\n */\nfunction serialise(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) {\n // Non-null for a text node; nodeValue is nullable only on document and\n // doctype nodes, which cannot appear inside a message. Outside a pre, runs\n // of whitespace collapse to one space -- the same collapsing the renderer\n // does, so what is copied matches what is read.\n return (node.nodeValue as string).replace(/\\s+/g, \" \");\n }\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return \"\";\n }\n const element = node as Element;\n const tag = element.tagName;\n if (tag === \"BR\") {\n return \"\\n\";\n }\n if (tag === \"PRE\") {\n // Verbatim: its whitespace is its content.\n return `\\n\\n${text(element)}\\n\\n`;\n }\n if (tag === \"TABLE\") {\n return `\\n\\n${tableText(element)}\\n\\n`;\n }\n if (tag === \"UL\" || tag === \"OL\") {\n return `\\n\\n${listText(element, tag === \"OL\")}\\n\\n`;\n }\n const inner = children(element);\n return BLOCK_TAGS.has(tag) ? `\\n\\n${inner}\\n\\n` : inner;\n}\n\n/** Every child of `element`, serialised and joined. */\nfunction children(element: Element): string {\n let joined = \"\";\n for (const child of Array.from(element.childNodes)) {\n joined += serialise(child);\n }\n return joined;\n}\n\n/**\n * A list, one item per line, marked the way it is rendered.\n *\n * Built here rather than at the item, so the marker comes from the list that\n * owns it and never from an item's parent lookup -- which has a null arm no\n * message can produce.\n */\nfunction listText(list: Element, numbered: boolean): string {\n return Array.from(list.children)\n .map((item, index) => `${numbered ? `${index + 1}. ` : \"- \"}${children(item).trim()}`)\n .join(\"\\n\");\n}\n\n/**\n * A table as tab-separated rows.\n *\n * Tabs rather than a drawn grid because that is what spreadsheets parse: a\n * paste of tab-separated lines lands one value per cell, which is the whole\n * point of copying a table out of an answer.\n */\nfunction tableText(table: Element): string {\n return Array.from(table.querySelectorAll(\"tr\"))\n .map((row) =>\n Array.from(row.children)\n .map((cell) => text(cell).replace(/\\s+/g, \" \").trim())\n .join(\"\\t\"),\n )\n .join(\"\\n\");\n}\n\n/** An element's text. Never null: only documents and doctypes have none. */\nfunction text(element: Element): string {\n return element.textContent as string;\n}\n\n/** Tidy the block boundaries the walk inserted generously. */\nfunction normalise(text: string): string {\n return text\n .replace(/[^\\S\\n]+\\n/g, \"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n", "import { FEEDBACK_EVENT, ICON_RETRY, MESSAGE_ACTIONS } from \"../../constants.js\";\nimport type { AgUiMessageIds } from \"../../core/agui_client.js\";\nimport type { FeedbackDetail } from \"../../core/events/feedback_detail.js\";\nimport { commaTokens } from \"../../core/utils.js\";\nimport { copyPayload } from \"../excerpts/copy_payload.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { attachMessageActions, messageActionBar, messageActionButton } from \"./message_actions.js\";\n\n/** What the answer actions need from the element that owns them. */\nexport interface AnswerActionsHost {\n /** The custom element: its `data-message-actions`, and where feedback is dispatched. */\n readonly element: HTMLElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Retry the last turn, as the element's public `retryLastTurn` does. */\n readonly retry: () => void;\n /** The element's current conversation thread. */\n readonly threadId: () => string;\n /** Follow the transcript's foot, as every site that adds to it does. */\n readonly follow: () => void;\n}\n\n/** A finished bubble that is not an answer, and so carries no rating. */\ninterface Unrateable {\n readonly rateable: false;\n}\n\n/**\n * The action row under a finished answer -- copy, retry, feedback -- and the\n * one row currently holding Retry.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class AnswerActions {\n readonly #host: AnswerActionsHost;\n /**\n * The one action row currently carrying Retry, if any.\n *\n * Retry belongs to the **last** turn only: re-running an older one is\n * branching, and a page-driving agent's past turns clicked buttons that a\n * re-run does not undo. One owner keeps exactly one offer on screen.\n */\n #retryOwner: HTMLElement | null = null;\n\n constructor(host: AnswerActionsHost) {\n this.#host = host;\n }\n\n /** Forget the row holding Retry, with the transcript it was in. */\n forget(): void {\n this.#retryOwner = null;\n }\n\n /**\n * Give a finished assistant bubble its action row, and hand it Retry.\n *\n * Every finished bubble gets copy and feedback -- both are safe on a message\n * of any age. Retry moves to the newest, because it is the only one where\n * re-running answers the same question rather than rewriting history.\n *\n * `data-message-actions` subtracts from that. The row is built only when\n * something survives to go in it: an empty row still takes its margin, still\n * answers to the `message-actions` part, and still reads to a screen reader\n * as a group of actions with none in it.\n *\n * `message` names the answer, which is what a rating is filed under; a bubble\n * that is not an answer says so instead, and has no id to give.\n */\n attach(bubble: HTMLDivElement, message: AgUiMessageIds | Unrateable): void {\n const enabled = this.#enabled();\n const copyable = enabled.has(MESSAGE_ACTIONS.COPY);\n // A failed run is copyable -- error text is what people paste into a bug\n // report -- but not rateable: a rating is a statement about an *answer*,\n // and mixing \"the connection dropped\" into that signal makes the host's\n // feedback data say less than it did before.\n const answer = \"messageId\" in message ? message : null;\n const rateable = answer !== null && enabled.has(MESSAGE_ACTIONS.FEEDBACK);\n // Read now, not at click time: the thread the message was drawn in is the\n // one it is stored under, even if a later path kept bubbles across threads.\n const threadId = this.#host.threadId();\n if (copyable || rateable) {\n attachMessageActions(bubble, {\n strings: this.#host.strings(),\n // Read at click time, not captured: a bubble rendered from markdown\n // holds its text in the DOM, and that is what the user sees and means\n // to copy. Serialised rather than read off `textContent`, which welds\n // a table into one run of digits and picks up the code blocks' own\n // copy buttons on the way past.\n ...(copyable\n ? {\n text: () => copyPayload(bubble).text,\n html: () => copyPayload(bubble).html,\n }\n : {}),\n ...(rateable\n ? {\n onFeedback: (rating: \"up\" | \"down\") => {\n this.#host.element.dispatchEvent(\n new CustomEvent<FeedbackDetail>(FEEDBACK_EVENT, {\n detail: {\n content: copyPayload(bubble).text,\n rating,\n messageId: answer.messageId,\n threadId,\n // Omitted rather than undefined: a restored message has\n // no run, and a key holding nothing reads as one that\n // was looked up and came back empty.\n ...(answer.runId === undefined ? {} : { runId: answer.runId }),\n },\n bubbles: true,\n composed: true,\n }),\n );\n },\n }\n : {}),\n });\n }\n if (enabled.has(MESSAGE_ACTIONS.RETRY)) {\n this.#moveRetryTo(messageActionBar(bubble, this.#host.strings()));\n }\n // The row is insertion too: without this a pinned transcript rests one row short of its foot.\n this.#host.follow();\n }\n\n /** Move the Retry button onto `bar`, taking it off whoever held it. */\n #moveRetryTo(bar: HTMLElement): void {\n this.#retryOwner?.querySelector(\".message-action--retry\")?.remove();\n const retry = messageActionButton(\"retry\", this.#host.strings().retryMessage, ICON_RETRY);\n retry.addEventListener(\"click\", () => {\n this.#host.retry();\n });\n // First in the row: it is the action a reader reaches for when the answer\n // was wrong, which is when they are least inclined to hunt for a control.\n bar.prepend(retry);\n this.#retryOwner = bar;\n }\n\n /**\n * Which message actions a finished bubble offers, from\n * `data-message-actions`.\n *\n * **Absent means copy and retry, not all three.** Those two work with nothing\n * wired: copy reads the DOM, retry drives this element. The rating pair does\n * not -- it fires `ag-ui-feedback` and stores nothing by design, because a\n * rating belongs to whatever the host already uses for product signal. With no\n * listener the buttons still latch `aria-pressed`, so a reader is told their\n * rating was taken and a screen reader announces it, while nothing recorded\n * anything. This README has always said two buttons that lead nowhere are\n * worse than none; shipping them by default was that sentence being false.\n *\n * A host with a listener asks for them: `data-message-actions=\"copy,retry,feedback\"`.\n * A value names the survivors, which makes `data-message-actions=\"false\"` --\n * the spelling its sibling `data-quote-selection` uses -- an empty set by\n * falling out of the same rule rather than by a case of its own.\n */\n #enabled(): ReadonlySet<string> {\n const attr = this.#host.element.getAttribute(\"data-message-actions\");\n if (attr === null) {\n return new Set([MESSAGE_ACTIONS.COPY, MESSAGE_ACTIONS.RETRY]);\n }\n return new Set(commaTokens(attr));\n }\n}\n", "import { renderMarkdown } from \"./render_markdown.js\";\n\n/** What the streamed answer needs from the element that owns it. */\nexport interface AnswerStreamHost {\n /** Append an empty assistant bubble to the transcript, and return it. */\n readonly openBubble: () => HTMLDivElement;\n /** The element's `allowImages`, read per render. */\n readonly allowImages: () => boolean;\n /** Keep the transcript at its foot, if the reader is there. */\n readonly follow: () => void;\n}\n\n/**\n * The assistant answer currently streaming: the bubble it streams into, the\n * text the next frame will draw, and how many deltas it arrived in.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class AnswerStream {\n readonly #host: AnswerStreamHost;\n #streamingBubble: HTMLDivElement | null = null;\n // Text deltas applied to the current streaming bubble. >1 \u21D2 the message\n // revealed progressively as it streamed, so the word reveal must not re-animate\n // it; \u22641 \u21D2 it arrived at once and the word reveal is appropriate.\n #streamDeltas = 0;\n // The accumulated answer the next render will draw. Deltas overwrite it\n // (each one carries the whole answer), so a frame always draws the latest.\n #streamBuffer = \"\";\n // The frame that render is queued on, or `null` when nothing is queued \u2014\n // also the flag saying a delta is still undrawn.\n #streamFrame: number | null = null;\n\n constructor(host: AnswerStreamHost) {\n this.#host = host;\n }\n\n /** Text deltas the current answer has arrived in so far. */\n get deltas(): number {\n return this.#streamDeltas;\n }\n\n /**\n * Count one delta received. Counted per delta received, not per render: the\n * word reveal asks whether the answer *arrived* progressively, which\n * coalescing renders must not change the answer to.\n */\n countDelta(): void {\n this.#streamDeltas += 1;\n }\n\n /**\n * Queue a render of the answer so far, at most one per frame.\n *\n * Each `TEXT_MESSAGE_CONTENT` event carries the *whole* accumulated answer,\n * and drawing it means marked + DOMPurify over the entire document and a\n * wholesale replacement of the bubble's subtree. Once per token that is\n * quadratic in the answer's length \u2014 a long answer is agent-controlled, so\n * an ordinary run becomes a progressively stalling tab \u2014 and every rebuild\n * takes any selection or focus inside the bubble with it.\n *\n * A frame is the right grain: it is the fastest anything on screen can\n * change anyway, so a burst of tokens costs one parse and the text still\n * appears to flow rather than in visible chunks.\n */\n queue(buffer: string): void {\n this.#streamBuffer = buffer;\n this.#open();\n if (this.#streamFrame !== null) {\n return;\n }\n this.#streamFrame = requestAnimationFrame(() => {\n this.#streamFrame = null;\n this.into(this.#streamBuffer);\n });\n }\n\n /** Render `buffer` into the streaming bubble now, dropping any queued frame. */\n into(buffer: string): HTMLDivElement {\n // A frame still queued would otherwise fire after this and repaint the\n // bubble with whatever the last delta held \u2014 behind the buffer just drawn.\n if (this.#streamFrame !== null) {\n cancelAnimationFrame(this.#streamFrame);\n this.#streamFrame = null;\n }\n this.#streamBuffer = buffer;\n const bubble = this.#open();\n bubble.innerHTML = renderMarkdown(buffer, { allowImages: this.#host.allowImages() });\n this.#host.follow();\n return bubble;\n }\n\n /**\n * Close the current answer's streaming bubble.\n *\n * Draws a queued render first. A run that ends without a text end \u2014 a\n * cancel, an error, a round boundary \u2014 leaves the last delta sitting in the\n * queue, and simply dropping the bubble here would strand it: the partial\n * answer the user stopped mid-sentence would lose its final tokens, or be an\n * empty bubble above the stopped note.\n */\n end(): void {\n if (this.#streamFrame !== null) {\n this.into(this.#streamBuffer);\n }\n this.#streamingBubble = null;\n }\n\n /**\n * The bubble the current answer streams into, opening it on first sight.\n *\n * Opened the moment a token arrives rather than on the frame that draws it,\n * so the answer's container replaces the pending dots straight away and the\n * turn never shows a gap while the first render waits for a frame.\n */\n #open(): HTMLDivElement {\n if (this.#streamingBubble === null) {\n this.#streamingBubble = this.#host.openBubble();\n this.#streamDeltas = 0;\n }\n return this.#streamingBubble;\n }\n}\n", "import type { UiStrings } from \"../ui_strings.js\";\n\n/** The transcript's parts, owned by the element, and what fills them. */\nexport interface TranscriptOptions {\n readonly messages: HTMLElement;\n readonly jumpButton: HTMLButtonElement;\n readonly emptyWrap: HTMLElement;\n /** The greeting's text node, kept by the element so a new user name updates it. */\n readonly greetingText: HTMLElement;\n /** The starter chips, or `null` when the host configured none. */\n readonly starters: HTMLElement | null;\n readonly strings: UiStrings;\n}\n\n/**\n * Ready the message list, its jump-to-latest control and the empty state.\n *\n * The empty state is built but not put into the list: the element mounts the\n * scroller, the quote offer and the announcer first and appends it after, so\n * the scroller's observers see the list fill exactly as they always have.\n */\nexport function buildTranscript(options: TranscriptOptions): void {\n const { messages, jumpButton, emptyWrap, strings } = options;\n messages.className = \"messages\";\n messages.setAttribute(\"part\", \"messages\");\n messages.setAttribute(\"role\", \"log\");\n // NOT a live region. The streaming bubble's innerHTML is replaced inside\n // this element on every animation frame, and `role=\"log\"` already implies\n // polite announcement whose default `aria-relevant` includes text\n // additions -- so a screen reader was asked to re-announce the whole answer\n // tens of times as it streamed. `aria-live=\"off\"` is an explicit override\n // of the role's implicit value, which is why the role can stay: the log\n // semantics are what let the transcript be navigated as one, and only the\n // announcing is the defect. Status goes to the announcer instead.\n messages.setAttribute(\"aria-live\", \"off\");\n messages.setAttribute(\"aria-label\", strings.conversation);\n\n jumpButton.className = \"jump-latest\";\n jumpButton.type = \"button\";\n jumpButton.setAttribute(\"part\", \"jump-latest\");\n jumpButton.textContent = strings.jumpToLatest;\n\n // Empty-state region: a host slot at the top of the list, hidden as soon as\n // anything renders.\n emptyWrap.className = \"empty\";\n emptyWrap.setAttribute(\"part\", \"empty\");\n // The greeting heads the empty state, in a slot of its own: a host that\n // replaces the starters keeps the greeting, and a host that replaces the\n // greeting keeps the starters. A div rather than a heading, because this\n // sits inside somebody else's page, which owns the document outline.\n const greeting = document.createElement(\"div\");\n greeting.className = \"greeting\";\n greeting.setAttribute(\"part\", \"greeting\");\n const greetingSlot = document.createElement(\"slot\");\n greetingSlot.name = \"greeting\";\n greetingSlot.append(options.greetingText);\n greeting.append(greetingSlot);\n const emptySlot = document.createElement(\"slot\");\n emptySlot.name = \"empty\";\n // Fallback content, so a host that slots its own gets exactly that and\n // nothing of ours: the starters live *inside* the slot rather than beside\n // it, which is the difference between an offer and an imposition.\n if (options.starters !== null) {\n emptySlot.append(options.starters);\n }\n emptyWrap.replaceChildren(greeting, emptySlot);\n}\n", "import type { UiStrings } from \"../ui_strings.js\";\nimport { renderSuggestionChips } from \"./suggestion_chips.js\";\n\n/**\n * The prompts offered on an empty transcript, from `element`'s `data-starters`.\n *\n * Different from the suggestion chips a run pushes, which are follow-ups to\n * something already said. These answer the blank-page question instead, and\n * they are the host's rather than the model's -- only the host knows what its\n * page is for. Shares the renderer, the count and the length limit, because\n * two rows of prompt chips that behaved differently would be the harder\n * thing to explain.\n *\n * Read once at connect: it is content for a state the widget is in before\n * anything happens, and a host that wants it to change has `slot=\"empty\"`.\n *\n * Parses the attribute itself rather than through the element's JSON attribute\n * reader, because the warning is its own: it says no starters are shown and\n * gives an example of the shape, where the shared one says a built-in default\n * is in use, which for this attribute there is not.\n */\nexport function renderStarterChips(\n element: Element,\n strings: UiStrings,\n onPick: (prompt: string) => void,\n): HTMLElement | null {\n const raw = element.getAttribute(\"data-starters\");\n if (raw === null) {\n return null;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n console.warn(\n \"<ag-ui-chat>: data-starters is not valid JSON, so no starters are shown. \" +\n \"It takes an array of strings, e.g. data-starters='[\\\"Summarise this page\\\"]'.\",\n );\n return null;\n }\n return renderSuggestionChips({ prompts: parsed }, strings, onPick);\n}\n", "import type { UiStrings } from \"../ui_strings.js\";\n\n/** How long the button shows its \"copied\" confirmation before reverting. */\nconst CONFIRM_MS = 1500;\n\n/**\n * Give every fenced code block in `root` a copy button.\n *\n * Call only on finished bubbles: the streaming bubble reassigns its `innerHTML`\n * on every delta, so a button attached mid-stream is discarded and rebuilt for\n * each one.\n *\n * Idempotent \u2014 a bubble already processed is skipped, so a re-render or a second\n * call cannot stack buttons.\n */\nexport function attachCopyButtons(root: ParentNode, strings: UiStrings): void {\n for (const pre of Array.from(root.querySelectorAll(\"pre\"))) {\n const code = pre.querySelector(\"code\");\n if (code === null || pre.querySelector(\".code-copy\") !== null) {\n continue;\n }\n pre.classList.add(\"has-copy\");\n pre.append(button(code, strings));\n }\n}\n\nfunction button(code: Element, strings: UiStrings): HTMLButtonElement {\n // Never null: `textContent` is nullable only on documents and doctypes,\n // and this is always the `code` element `querySelector` just returned.\n const text = code.textContent as string;\n const copy = document.createElement(\"button\");\n copy.type = \"button\";\n copy.className = \"code-copy\";\n copy.setAttribute(\"part\", \"code-copy\");\n copy.textContent = strings.copyCode;\n copy.title = strings.copyCode;\n copy.setAttribute(\"aria-label\", strings.copyCode);\n copy.addEventListener(\"click\", () => {\n void writeText(text).then((ok) => {\n // Report the real outcome: a button that always claims success leaves the\n // reader pasting stale clipboard content.\n confirm(copy, ok ? strings.copied : strings.copyFailed, strings);\n });\n });\n return copy;\n}\n\n/**\n * Copy `text`, reporting whether it landed. The Clipboard API needs a secure\n * context and a user gesture and is absent in some embeddings, so failure is an\n * ordinary outcome rather than an error to throw at the host page.\n */\nasync function writeText(text: string): Promise<boolean> {\n const clipboard = navigator.clipboard;\n if (clipboard === undefined) {\n return false;\n }\n try {\n await clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction confirm(copy: HTMLButtonElement, message: string, strings: UiStrings): void {\n copy.textContent = message;\n copy.dataset[\"state\"] = message === strings.copied ? \"copied\" : \"failed\";\n setTimeout(() => {\n copy.textContent = strings.copyCode;\n delete copy.dataset[\"state\"];\n }, CONFIRM_MS);\n}\n", "import { fillUiString } from \"../fill_ui_string.js\";\nimport { DEFAULT_UI_STRINGS, type UiStrings } from \"../ui_strings.js\";\n\n/** Below this, a reasoning block is too short to time and its header reads `thoughts`. */\nconst TIMED_FROM_MS = 1000;\n\n/**\n * A muted \"thinking\" region for a reasoning model's streamed chain-of-thought.\n *\n * Sits at the top of the current answer group. Its header reads `thinking`\n * while the model reasons, and {@link settle} stops the clock and names how\n * long it took (\"Thought for 4s\"). {@link stream} replaces the body with the\n * running buffer, which opens expanded and folds away on {@link collapse},\n * once the answer's first text token arrives.\n *\n * The header is a disclosure only while there is text behind it. A provider\n * that reasons without sending any -- redacted thinking, or reasoning with\n * its summaries off -- still opens and closes a block, and a toggle there\n * folded and unfolded an empty, ruled box. Until the buffer has text the\n * header is a plain label and the body is not drawn; the first text turns the\n * label into the toggle, and the body comes with it.\n *\n * Pure DOM. The host inserts {@link element}; all visible chrome text comes\n * from {@link UiStrings}. The clock is injectable so the timing is testable.\n */\nexport class ThoughtsBlock {\n /** The block's root element; insert this at the top of the answer group. */\n readonly element: HTMLDivElement;\n\n readonly #label: HTMLSpanElement;\n readonly #body: HTMLPreElement;\n readonly #toggle: HTMLButtonElement;\n readonly #strings: UiStrings;\n readonly #now: () => number;\n /** When the running round started, or `null` once {@link settle} stopped the clock. */\n #startedAt: number | null;\n /** The reasoning time of the rounds already settled, in milliseconds. */\n #elapsed = 0;\n #collapsed = false;\n #hasText = false;\n\n /**\n * Build the block as reasoning starts, which is when its clock starts.\n *\n * @param strings - The resolved string table.\n * @param now - The clock, in milliseconds; `performance.now` unless a test\n * supplies its own.\n */\n constructor(\n strings: UiStrings = DEFAULT_UI_STRINGS,\n now: () => number = () => performance.now(),\n ) {\n this.#strings = strings;\n this.#now = now;\n this.#startedAt = now();\n\n this.element = document.createElement(\"div\");\n this.element.className = \"thoughts\";\n this.element.setAttribute(\"part\", \"thoughts\");\n // Lets CSS animate the header while the model is still reasoning; dropped\n // when the block settles.\n this.element.setAttribute(\"data-streaming\", \"\");\n\n this.#toggle = document.createElement(\"button\");\n this.#toggle.type = \"button\";\n this.#toggle.className = \"thoughts-toggle\";\n this.#toggle.setAttribute(\"part\", \"thoughts-toggle\");\n this.#toggle.setAttribute(\"aria-expanded\", \"true\");\n\n this.#label = document.createElement(\"span\");\n this.#label.className = \"thoughts-label\";\n this.#label.setAttribute(\"part\", \"thoughts-label\");\n this.#label.textContent = strings.thinking;\n\n this.#body = document.createElement(\"pre\");\n this.#body.className = \"thoughts-body\";\n this.#body.setAttribute(\"part\", \"thoughts-body\");\n this.#body.hidden = true;\n\n this.#toggle.addEventListener(\"click\", () => {\n this.#setCollapsed(!this.#collapsed);\n });\n\n // The label stands alone until there is text for the toggle to open onto.\n this.element.append(this.#label, this.#body);\n }\n\n /**\n * A further round of reasoning in the same turn, after a tool call settled\n * the first: restart the clock and the live header. The rounds' times add\n * up. Ignored while the clock is already running.\n */\n begin(): void {\n if (this.#startedAt !== null) {\n return;\n }\n this.#startedAt = this.#now();\n this.element.setAttribute(\"data-streaming\", \"\");\n this.#label.textContent = this.#strings.thinking;\n }\n\n /** Replace the reasoning body with the running buffer (the full text so far). */\n stream(buffer: string): void {\n this.#body.textContent = buffer;\n this.#setHasText(buffer.trim() !== \"\");\n }\n\n /**\n * Stop the clock and settle the header to how long the reasoning took.\n *\n * Called when reasoning ends, or by whatever arrives first in its place --\n * the answer's text, a tool call, or the turn ending -- so the live label\n * never outlives the reasoning. Idempotent: only the first call after a\n * start counts.\n */\n settle(): void {\n if (this.#startedAt === null) {\n return;\n }\n this.#elapsed += this.#now() - this.#startedAt;\n this.#startedAt = null;\n this.element.removeAttribute(\"data-streaming\");\n this.#label.textContent =\n this.#elapsed < TIMED_FROM_MS\n ? this.#strings.thoughts\n : fillUiString(this.#strings.thoughtFor, {\n seconds: Math.round(this.#elapsed / TIMED_FROM_MS),\n });\n }\n\n /**\n * Fold the region away when the answer's first text token arrives, settling\n * the header first. Idempotent, since the per-token text handler calls it\n * repeatedly.\n */\n collapse(): void {\n this.settle();\n if (this.#collapsed) {\n return;\n }\n this.#setCollapsed(true);\n }\n\n /** Swap the header between the plain label and the toggle around it. */\n #setHasText(hasText: boolean): void {\n if (hasText === this.#hasText) {\n return;\n }\n this.#hasText = hasText;\n if (hasText) {\n this.#toggle.append(this.#label);\n this.element.prepend(this.#toggle);\n } else {\n this.#toggle.remove();\n this.element.prepend(this.#label);\n }\n this.#setCollapsed(this.#collapsed);\n }\n\n #setCollapsed(collapsed: boolean): void {\n this.#collapsed = collapsed;\n this.#body.hidden = collapsed || !this.#hasText;\n this.#toggle.setAttribute(\"aria-expanded\", String(!collapsed));\n }\n}\n", "import {\n SUBAGENT_PHASE,\n TOOL_CALL_STATUS,\n TOOL_GROUP_DISPLAY,\n type ToolGroupDisplayMode,\n} from \"../../constants.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\n\n/** What a group says about itself, read by the shadow CSS from `data-state`. */\ntype GroupState = \"waiting\" | \"running\" | \"done\" | \"error\";\n\n/** The statuses a step is still open in. */\nconst OPEN_STATUSES: ReadonlySet<string> = new Set([\n TOOL_CALL_STATUS.PENDING,\n TOOL_CALL_STATUS.DEFERRED,\n]);\n\n/**\n * A sub-agent panel still working, by the phase it stamps on itself. A panel\n * outlives the delegation it drew, so a settled one does not match.\n */\nconst RUNNING_SUBAGENT = `.tool-call-subagent > .subagent:is(${[\n SUBAGENT_PHASE.STARTED,\n SUBAGENT_PHASE.TOOL_CALL,\n SUBAGENT_PHASE.TOOL_RESULT,\n]\n .map((phase) => `[data-phase=\"${phase}\"]`)\n .join(\", \")})`;\n\n/** One step of the group: its card, and its label as the row names it. */\ninterface Step {\n readonly element: HTMLElement;\n readonly name: string;\n readonly label: string;\n}\n\n/**\n * The attributes the row is drawn from: each card's `data-status`, its\n * `data-asking` while a question or a confirmation is open on it, its\n * `data-has-result` once a result with text arrived, and the `data-phase` and\n * `data-agent` a sub-agent panel stamps on itself inside the card that\n * delegated to it. Watched rather than told, so a step settled, asked about or\n * delegated by any path updates the row without the group being called.\n */\nconst WATCHED_ATTRIBUTES: readonly string[] = [\n \"data-status\",\n \"data-asking\",\n \"data-has-result\",\n \"data-phase\",\n \"data-agent\",\n];\n\n/**\n * Whether a lone step's card has anything to show under the row, which hides\n * the card's own head: arguments, a result with text, an approval prompt (drawn\n * while the call is deferred) or a sub-agent's progress. Which of the first two\n * the inner display draws decides which count: inline draws no arguments, and\n * minimal draws neither, so a call is not offered over what it would not show.\n */\nfunction hasDetails(card: HTMLElement, display: ToolGroupDisplayMode): boolean {\n const minimal = display === TOOL_GROUP_DISPLAY.MINIMAL;\n const args = !minimal && display !== TOOL_GROUP_DISPLAY.INLINE;\n return (\n (args && card.hasAttribute(\"data-has-args\")) ||\n (!minimal && card.hasAttribute(\"data-has-result\")) ||\n card.getAttribute(\"data-status\") === TOOL_CALL_STATUS.DEFERRED ||\n card.querySelector(\".tool-call-subagent > *\") !== null\n );\n}\n\n/**\n * Consecutive tool calls folded into one quiet row, \"Worked through 5 steps\",\n * with the per-call cards one click down. Built by the transcript for each run\n * of calls when the element's `toolDisplay` is `grouped`.\n *\n * The group owns no state of its own beyond its nodes and two facts: each\n * step's label, and whether it has already opened itself for the current wait.\n * Everything else is read back off the cards each time one changes.\n *\n * It opens itself while a step waits on the user, because a deferred step\n * carries its approval prompt inside its card and a folded group would hide\n * the very question it is asking. Once per wait, so the user can fold it\n * again. A running sub-agent does not open it: the row names the sub-agent\n * instead, beside the running mark.\n */\nexport class ToolStepGroup {\n readonly element: HTMLDivElement;\n readonly #strings: UiStrings;\n readonly #display: () => ToolGroupDisplayMode;\n readonly #list: HTMLDivElement;\n readonly #head: HTMLButtonElement;\n readonly #label: HTMLSpanElement;\n readonly #meta: HTMLSpanElement;\n /** The steps, in order. Cards only ever join a group, so this is its list's children. */\n readonly #steps: Step[] = [];\n /** Whether the group has already opened itself for the current wait. */\n #openedForWait = false;\n\n constructor(strings: UiStrings, display: () => ToolGroupDisplayMode) {\n this.#strings = strings;\n this.#display = display;\n this.element = document.createElement(\"div\");\n this.element.className = \"tool-group\";\n this.element.setAttribute(\"part\", \"tool-group\");\n this.element.setAttribute(\"data-open\", \"false\");\n\n this.#head = document.createElement(\"button\");\n this.#head.type = \"button\";\n this.#head.className = \"tool-group-head\";\n this.#head.setAttribute(\"part\", \"tool-group-head\");\n this.#head.setAttribute(\"aria-expanded\", \"false\");\n\n const icon = document.createElement(\"span\");\n icon.className = \"tool-group-icon\";\n icon.setAttribute(\"part\", \"tool-group-icon\");\n icon.setAttribute(\"aria-hidden\", \"true\");\n\n this.#label = document.createElement(\"span\");\n this.#label.className = \"tool-group-label\";\n this.#label.setAttribute(\"part\", \"tool-group-label\");\n\n this.#meta = document.createElement(\"span\");\n this.#meta.className = \"tool-group-meta\";\n this.#meta.setAttribute(\"part\", \"tool-group-meta\");\n\n const chevron = document.createElement(\"span\");\n chevron.className = \"tool-group-chevron\";\n chevron.setAttribute(\"aria-hidden\", \"true\");\n\n this.#head.append(icon, this.#label, this.#meta, chevron);\n this.#head.addEventListener(\"click\", () => {\n this.setOpen(this.element.getAttribute(\"data-open\") !== \"true\");\n });\n\n this.#list = document.createElement(\"div\");\n this.#list.className = \"tool-group-list\";\n this.#list.setAttribute(\"part\", \"tool-group-list\");\n\n this.element.append(this.#head, this.#list);\n\n new MutationObserver(() => {\n this.refresh();\n }).observe(this.#list, {\n attributes: true,\n attributeFilter: [...WATCHED_ATTRIBUTES],\n subtree: true,\n });\n }\n\n /**\n * Add a card's element as the group's next step, under the label the card\n * was built with.\n *\n * A step whose label an earlier step already has gets a repeat ordinal,\n * \"Fill field (2)\", in an element of its own beside the card's name. The\n * name itself is never rewritten, so a group flattened back into per-call\n * cards by a card display mode shows exactly the label the card was built\n * with, and the CSS hides the ordinal there.\n */\n add(card: HTMLElement, name: string): void {\n const seen = this.#steps.filter((step) => step.name === name).length + 1;\n let label = name;\n if (seen > 1) {\n const repeat = document.createElement(\"span\");\n repeat.className = \"tool-call-repeat\";\n repeat.setAttribute(\"part\", \"tool-card-repeat\");\n repeat.textContent = fillUiString(this.#strings.toolStepRepeat, { n: seen });\n card.querySelector(\".tool-call-name\")?.after(repeat);\n label = `${name} ${repeat.textContent}`;\n }\n this.#steps.push({ element: card, name, label });\n this.#list.append(card);\n this.refresh();\n }\n\n /** Show or hide the per-step cards. */\n setOpen(open: boolean): void {\n this.element.setAttribute(\"data-open\", String(open));\n this.#head.setAttribute(\"aria-expanded\", String(open));\n }\n\n /**\n * Offer the row as a disclosure only while something is behind it. Several\n * steps always are, since each shows its own head; a lone step's head is not\n * drawn in the group, so the row is a label until its card has details. A\n * row that loses them, a gated call with no arguments once it is answered,\n * folds as it goes.\n */\n #setExpandable(expandable: boolean): void {\n this.#head.disabled = !expandable;\n if (expandable) {\n this.#head.setAttribute(\"aria-expanded\", this.element.getAttribute(\"data-open\") as string);\n return;\n }\n this.element.setAttribute(\"data-open\", \"false\");\n this.#head.removeAttribute(\"aria-expanded\");\n }\n\n /**\n * Open the group now, for the wait that is about to start.\n *\n * The group opens itself from its mutation observer, which runs a tick after\n * the card is marked deferred. The approval prompt is drawn, and takes focus,\n * in the same tick as the mark, while the list is still out of the layout: the\n * focus is dropped and the scroll it would cause never happens. So the caller\n * that is about to draw the prompt opens the group first, and this marks the\n * wait as already answered for, so the observer's later refresh does not open\n * it again over a user who folded it.\n */\n reveal(): void {\n this.#openedForWait = true;\n this.setOpen(true);\n }\n\n /**\n * The row's note for a running sub-agent, naming it, or `null` when no step\n * is delegating right now. Only a step that is itself still running counts.\n */\n #delegation(): string | null {\n for (const { element } of this.#steps) {\n const panel =\n element.getAttribute(\"data-status\") === TOOL_CALL_STATUS.PENDING\n ? element.querySelector(RUNNING_SUBAGENT)\n : null;\n if (panel !== null) {\n const agent = panel.getAttribute(\"data-agent\");\n return agent === null\n ? this.#strings.subAgentWorking\n : fillUiString(this.#strings.subAgentDelegatedTo, { agent });\n }\n }\n return null;\n }\n\n /** Redraw the row from the cards, for a change the cards do not announce. */\n refresh(): void {\n const strings = this.#strings;\n const steps = this.#steps;\n const statuses = steps.map((step) => step.element.getAttribute(\"data-status\") ?? \"\");\n const open = steps.filter((_, i) => OPEN_STATUSES.has(statuses[i] as string));\n const count = (status: string): number => statuses.filter((s) => s === status).length;\n const failed = count(TOOL_CALL_STATUS.ERROR);\n const declined = count(TOOL_CALL_STATUS.DECLINED);\n const deferred = count(TOOL_CALL_STATUS.DEFERRED);\n // A step is waiting on the user when its approval is pending on the server,\n // or when a question or confirmation is open on it. The second kind keeps\n // its status at running, so it is read off its own flag.\n const asking = steps.filter((step) => step.element.hasAttribute(\"data-asking\")).length;\n const waiting = deferred + asking;\n const total = steps.length;\n\n // Opens for a deferred step only. An approval renders inside its card, which\n // a folded group would hide; a question or confirmation renders beside the\n // group, in view, so there is nothing for it to open.\n if (deferred > 0 && !this.#openedForWait) {\n this.#openedForWait = true;\n this.setOpen(true);\n } else if (deferred === 0) {\n this.#openedForWait = false;\n }\n\n let state: GroupState = \"done\";\n if (waiting > 0) {\n state = \"waiting\";\n } else if (open.length > 0) {\n state = \"running\";\n } else if (failed > 0) {\n state = \"error\";\n }\n this.element.setAttribute(\"data-state\", state);\n // The state is also a part, because `::part()` takes no attribute selector;\n // the whole list is rewritten so the old modifier goes.\n this.element.setAttribute(\"part\", `tool-group tool-group-${state}`);\n this.element.setAttribute(\"data-count\", String(total));\n\n const only = total === 1 ? steps[0] : undefined;\n this.#setExpandable(only === undefined || hasDetails(only.element, this.#display()));\n if (only !== undefined) {\n this.#label.textContent = only.label;\n } else {\n const template =\n state === \"waiting\"\n ? strings.toolGroupSteps\n : state === \"running\"\n ? strings.toolGroupWorking\n : strings.toolGroupWorked;\n this.#label.textContent = fillUiString(template, { count: total });\n }\n\n const notes: string[] = [];\n const delegation = this.#delegation();\n const current = open[0];\n if (waiting > 0) {\n notes.push(fillUiString(strings.toolGroupWaiting, { count: waiting }));\n } else if (delegation !== null) {\n notes.push(delegation);\n } else if (current !== undefined && total > 1) {\n notes.push(current.label);\n }\n if (failed > 0) {\n notes.push(fillUiString(strings.toolGroupFailed, { count: failed }));\n }\n if (declined > 0) {\n notes.push(fillUiString(strings.toolGroupDeclined, { count: declined }));\n }\n this.#meta.replaceChildren(\n ...notes.map((text) => {\n const note = document.createElement(\"span\");\n note.className = \"tool-group-note\";\n note.textContent = text;\n return note;\n }),\n );\n this.#meta.hidden = notes.length === 0;\n }\n}\n", "import { TOOL_DISPLAY } from \"../../constants.js\";\nimport type { ToolDisplayMode } from \"../progress/tool_call_card.js\";\n\n/**\n * Whether a new tool call folds into a step group, given the element's\n * `toolDisplay`.\n *\n * The display mode alone decides, whatever the theme: `grouped` (the default,\n * and what an unknown value reads as) folds, and the four card modes keep\n * per-call cards. Asked as each card is built, so switching to `grouped`\n * folds only the calls drawn afterwards; switching away flattens the groups\n * already drawn, which the shadow CSS does from the host attribute.\n */\nexport function groupsToolSteps(mode: ToolDisplayMode): boolean {\n return mode === TOOL_DISPLAY.GROUPED;\n}\n", "/**\n * Call a consumer's renderer, turning a throw into \"nothing drawn\".\n *\n * `render` is consumer code -- a host's activity renderer, a tool's `render` --\n * and both call sites run inside the history replay, where a throw abandons the\n * loop and takes every later turn of the transcript with it -- silently, and\n * again on every reload. One thing that fails to draw is worth losing; the rest\n * of the conversation is not. Reported so the failure is findable rather than\n * merely survived.\n *\n * @param render - The consumer's renderer, already bound to its input.\n * @param subject - What was being drawn, for the warning: `tool <name>` or\n * `activity <type>`.\n */\nexport function renderOrWarn(render: () => Node | null, subject: string): Node | null {\n try {\n return render();\n } catch (error) {\n console.warn(`ag-ui-chat: render failed for ${subject}`, error);\n return null;\n }\n}\n", "/** Collect the text nodes under ``root`` with their parents (depth-first). */\nfunction collectTextNodes(root: Node, out: { node: Text; parent: Node }[]): void {\n for (const child of Array.from(root.childNodes)) {\n if (child.nodeType === Node.TEXT_NODE) {\n out.push({ node: child as Text, parent: root });\n } else {\n collectTextNodes(child, out);\n }\n }\n}\n\n/**\n * Wrap each word under ``root`` in `<span class=\"word\" style=\"--ag-ui-word-index: N\">`\n * so CSS can reveal them one-by-one (staggered by the index). Whitespace is\n * preserved as plain text. Used for the `word` text-animation mode on a\n * completed assistant message; pure DOM, idempotent enough to re-run.\n */\nexport function wrapWords(root: HTMLElement): void {\n const texts: { node: Text; parent: Node }[] = [];\n collectTextNodes(root, texts);\n let index = 0;\n for (const { node, parent } of texts) {\n const fragment = document.createDocumentFragment();\n for (const part of node.data.split(/(\\s+)/)) {\n if (part === \"\") {\n continue;\n }\n if (/\\s/.test(part)) {\n fragment.appendChild(document.createTextNode(part));\n continue;\n }\n const span = document.createElement(\"span\");\n span.className = \"word\";\n span.style.setProperty(\"--ag-ui-word-index\", String(index));\n span.textContent = part;\n fragment.appendChild(span);\n index += 1;\n }\n parent.replaceChild(fragment, node);\n }\n}\n", "/** A transcript that follows new content, unless the reader has other ideas. */\nexport interface StickToBottom {\n /**\n * New content arrived. Scrolls to the bottom only while following, so\n * reading older messages during a run is no longer undone on the next token.\n */\n readonly follow: () => void;\n /** Go to the bottom and resume following, whatever the reader was doing. */\n readonly jump: () => void;\n /** Whether the transcript is currently following new content. */\n readonly following: () => boolean;\n readonly dispose: () => void;\n}\n\nexport interface StickToBottomOptions {\n /** The scrolling element -- the message list. */\n readonly viewport: HTMLElement;\n /**\n * Called whenever the answer to \"should a jump-to-latest affordance show?\"\n * changes. True means the reader has scrolled away *and* has since missed\n * something; scrolling up through a settled transcript is not a reason to\n * nag.\n */\n readonly onMissedContent: (missed: boolean) => void;\n}\n\n/**\n * How close to the bottom still counts as the bottom, in CSS pixels.\n *\n * Not zero: `scrollHeight - scrollTop - clientHeight` lands on fractional\n * values under a zoom level or a fractional device pixel ratio, so an exact\n * comparison reports \"scrolled away\" for a transcript that is visibly pinned.\n */\nconst BOTTOM_SLACK_PX = 4;\n\n/**\n * Follow the foot of a scrolling transcript, and stop when the reader scrolls\n * away.\n *\n * Before this, eleven separate sites assigned `scrollTop = scrollHeight`\n * unconditionally and nothing anywhere listened for a `scroll` event -- so\n * nothing knew the reader had scrolled up, and scrolling back through a run was\n * undone by the next token. Stick-to-bottom with a jump-to-latest affordance is\n * a named primitive elsewhere for exactly this reason: shadcn ships it as\n * `MessageScroller`, AI Elements as `ConversationScrollButton`.\n *\n * **Telling a reader's scroll from our own is the whole problem**, and the\n * answer here is that it does not have to be told. A programmatic scroll only\n * ever happens while already following, and it lands at the bottom, so the\n * `scroll` event it provokes recomputes \"at the bottom\" as true and changes\n * nothing. A reader's scroll is the only kind that can move the answer.\n *\n * A `ResizeObserver` covers the case scroll events cannot see: the *viewport*\n * changing size. Resizing the panel, or the keyboard opening on a phone, moves\n * the foot without anything scrolling and without any content arriving, so a\n * pinned transcript would silently come unpinned.\n *\n * \u26A0 It does **not** cover content that grows after insertion -- an image\n * decoding, a chart laying out. A `ResizeObserver` on a scroll container does\n * not fire when its `scrollHeight` changes, so catching that means observing\n * every child, and the payoff is one late nudge in a case the reader can fix by\n * scrolling. Insertion itself is covered: every site that adds to the\n * transcript calls {@link StickToBottom.follow}.\n */\nexport function createStickToBottom({\n viewport,\n onMissedContent,\n}: StickToBottomOptions): StickToBottom {\n let isFollowing = true;\n let missed = false;\n\n const atBottom = (): boolean =>\n viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <= BOTTOM_SLACK_PX;\n\n const setMissed = (next: boolean): void => {\n if (next === missed) {\n return;\n }\n missed = next;\n onMissedContent(missed);\n };\n\n const toBottom = (): void => {\n viewport.scrollTop = viewport.scrollHeight;\n };\n\n const onScroll = (): void => {\n isFollowing = atBottom();\n if (isFollowing) {\n setMissed(false);\n }\n };\n\n const follow = (): void => {\n if (isFollowing) {\n toBottom();\n return;\n }\n setMissed(true);\n };\n\n // Passive: this listener never calls preventDefault, and saying so keeps it\n // off the critical path of a scroll it has no intention of blocking.\n viewport.addEventListener(\"scroll\", onScroll, { passive: true });\n\n const observer = new ResizeObserver(() => {\n if (isFollowing) {\n toBottom();\n }\n });\n observer.observe(viewport);\n\n return {\n follow,\n jump: (): void => {\n isFollowing = true;\n setMissed(false);\n toBottom();\n },\n following: (): boolean => isFollowing,\n dispose: (): void => {\n viewport.removeEventListener(\"scroll\", onScroll);\n observer.disconnect();\n },\n };\n}\n", "import { MESSAGE_ROLE, type ToolGroupDisplayMode, X_SUMMARY_KEY } from \"../../constants.js\";\nimport type { AgUiToolCall } from \"../../core/agui_client.js\";\nimport type { MessageRole } from \"../../core/message_role.js\";\nimport { skillNameFrom } from \"../../skills/skill_name_from.js\";\nimport type { ChartRenderer, ClientTool } from \"../../tools/client_tool_registry.js\";\nimport { attachCopyButtons } from \"../excerpts/attach_copy_buttons.js\";\nimport { fillUiString } from \"../fill_ui_string.js\";\nimport { prettifyToolName } from \"../progress/prettify_tool_name.js\";\nimport { renderRunNotice } from \"../progress/run_notice.js\";\nimport { ThoughtsBlock } from \"../progress/thoughts_block.js\";\nimport {\n ToolCallCard,\n type ToolDisplayMode,\n type ToolPayload,\n} from \"../progress/tool_call_card.js\";\nimport { ToolStepGroup } from \"../progress/tool_step_group.js\";\nimport type { UiStrings } from \"../ui_strings.js\";\nimport { groupsToolSteps } from \"./groups_tool_steps.js\";\nimport { renderMarkdown } from \"./render_markdown.js\";\nimport { renderOrWarn } from \"./render_or_warn.js\";\nimport { wrapWords } from \"./reveal_words.js\";\nimport { createStickToBottom, type StickToBottom } from \"./stick_to_bottom.js\";\n\n/** What the transcript needs from the element that owns it. */\nexport interface TranscriptHost {\n /** The custom element: its text-animation attribute, and the `data-empty` stamp. */\n readonly element: HTMLElement;\n /** The scrolling message list. */\n readonly messages: HTMLDivElement;\n /** The empty-state region at the top of the list. */\n readonly emptyWrap: HTMLDivElement;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** The element's `allowImages`, read per render. */\n readonly allowImages: () => boolean;\n /** Resolve a frontend tool by name, for its `x-summary`. */\n readonly resolveTool: (name: string) => ClientTool | null;\n /** The element's `toolSummaries`, read per card. */\n readonly toolSummaries: () => Record<string, string>;\n /** The server catalog's label for a tool, if it sent one. */\n readonly serverSummary: (name: string) => string | undefined;\n /** The element's `formatToolPayload`, asked per region of a card. */\n readonly formatToolPayload: (payload: ToolPayload) => Node | string | null;\n /** The element's `toolDisplay`, read per card: it decides whether calls fold into a step group. */\n readonly toolDisplay: () => ToolDisplayMode;\n /** The element's `toolGroupDisplay`, read per row: it decides what a lone step offers. */\n readonly toolGroupDisplay: () => ToolGroupDisplayMode;\n}\n\n/**\n * The transcript: the bubbles, the open answer group, the pending dots, the\n * reasoning region, the tool cards by call id, and the scroller that follows\n * the foot.\n *\n * The hub most other parts of the element draw into, so it holds only the\n * transcript's own state and asks the element for nothing but configuration.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class Transcript {\n readonly #host: TranscriptHost;\n /** Tool-call cards awaiting execution, keyed by call id. */\n readonly #toolCards = new Map<string, ToolCallCard>();\n /** Card elements by call id, so a rendering handler can find its own card. */\n readonly #cardElements = new Map<string, HTMLElement>();\n /**\n * Cards whose call is being run, by call id. A card leaves the awaiting ones\n * the moment its call is dispatched, and a handler that opens a prompt on its\n * own card is still running long after, so it is found here.\n */\n readonly #running = new Map<string | undefined, ToolCallCard>();\n /**\n * Call ids whose card was already settled from a streamed server-side result\n * (`TOOL_CALL_RESULT`), so the post-run executeTool sweep doesn't overwrite\n * the real output with the generic \"executed on the server\" fallback.\n */\n readonly #serverSettled = new Set<string>();\n /** Follows the foot of the transcript, and stops when the reader scrolls away. */\n #scroller!: StickToBottom;\n #pending: HTMLDivElement | null = null;\n // The current assistant turn's grouping container. One `.answer`\n // wraps everything a single answer produces \u2014 streamed text, tool cards, the\n // pending indicator \u2014 so it can be boxed as one \"well\" by CSS. Opened on the\n // turn's first run start, closed at settle, so it spans the whole multi-round\n // frontend-tool loop (which is several AG-UI runs), not one run. `null`\n // between turns; user bubbles never enter it.\n #currentGroup: HTMLDivElement | null = null;\n // The current turn's streamed-reasoning region, shown at the top of\n // the answer group while a reasoning model thinks and collapsed once the\n // answer's first text token arrives. `null` outside a reasoning turn.\n #thoughts: ThoughtsBlock | null = null;\n /** The step group behind each group element, so a new card can find its run. */\n readonly #stepGroups = new WeakMap<Element, ToolStepGroup>();\n /**\n * An empty comment after each step group that has rendered output, which\n * every later output is placed before, so a group's outputs come out in call\n * order. Every card of a round joins its group before any handler runs, so\n * placing each output straight after the group would put the newest first;\n * and a marker rather than the last output, because an output may be a\n * fragment, which leaves nothing behind to place the next one after.\n */\n readonly #groupEnds = new WeakMap<Element, Comment>();\n /**\n * The step group element each placed output belongs to. A tool's own output\n * does not end its group: the next call joins the group above it. Without\n * that, replay -- which draws each restored call's output before the next\n * call's card -- would split a run the live stream drew as one group.\n */\n readonly #outputGroups = new WeakMap<Node, Element>();\n\n constructor(host: TranscriptHost) {\n this.#host = host;\n }\n\n /**\n * Start following the foot of the list, and wire the jump button to it.\n * Called while rendering rather than at construction: the viewport has to\n * exist and the observer has to have something to observe. The button\n * outlives a connection, so its listener goes under `signal`.\n */\n mountScroller(jumpButton: HTMLButtonElement, signal: AbortSignal): void {\n jumpButton.addEventListener(\n \"click\",\n () => {\n this.jump();\n },\n { signal },\n );\n this.#scroller = createStickToBottom({\n viewport: this.#host.messages,\n onMissedContent: (missed) => {\n jumpButton.dataset[\"missed\"] = String(missed);\n },\n });\n }\n\n /** Stop following, when the element leaves the document. */\n disposeScroller(): void {\n this.#scroller.dispose();\n }\n\n /** Keep the list at its foot, if the reader is there. */\n follow(): void {\n this.#scroller.follow();\n }\n\n /** Go to the foot, whether or not the reader had scrolled away. */\n jump(): void {\n this.#scroller.jump();\n }\n\n /** Whether the empty-state region is showing, which is when nothing else is. */\n isEmpty(): boolean {\n return !this.#host.emptyWrap.hidden;\n }\n\n /** The card drawn for a call id, while it is still awaiting execution. */\n card(callId: string): ToolCallCard | undefined {\n return this.#toolCards.get(callId);\n }\n\n /** Every card still awaiting execution. */\n cards(): IterableIterator<ToolCallCard> {\n return this.#toolCards.values();\n }\n\n /** Stop tracking a call's card as awaiting execution. */\n forgetCard(callId: string): void {\n this.#toolCards.delete(callId);\n }\n\n /** Remember the element a call's card is, for a renderer to place itself against. */\n setCardElement(callId: string, element: HTMLElement): void {\n this.#cardElements.set(callId, element);\n }\n\n /** Record that a call's card was settled from a streamed server-side result. */\n markServerSettled(callId: string): void {\n this.#serverSettled.add(callId);\n }\n\n /** Whether a call's card was settled from a streamed server-side result. */\n isServerSettled(callId: string): boolean {\n return this.#serverSettled.has(callId);\n }\n\n /** Fold the reasoning region away, once the answer has begun. */\n collapseThoughts(): void {\n this.#thoughts?.collapse();\n }\n\n /**\n * Stop the reasoning region's clock and settle its header, when reasoning\n * ends or whatever replaces its end arrives first. A no-op without one.\n */\n settleThoughts(): void {\n this.#thoughts?.settle();\n }\n\n /**\n * Close the turn's answer group. Drop it if the turn rendered nothing\n * (e.g. a server-only round that streamed no text/card) so an opted-in\n * well leaves no empty box behind.\n */\n closeGroup(): void {\n if (this.#currentGroup !== null && this.#currentGroup.childElementCount === 0) {\n this.#currentGroup.remove();\n this.updateEmptyState();\n }\n // A turn can end with its reasoning never ended, by a stop, an error or a\n // server that sent no end, and the live label must not outlive the turn.\n this.settleThoughts();\n this.#currentGroup = null;\n this.#thoughts = null;\n }\n\n /**\n * Let go of the open turn: its group, its reasoning region, its pending dots\n * and the cards awaiting execution. The first half of wiping the transcript.\n */\n releaseTurn(): void {\n this.#currentGroup = null;\n this.#thoughts = null;\n this.hidePending();\n this.#toolCards.clear();\n }\n\n /** Forget which cards settled from the server and where each card is. */\n forgetCards(): void {\n this.#serverSettled.clear();\n this.#cardElements.clear();\n this.#running.clear();\n }\n\n /** Remember the card of a call being run, for {@link setAsking}. */\n holdRunning(callId: string, card: ToolCallCard): void {\n this.#running.set(callId, card);\n }\n\n /**\n * Say whether a prompt is open on the card of a running call. A call id of\n * none, or one no card was held for, has no card to say it on.\n */\n setAsking(callId: string | undefined, asking: boolean): void {\n this.#running.get(callId)?.setAsking(asking);\n }\n\n /** Empty the list back to its empty-state region. The last half of wiping it. */\n empty(): void {\n this.#host.messages.replaceChildren(this.#host.emptyWrap);\n this.updateEmptyState();\n }\n\n /** The bubble behind `AgUiChat.appendMessage`, whose doc is the contract. */\n append(role: MessageRole, content: string): HTMLDivElement {\n const bubble = document.createElement(\"div\");\n bubble.className = `message message--${role}`;\n bubble.setAttribute(\"part\", `message message-${role}`);\n if (role === MESSAGE_ROLE.ASSISTANT) {\n bubble.innerHTML = renderMarkdown(content, { allowImages: this.#host.allowImages() });\n // A finished bubble: rehydrated history, or a whole message appended at\n // once. The streaming bubble gets its buttons in onTextEnd instead.\n attachCopyButtons(bubble, this.#host.strings());\n this.ensureGroup().appendChild(bubble);\n } else {\n this.#currentGroup = null;\n bubble.textContent = content;\n this.#host.messages.appendChild(bubble);\n }\n this.updateEmptyState();\n // A user bubble means someone just pressed Send, which is as deliberate as\n // pressing the jump button -- so it goes to the bottom even if they had\n // scrolled away to re-read something before typing.\n if (role === MESSAGE_ROLE.USER) {\n this.jump();\n } else {\n this.follow();\n }\n return bubble;\n }\n\n /**\n * The open answer group, creating and appending it on first use. Everything a\n * single assistant turn renders (text, tool cards, the pending indicator)\n * goes inside it, so the opt-in `data-answer-well` styling can box the whole\n * turn. Idempotent across the turn's runs \u2014 it persists until the run's\n * settle closes it, see {@link closeGroup}.\n */\n ensureGroup(): HTMLDivElement {\n if (this.#currentGroup === null) {\n const group = document.createElement(\"div\");\n group.className = \"answer\";\n group.setAttribute(\"part\", \"answer\");\n this.#currentGroup = group;\n this.#host.messages.appendChild(group);\n this.updateEmptyState();\n }\n return this.#currentGroup;\n }\n\n /**\n * Word-by-word reveal for the `word` text-animation mode, applied to a\n * completed assistant bubble. `fade` is pure CSS (no JS); `none` is a no-op.\n */\n revealWords(bubble: HTMLDivElement): void {\n if (this.#host.element.getAttribute(\"data-text-animation\") === \"word\") {\n wrapWords(bubble);\n }\n }\n\n /**\n * Hide the empty-state region once the message list holds anything else, and\n * say so on the host as `data-empty`.\n *\n * Stamped on the host because the layout has to answer it: where the\n * composer sits is decided outside the list this region lives in, and no\n * selector reaches from inside the list back up to the list's siblings. It is\n * also a documented styling hook for a host's own chrome around a full-page\n * chat.\n */\n updateEmptyState(): void {\n this.#host.emptyWrap.hidden = this.#host.messages.childElementCount > 1;\n this.#host.element.toggleAttribute(\"data-empty\", !this.#host.emptyWrap.hidden);\n }\n\n /** A muted \"\u23F9 Stopped\" line in the transcript (distinct from the \u26A0\uFE0F error bubble). */\n appendStoppedNote(): void {\n const note = document.createElement(\"div\");\n note.className = \"stopped-note\";\n note.setAttribute(\"part\", \"stopped\");\n note.setAttribute(\"role\", \"status\");\n note.textContent = this.#host.strings().stopped;\n this.ensureGroup().appendChild(note);\n this.updateEmptyState();\n this.follow();\n }\n\n /**\n * Show a \"thinking\" indicator while the agent is being awaited \u2014 both the\n * silent stretch before the first token and the gap after a tool result\n * while the next round is requested. Idempotent.\n */\n showPending(): void {\n if (this.#pending !== null) {\n return;\n }\n const pending = document.createElement(\"div\");\n pending.className = \"pending\";\n pending.setAttribute(\"part\", \"pending\");\n pending.setAttribute(\"role\", \"status\");\n pending.setAttribute(\"aria-label\", this.#host.strings().thinking);\n for (let i = 0; i < 3; i += 1) {\n const dot = document.createElement(\"span\");\n dot.className = \"pending-dot\";\n pending.appendChild(dot);\n }\n this.#pending = pending;\n this.ensureGroup().appendChild(pending);\n this.updateEmptyState();\n this.follow();\n }\n\n /** Remove the pending indicator if shown. */\n hidePending(): void {\n this.#pending?.remove();\n this.#pending = null;\n }\n\n /**\n * The current turn's thoughts region, creating it (at the top of the answer\n * group, above any streamed text or tool cards) on first sight. Idempotent\n * across a turn's reasoning tokens.\n */\n showThoughts(): ThoughtsBlock {\n if (this.#thoughts === null) {\n this.#thoughts = new ThoughtsBlock(this.#host.strings());\n const group = this.ensureGroup();\n group.insertBefore(this.#thoughts.element, group.firstChild);\n this.updateEmptyState();\n this.follow();\n }\n return this.#thoughts;\n }\n\n /**\n * Render a skill notice for a `load_capability` call; ``true`` when handled.\n *\n * Shared by the live stream and history replay so the transcript looks the\n * same before and after a reload.\n */\n noticeIfSkillLoad(call: AgUiToolCall): boolean {\n const skill = skillNameFrom(call);\n if (skill === null) {\n return false;\n }\n this.appendNotice(\n \"\u2728\",\n fillUiString(this.#host.strings().usingSkill, { name: skill }),\n \"skill\",\n );\n return true;\n }\n\n /**\n * An inline notice about something the run did.\n *\n * Goes through {@link ensureGroup} like a tool card so it lands *inside* the\n * assistant turn it annotates rather than floating between turns, and does\n * the same empty-state and scroll bookkeeping afterwards.\n *\n * `undo` is offered only where the agent rearranged the user's own window --\n * see {@link renderRunNotice} for why a notice may carry that one control and\n * nothing else.\n */\n appendNotice(\n icon: string,\n text: string,\n kind: string,\n undo?: { readonly label: string; readonly onActivate: () => void },\n ): void {\n this.ensureGroup().appendChild(renderRunNotice(icon, text, kind, undo));\n this.updateEmptyState();\n this.follow();\n }\n\n /**\n * Place a tool's rendered node against its own card.\n *\n * Anchored rather than appended because a client tool's handler does not run\n * until the round is over: appending would put the node after everything the\n * model said next, visibly detached from the call that produced it, and in a\n * different order than the same transcript takes on reload. The card was\n * created inline, in the right place, so anchoring makes *when* the handler\n * runs stop mattering.\n */\n renderToolOutput(render: ChartRenderer, call: AgUiToolCall): void {\n const node = renderOrWarn(() => render(call.args), `tool ${call.name}`);\n if (node === null) {\n return;\n }\n // `after` rather than an insert-or-append branch: both callers set the card\n // element immediately before calling, and a parentless anchor makes `after`\n // a no-op, so the alternative would be a branch nothing can reach.\n //\n // A card folded into a step group has its output placed after the group\n // rather than inside it, so a chart is never hidden one click down.\n const anchor = this.#cardElements.get(call.id);\n const group = anchor?.closest(\".tool-group\");\n if (group === null || group === undefined) {\n anchor?.after(node);\n } else {\n let end = this.#groupEnds.get(group);\n if (end === undefined) {\n end = document.createComment(\"\");\n group.after(end);\n this.#groupEnds.set(group, end);\n }\n const placed = node instanceof DocumentFragment ? [...node.children] : [node];\n end.before(node);\n for (const output of placed) {\n this.#outputGroups.set(output, group);\n }\n }\n this.afterGrew();\n }\n\n /** Update the empty state and follow the foot, after the transcript grew. */\n afterGrew(): void {\n this.updateEmptyState();\n this.follow();\n }\n\n /**\n * The card for ``call``, creating and appending it on first sight.\n *\n * The run's tool-call handler creates the card (pending) during the run; the\n * tool's execution later retrieves the same card to settle it.\n */\n cardFor(call: AgUiToolCall): ToolCallCard {\n const existing = this.#toolCards.get(call.id);\n if (existing !== undefined) {\n return existing;\n }\n // Prefer the tool's own `x-summary`; then an explicit `toolSummaries`\n // entry; then the fetched server catalog (`data-tools-url`). All cover\n // server-side tools whose schema never reached the browser.\n const labelled = this.#host.resolveTool(call.name)?.parameters[X_SUMMARY_KEY];\n const summary =\n typeof labelled === \"string\"\n ? labelled\n : (this.#host.toolSummaries()[call.name] ??\n this.#host.serverSummary(call.name) ??\n prettifyToolName(call.name));\n const card = new ToolCallCard(call.name, call.args, summary, this.#host.strings(), {\n // A thunk over the live property, not the property itself: the card keeps\n // this for the life of the call, and the result region is filled when the\n // tool settles -- which can be long after a host set the hook.\n formatPayload: (payload) => this.#host.formatToolPayload(payload),\n });\n this.#toolCards.set(call.id, card);\n if (groupsToolSteps(this.#host.toolDisplay())) {\n this.#stepGroup().add(card.element, summary);\n } else {\n this.ensureGroup().appendChild(card.element);\n }\n this.updateEmptyState();\n this.follow();\n return card;\n }\n\n /** Redraw every step group's row, for a change of the inner display, which no card announces. */\n refreshStepGroups(): void {\n for (const element of this.#host.messages.querySelectorAll(\".tool-group\")) {\n this.#stepGroups.get(element)?.refresh();\n }\n }\n\n /**\n * Open the step group ``card`` sits in, at once, ahead of a prompt about to be\n * drawn inside it. A no-op for a card drawn in a card display mode, which has\n * no group.\n */\n revealStep(card: ToolCallCard): void {\n const group = card.element.closest(\".tool-group\");\n (group === null ? undefined : this.#stepGroups.get(group))?.reveal();\n }\n\n /**\n * The step group a new card joins. Consecutive cards share one, and so do\n * cards separated only by the group's own rendered output; anything else in\n * between (text, a confirmation, a question) starts the next.\n *\n * The pending dots are not skipped over: a tool call takes them down before\n * its card is drawn, so they are never what a card finds at the foot of the\n * turn.\n */\n #stepGroup(): ToolStepGroup {\n const answer = this.ensureGroup();\n const last = answer.lastElementChild;\n const existing =\n last === null ? undefined : this.#stepGroups.get(this.#outputGroups.get(last) ?? last);\n if (existing !== undefined) {\n return existing;\n }\n const group = new ToolStepGroup(this.#host.strings(), this.#host.toolGroupDisplay);\n this.#stepGroups.set(group.element, group);\n if (last === null) {\n answer.prepend(group.element);\n } else {\n last.after(group.element);\n }\n return group;\n }\n}\n", "import { renderOrWarn } from \"../ui/transcript/render_or_warn.js\";\nimport type { ActivityRegistration } from \"./activity_registration.js\";\n\n/** What the activity registry needs from the element that owns it. */\nexport interface ActivityRegistryHost {\n /** The current answer group, opening one if none is open. */\n readonly ensureGroup: () => HTMLDivElement;\n /** Update the empty state and follow the foot after the transcript grew. */\n readonly afterTranscriptGrew: () => void;\n /** Append an ambient run notice to the current group. */\n readonly appendNotice: (icon: string, text: string, kind: string) => void;\n}\n\n/**\n * The AG-UI activities this element can draw, and the blocks it drew: which\n * `activity_type`s have a renderer, which arrived with none, and the node each\n * drawn activity is on screen as.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class ActivityRegistry {\n readonly #host: ActivityRegistryHost;\n /**\n * Which `activity_type`s this element can draw, by name.\n *\n * A registry rather than a branch because `activity_type` is an open string\n * the protocol does not enumerate. The two built-ins go through it like any\n * host registration, which is the test that the seam is real.\n */\n readonly #activityRenderers = new Map<string, ActivityRegistration>();\n /** Types that arrived with nobody registered to draw them. See {@link unhandledTypes}. */\n readonly #unhandledActivityTypes = new Set<string>();\n /** Chart blocks by activity message id, so an update redraws in place. */\n readonly #activityBlocks = new Map<string, HTMLElement>();\n\n constructor(host: ActivityRegistryHost) {\n this.#host = host;\n }\n\n /** The registration behind `AgUiChat.registerActivityRenderer`, whose doc is the contract. */\n register(registration: ActivityRegistration): void {\n this.#activityRenderers.set(registration.type, registration);\n this.#unhandledActivityTypes.delete(registration.type);\n }\n\n /** Whether a renderer is registered for `activityType`. */\n has(activityType: string): boolean {\n return this.#activityRenderers.has(activityType);\n }\n\n /** The set behind `AgUiChat.unhandledActivityTypes`, whose doc is the contract. */\n unhandledTypes(): readonly string[] {\n return [...this.#unhandledActivityTypes];\n }\n\n /** Forget the drawn blocks, with the transcript they were drawn into. */\n clearBlocks(): void {\n this.#activityBlocks.clear();\n }\n\n /**\n * Draw, replace or remove one activity, whatever kind it is.\n *\n * The single path for all three routes an activity arrives by -- pushed\n * (`onActivity`), patched (`onActivityChanged`) and replayed from history --\n * which is why the renderer contract has to be pure: the same content is\n * drawn again on every thread load.\n *\n * An unregistered type draws nothing and says nothing. That is the protocol's\n * own answer -- a client that does not know a name ignores the event -- and a\n * warning here would fire on every well-behaved forward-compatible server,\n * while a placeholder would put the protocol's growth in the user's face.\n * {@link unhandledTypes} is the way to find out what arrived.\n */\n draw(messageId: string, activityType: string, content: unknown): void {\n const registration = this.#activityRenderers.get(activityType);\n if (registration === undefined) {\n this.#unhandledActivityTypes.add(activityType);\n return;\n }\n const node = renderOrWarn(() => registration.render(content), `activity ${activityType}`);\n if (node === null) {\n this.#remove(messageId, activityType, registration.removedNotice, content);\n return;\n }\n const existing = this.#activityBlocks.get(messageId);\n if (existing === undefined) {\n this.#host.ensureGroup().appendChild(node as HTMLElement);\n } else {\n // Replaced rather than appended: a server redrawing under the same id\n // means *this one changed*, and a second copy below the first would read\n // as two measurements instead of one that moved.\n existing.replaceWith(node);\n }\n this.#activityBlocks.set(messageId, node as HTMLElement);\n this.#host.afterTranscriptGrew();\n }\n\n /**\n * Take away an activity whose content stopped being drawable.\n *\n * Leaving the old one up is the worst available answer: it shows values that\n * have been retracted, reading as current, and a reload drops it anyway\n * because the *stored* content is the version that could not be drawn. Live\n * and reload should agree, and both should say \"gone\".\n *\n * Removing is right, but not in silence: a drawn chart that disappears with\n * no `console` call anywhere on the path is reported not as a bug but as\n * \"the charts are flaky\".\n */\n #remove(\n messageId: string,\n activityType: string,\n notice: string | undefined,\n content: unknown,\n ): void {\n const had = this.#activityBlocks.has(messageId);\n this.#activityBlocks.get(messageId)?.remove();\n this.#activityBlocks.delete(messageId);\n console.warn(\n `ag-ui-chat: activity ${messageId} (${activityType}) was not drawable and has been ` +\n \"removed. A chart's points must each be a finite JSON number; a numeric column \" +\n \"serialised as a string (a Decimal, typically) is rejected rather than coerced.\",\n content,\n );\n // Only when something was on screen: content that never drew has no\n // disappearance to explain, and a notice for every rejected push is noise.\n if (had && notice !== undefined) {\n this.#host.appendNotice(\"\\u{1F4C9}\", notice, \"chart-undrawable\");\n }\n }\n}\n", "/**\n * Read an opt-in flag attribute on `element` the way HTML reads a boolean\n * attribute.\n *\n * Present means on: bare (`data-prompt-chips`), empty (`=\"\"`), or any value\n * except the literal `\"false\"`. Comparing against `\"true\"` instead would make\n * the bare spelling every native boolean attribute uses silently disable the\n * feature it names. `=\"false\"` still turns it off.\n */\nexport function readFlag(element: Element, name: string): boolean {\n const value = element.getAttribute(name);\n return value !== null && value !== \"false\";\n}\n", "/**\n * Parse a JSON-valued attribute on `element`, saying so when it will not parse.\n *\n * `null` for an absent attribute, and `null` again for one that is not JSON --\n * but not quietly the second time. Quoting JSON inside an HTML attribute is\n * fiddly, and the result of getting it wrong is indistinguishable from the\n * feature being switched off: no chips appear, or the strings stay English,\n * with nothing anywhere saying why. That is the same failure `data-paste-attach`\n * already reports for a value it cannot read.\n *\n * Console only. A page author's typo is not the reader's business, nothing the\n * reader did was refused, and the degraded widget is still perfectly usable.\n */\nexport function readJsonAttribute(element: Element, name: string): unknown {\n const raw = element.getAttribute(name);\n if (raw === null) {\n return null;\n }\n try {\n return JSON.parse(raw);\n } catch {\n console.warn(\n `<ag-ui-chat>: ${name} is not valid JSON, so it was ignored entirely and ` +\n \"the built-in default is being used. Check the quoting -- JSON inside \" +\n \"an HTML attribute needs single quotes around the attribute value, or \" +\n \"its own double quotes escaped.\",\n );\n return null;\n }\n}\n", "import { MAX_TOOL_ROUNDS } from \"../constants.js\";\n\n/**\n * The tool-round budget from `element`'s `data-max-tool-rounds`, for one send.\n *\n * Anything unparseable becomes `NaN`, which {@link AgUiClient} rejects along\n * with a bound below one -- so the two ways of setting this are validated in\n * one place rather than agreeing by coincidence.\n */\nexport function readMaxToolRounds(element: Element): number {\n const attr = element.getAttribute(\"data-max-tool-rounds\");\n return attr === null ? MAX_TOOL_ROUNDS : Number.parseInt(attr, 10);\n}\n", "import {\n CUSTOM_AGENT_EVENT,\n INVALIDATE_CUSTOM_NAME,\n INVALIDATE_EVENT,\n MESSAGE_ROLE,\n RUN_FINISHED_EVENT,\n SUBAGENT_CUSTOM_NAME,\n TOOL_CALL_STATUS,\n} from \"../constants.js\";\nimport { attachCopyButtons } from \"../ui/excerpts/attach_copy_buttons.js\";\nimport type { RunAnnouncer } from \"../ui/progress/run_announcer.js\";\nimport type { SubAgentProgress } from \"../ui/progress/subagent_progress.js\";\nimport type { AnswerActions } from \"../ui/transcript/answer_actions.js\";\nimport type { AnswerStream } from \"../ui/transcript/answer_stream.js\";\nimport type { Transcript } from \"../ui/transcript/transcript.js\";\nimport type { UiStrings } from \"../ui/ui_strings.js\";\nimport type { ActivityRegistry } from \"./activity_registry.js\";\nimport type { AgUiClientHandlers } from \"./agui_client.js\";\nimport type { CustomAgentDetail } from \"./events/custom_agent_detail.js\";\nimport type { InvalidateDetail } from \"./events/invalidate_detail.js\";\nimport type { RunFinishedDetail } from \"./events/run_finished_detail.js\";\nimport type { ToolRun } from \"./events/tool_run.js\";\nimport type { MessageRole } from \"./message_role.js\";\nimport { toolStatusFromOutcome } from \"./tool_outcome.js\";\n\n/** What the run's event handlers need from the element that owns them. */\nexport interface RunHandlersHost {\n /** The custom element, which the run's events are dispatched on. */\n readonly element: HTMLElement;\n /** The transcript the run draws into. */\n readonly transcript: Transcript;\n /** The answer streaming into its bubble. */\n readonly stream: AnswerStream;\n /** The action row under each finished answer. */\n readonly actions: AnswerActions;\n /** The activity renderers, and the blocks they drew. */\n readonly activities: ActivityRegistry;\n /** A delegated sub-agent's progress, on the card that delegated. */\n readonly subagents: SubAgentProgress;\n /** The screen-reader status region. */\n readonly announcer: RunAnnouncer;\n /** The resolved string table. */\n readonly strings: () => UiStrings;\n /** Whether an interaction is already in flight, which the composer owns. */\n readonly running: () => boolean;\n /** Swap the composer between Send and Stop; settling sends a queued turn. */\n readonly setRunning: (running: boolean) => void;\n /** The element's `appendMessage`, which a failed run's bubble opens through. */\n readonly appendMessage: (role: MessageRole, content: string) => HTMLDivElement;\n /** Note an assistant answer finished on `threadId`, which may be unseen. */\n readonly noteUnread: (threadId: string) => void;\n}\n\n/**\n * What one conversation's runs accumulate for the host between an\n * interaction's first round and its settle.\n *\n * A record per conversation rather than fields on the controller, because a\n * run can outlive the conversation it belongs to. Cancelling is a request, not\n * an ending: a stopped run reports how it ended once its request has closed --\n * or once a host tool's handler, which cancelling cannot interrupt, has\n * returned -- and by then New chat may have cleared the transcript and the next\n * message may already be running. Each handler table keeps the record it was\n * built with, so that report describes the run that made it and nothing the\n * next conversation did.\n */\ninterface RunLedger {\n /**\n * Tool calls made during the current interaction, in the order they started,\n * so {@link RUN_FINISHED_EVENT} can report them once the whole thing settles.\n * Spans tool rounds and an approval interrupt; emptied when the event fires.\n */\n readonly tools: { readonly id: string; readonly name: string }[];\n /**\n * Which of those calls had a result streamed back, and so ran on the server.\n *\n * Kept here rather than read from the transcript's cards, because New chat\n * clears the transcript and a run it cut off reports afterwards: a booking\n * the server made would come out as the host's own tool, which is the one\n * side the documented listener skips a refetch for.\n */\n readonly serverSettled: Set<string>;\n /**\n * Keys announced during this interaction, de-duplicated in first-seen order.\n *\n * Per element, never module-level: a second mounted chat is a second run, and\n * sharing this would tell one page to refetch on the other's writes. Emptied\n * by {@link RunHandlers.#dispatchRunFinished}, which is the one place that has\n * read it.\n */\n readonly invalidated: Set<string>;\n /**\n * Whether this turn already announced how it ended.\n *\n * `onSettled` is the terminal guarantee and fires however the run ended, so\n * it is the only place that can promise the user hears *something*. But a\n * stopped or failed run has already said the truer thing from `onCancelled`\n * or `onError`, and \"assistant answered\" after \"response stopped\" is worse\n * than silence.\n */\n announcedOutcome: boolean;\n /** How the interaction ended so far; read and reset when the run-finished event fires. */\n outcome: RunFinishedDetail[\"outcome\"];\n}\n\n/** An empty ledger, for a conversation nothing has run in yet. */\nfunction emptyLedger(): RunLedger {\n return {\n tools: [],\n serverSettled: new Set<string>(),\n invalidated: new Set<string>(),\n announcedOutcome: false,\n outcome: \"completed\",\n };\n}\n\n/** Handlers with the same signatures as `table`, each doing nothing once `attached` is false. */\nfunction whileAttached<T extends object>(table: T, attached: () => boolean): T {\n const guarded: Record<string, (...args: unknown[]) => void> = {};\n for (const [name, handler] of Object.entries(table) as [string, (...args: unknown[]) => void][]) {\n guarded[name] = (...args) => {\n if (attached()) {\n handler(...args);\n }\n };\n }\n return guarded as T;\n}\n\n/**\n * The AG-UI event handlers a run is drawn by, and what one interaction\n * accumulates for the host between its first round and its settle: the tool\n * calls it made, the keys it invalidated, and whether it already said how it\n * ended.\n *\n * A controller rather than a factory. The handlers hold nothing of their own,\n * but that bookkeeping is state, and it has never belonged to one handler\n * table: a table is built per client -- the conversation's own, rebuilt after\n * a reset, and one for each checkpoint continuation -- and every table built\n * for one conversation reports into the same bookkeeping. {@link forClient}\n * still returns a fresh table per call.\n *\n * Owned one-to-one by an `<ag-ui-chat>`, and holding no state outside the\n * instance.\n */\nexport class RunHandlers {\n readonly #host: RunHandlersHost;\n /**\n * The bookkeeping of the conversation on screen. Replaced rather than\n * emptied by {@link detach}, so a table built before then keeps its own.\n */\n #ledger: RunLedger = emptyLedger();\n\n constructor(host: RunHandlersHost) {\n this.#host = host;\n }\n\n /**\n * Detach every handler table built so far, because the conversation they\n * drew into has been cleared away.\n *\n * The element calls this when it resets, having first cancelled what was\n * running. A cancelled run still ends later, and a detached table still\n * reports to the host what that run did: a run stopped part-way may already\n * have written something, and {@link RUN_FINISHED_EVENT} fires on\n * cancellation for exactly that reason. Everything else it would do -- draw a\n * stopped note, announce, put the composer back to Send, settle the pending\n * cards -- would land in a transcript and a composer that now belong to\n * another conversation, possibly mid-run, and is dropped. So is any event the\n * run streams after the reset, invalidations included: an abort closes the\n * request those would arrive on, so what a cancelled run still delivers is\n * how it ended.\n */\n detach(): void {\n this.#ledger = emptyLedger();\n }\n\n /**\n * A handler table for one AG-UI client. Every table built for the current\n * conversation draws into the same transcript and shares its bookkeeping, so\n * a continuation run reports into the interaction the user is looking at.\n *\n * `threadId` is the thread the client was built for, named on the\n * run-finished detail. Taken here rather than read when the run settles,\n * because a stopped run settles after the reset that stopped it, when the\n * thread on screen is already the next one.\n */\n forClient(threadId: string): AgUiClientHandlers {\n const ledger = this.#ledger;\n const attached = (): boolean => ledger === this.#ledger;\n const { onSettled, onError, onCancelled, ...drawing } = this.#tableFor(ledger, threadId);\n const guarded = whileAttached({ onError, onCancelled }, attached);\n return {\n ...whileAttached(drawing, attached),\n // Recorded outside the check, like the settle: a detached run's ending is\n // still true, and the ledger is the only place it can be kept for the report.\n onError: (message) => {\n ledger.outcome = \"failed\";\n guarded.onError(message);\n },\n onCancelled: () => {\n ledger.outcome = \"stopped\";\n guarded.onCancelled();\n },\n onSettled: () => {\n if (attached()) {\n onSettled();\n }\n // Last, so a listener that refetches sees a transcript that has already\n // stopped changing -- and outside the check, because what a run did is\n // true whichever conversation is on screen when it ends.\n this.#dispatchRunFinished(ledger, threadId);\n },\n };\n }\n\n /**\n * The handler table itself, recording into `ledger`. {@link forClient}\n * decides how much of it still runs once the table is detached. An answer is\n * attributed to `threadId`, the thread the client was built for.\n */\n #tableFor(ledger: RunLedger, threadId: string): AgUiClientHandlers {\n return {\n onRunStart: () => {\n // Per *round*, so guard on the turn: a run that calls three tools fires\n // this three times and the user needs telling once.\n if (!this.#host.running()) {\n ledger.announcedOutcome = false;\n this.#host.announcer.announce(this.#host.strings().announceResponding);\n }\n this.#host.setRunning(true);\n // Open the answer group on the turn's first run so the pending\n // indicator (and everything after) lands inside the well. Idempotent:\n // later rounds of the same turn reuse it.\n this.#host.transcript.ensureGroup();\n this.#host.transcript.showPending();\n },\n onReasoningStart: () => {\n // The model is thinking: swap the pending dots for a live thoughts\n // region at the top of the turn's answer group.\n this.#host.transcript.hidePending();\n // A later round in the same turn finds the region already there, and\n // restarts its clock and its live label.\n this.#host.transcript.showThoughts().begin();\n },\n onReasoningDelta: (buffer) => {\n this.#host.transcript.showThoughts().stream(buffer);\n },\n onReasoningEnd: () => {\n // Settle the header to how long it took, but leave the region expanded\n // until the answer text starts: it collapses on the first text delta.\n this.#host.transcript.settleThoughts();\n },\n onTextDelta: (buffer) => {\n this.#host.transcript.hidePending();\n // The answer has begun \u2014 fold the thoughts away so they don't crowd it.\n this.#host.transcript.collapseThoughts();\n this.#host.stream.queue(buffer);\n this.#host.stream.countDelta();\n },\n onTextEnd: (buffer, message) => {\n // A text message that carried no content is a declaration, not an\n // answer, and drawing one puts an empty bubble above every tool call.\n //\n // `TOOL_CALL_START` names the assistant message a call belongs to, and\n // a response whose first part is a tool call has no text to open that\n // message with. pydantic-ai 2.37 started opening and closing an empty\n // one there so the id names a message the stream actually announced --\n // before that it named one no event carried, which a client could only\n // answer by inventing an id of its own that matches nothing echoed\n // back. So this envelope is a correctness fix upstream, it is legal\n // AG-UI, and any server may send one.\n //\n // `ConversationHistory.replay` already declines to draw a bubble for\n // an assistant message with no text. Without the same rule\n // here the live transcript and the reloaded one disagree about the\n // same conversation, which is the harder half of the bug to notice.\n if (buffer === \"\") {\n this.#host.stream.end();\n return;\n }\n const bubble = this.#host.stream.into(buffer);\n // Only reveal word-by-word when the message arrived at once. If it\n // streamed across multiple deltas it already revealed progressively, so\n // wrapping it now would replay the finished response one word at a time.\n if (this.#host.stream.deltas <= 1) {\n this.#host.transcript.revealWords(bubble);\n }\n attachCopyButtons(bubble, this.#host.strings());\n this.#host.actions.attach(bubble, message);\n this.#host.stream.end();\n this.#host.noteUnread(threadId);\n },\n onToolCall: (call) => {\n this.#host.transcript.hidePending();\n // A call ends the reasoning before it, whether or not its end arrived,\n // and a turn of reasoning then calls has no text delta to settle it.\n this.#host.transcript.settleThoughts();\n // A skill activation is an ordinary `load_capability` tool call \u2014 the\n // deferred-capability mechanism pydantic-ai already uses \u2014 so it arrives\n // here rather than on a channel of its own. Render it as a notice and\n // *return*: falling through would show a raw tool card beside the chip,\n // which is worse than the card alone.\n if (this.#host.transcript.noticeIfSkillLoad(call)) {\n return;\n }\n // Recorded after the skill-load return: a capability load is the agent\n // arranging itself, not work a host's data could have moved under.\n ledger.tools.push({ id: call.id, name: call.name });\n this.#host.transcript.cardFor(call);\n },\n onActivity: (activityType, content, messageId) => {\n this.#host.activities.draw(messageId, activityType, content);\n },\n onCustomEvent: (name, value) => {\n if (name === INVALIDATE_CUSTOM_NAME) {\n this.#dispatchInvalidation(ledger, value);\n return;\n }\n if (name === SUBAGENT_CUSTOM_NAME) {\n this.#host.subagents.report(value);\n return;\n }\n // Straight out to the host page, uninterpreted. This is the imperative\n // carrier: whatever it means, it means it to the page, not to the\n // transcript -- so it is dispatched and deliberately not rendered,\n // persisted or replayed. A host that does not know the name simply has\n // no listener, which is the graceful outcome the open field is for.\n this.#host.element.dispatchEvent(\n new CustomEvent<CustomAgentDetail>(CUSTOM_AGENT_EVENT, {\n detail: { name, value },\n bubbles: true,\n composed: true,\n }),\n );\n },\n // The delegation's own lifetime, on the protocol's events rather than the\n // CUSTOM channel its steps ride. Both end at the same panel.\n onSubAgentStarted: (subagentRunId, agent, parentToolCallId) => {\n this.#host.subagents.start(subagentRunId, agent, parentToolCallId);\n },\n onSubAgentFinished: (subagentRunId) => {\n this.#host.subagents.finish(subagentRunId);\n },\n onSubAgentError: (subagentRunId, message) => {\n this.#host.subagents.fail(subagentRunId, message);\n },\n onMessagesSnapshot: () => {\n // Honoured for persistence and announced, not re-rendered.\n //\n // The store follows the server, because the server is authoritative\n // about what the conversation *is* -- and it would follow it anyway:\n // `@ag-ui/client` replaces `agent.messages` before any subscriber runs,\n // and the run loop persists `agent.messages`. Done in silence, the\n // screen and the store would disagree until a reload served a\n // transcript the reader had never seen.\n //\n // Not re-rendered from the snapshot: a snapshot can land mid-run, and rebuilding the\n // transcript then would destroy the in-flight run's own UI state -- the streaming\n // bubble, the open answer group, and every tool card keyed by call id,\n // some of which are still waiting on results. Telling the reader costs\n // none of that, and this is the same answer the same question already\n // got for compaction, one handler up.\n this.#host.transcript.appendNotice(\n \"\\u{1F504}\",\n this.#host.strings().historyReplaced,\n \"history-replaced\",\n );\n },\n onToolResult: (toolCallId, content, outcome) => {\n const card = this.#host.transcript.card(toolCallId);\n if (card === undefined) {\n return;\n }\n // Settled as the server says it ended, not as \"it ended\": a refusal\n // settled as DONE is a green card, and a booking the server declined\n // reads, at a glance, as a booking that was made. An absent or\n // unrecognised outcome still means DONE, so a server that never states\n // one renders every call as done.\n card.settle(toolStatusFromOutcome(outcome), content);\n this.#host.transcript.markServerSettled(toolCallId);\n ledger.serverSettled.add(toolCallId);\n // The card stops being the live thing the moment it settles, and the\n // server goes straight back to the model with the result -- a wait with\n // nothing on screen to own it, and the longest one in a run when the\n // result is a large inlined attachment being re-sent with every request.\n // The dots go back where ``onToolCall`` took them from, after the card,\n // and whatever comes next clears them: reasoning, the first text delta,\n // the round ending, or ``onSettled``'s terminal guarantee.\n //\n // Not the same case as the one ``ToolDispatch.execute`` refuses to show\n // them for. That runs after the run has ended, so there is nothing left to\n // clear them and they would hang -- which is what happened before 0.2.1\n // and is why they were removed from here too. The terminal guarantee\n // that shipped in the same release is what makes showing them safe now.\n this.#host.transcript.showPending();\n },\n onActivityChanged: (messageId, activityType, content) => {\n this.#host.activities.draw(messageId, activityType, content);\n },\n onRunEnd: () => {\n // Per-round end; the button stays on Stop until the whole interaction\n // settles \u2014 the user must be able to cancel between tool rounds.\n this.#host.transcript.hidePending();\n this.#host.stream.end();\n },\n onError: (message) => {\n ledger.announcedOutcome = true;\n this.#host.announcer.announce(this.#host.strings().announceFailed);\n this.#host.transcript.hidePending();\n const bubble = this.#host.appendMessage(MESSAGE_ROLE.ASSISTANT, `\u26A0\uFE0F ${message}`);\n bubble.classList.add(\"message--failed\");\n // A failure is the one message whose action row is only worth having\n // for Retry: there is nothing here worth copying and nothing to rate.\n // A dropped connection with no way back was the whole of the gap --\n // uploads had a retry and runs did not.\n //\n // Not a `run-notice`: that element's contract is that it \"never\n // settles, takes no action, and carries no controls\", and is explicitly\n // \"distinct from an error, which is a failure\". This is a failure, so\n // it stays an error and gains the control instead.\n this.#host.actions.attach(bubble, { rateable: false });\n this.#host.transcript.revealWords(bubble);\n this.#host.stream.end();\n },\n onCancelled: () => {\n // Deliberate stop, not a failure: keep whatever partial text already\n // streamed and add a muted note instead of an error bubble.\n ledger.announcedOutcome = true;\n this.#host.announcer.announce(this.#host.strings().announceStopped);\n this.#host.transcript.hidePending();\n this.#host.transcript.appendStoppedNote();\n this.#host.stream.end();\n },\n onSettled: () => {\n // Terminal guarantee: whatever path ended the run, return to rest.\n if (!ledger.announcedOutcome) {\n this.#host.announcer.announce(this.#host.strings().announceAnswerReady);\n }\n this.#host.transcript.hidePending();\n this.#host.setRunning(false);\n this.#host.stream.end();\n // A tool card still pending at settle would hang forever: a call Stop or\n // RUN_ERROR ended before it ran, a server tool whose result never\n // streamed because the connection dropped, an approved call Stop kept\n // from resuming. None of them finished and nobody refused them, so the\n // card says exactly that, in the words the client sends the agent for\n // the same call on the next request.\n for (const card of this.#host.transcript.cards()) {\n if (!card.settled) {\n card.settle(TOOL_CALL_STATUS.INTERRUPTED, this.#host.strings().callNotFinished);\n }\n }\n this.#host.transcript.closeGroup();\n },\n };\n }\n\n /**\n * Tell the host the interaction is over and what ran in it.\n *\n * Last thing in `onSettled`, so a listener that refetches sees a transcript\n * that has already stopped changing. `side` is read from the streamed-result\n * bookkeeping rather than from the tool list: whether a call executed on the\n * server is a fact about the run, and a name can appear on both sides across a\n * conversation.\n */\n #dispatchRunFinished(ledger: RunLedger, threadId: string): void {\n const tools: ToolRun[] = ledger.tools.map(({ id, name }) => ({\n name,\n side: ledger.serverSettled.has(id) ? \"server\" : \"client\",\n }));\n const invalidated = [...ledger.invalidated];\n ledger.tools.length = 0;\n ledger.serverSettled.clear();\n ledger.invalidated.clear();\n const outcome = ledger.outcome;\n ledger.outcome = \"completed\";\n this.#host.element.dispatchEvent(\n new CustomEvent<RunFinishedDetail>(RUN_FINISHED_EVENT, {\n detail: { threadId, tools, invalidated, outcome },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Route one invalidation to the host, and remember it for the run summary.\n *\n * Dispatched immediately rather than only at the end, because that is what\n * makes a long multi-step run feel live -- the list refreshes as the third of\n * eight writes lands. The accumulated set rides\n * {@link RUN_FINISHED_EVENT} as well, so a host that would rather refetch once\n * upgrades by reading one extra field instead of adding a listener.\n *\n * Nothing is rendered, persisted or replayed. An invalidation is an\n * imperative: it has no place in the transcript and no meaning once acted on,\n * and replaying one on every thread load would be a refetch storm. That is the\n * whole reason the server sends it as `CUSTOM` rather than as an activity.\n */\n #dispatchInvalidation(ledger: RunLedger, value: unknown): void {\n const payload = (value ?? {}) as { keys?: unknown; reason?: unknown };\n // Defensive about the payload, not about the name: `value` is typed\n // `unknown` by the protocol, so a server can put anything there, and a\n // malformed announcement must not take the run down with it.\n const keys = Array.isArray(payload.keys)\n ? payload.keys.filter((key): key is string => typeof key === \"string\")\n : [];\n if (keys.length === 0) {\n return;\n }\n for (const key of keys) {\n ledger.invalidated.add(key);\n }\n this.#host.element.dispatchEvent(\n new CustomEvent<InvalidateDetail>(INVALIDATE_EVENT, {\n detail: { keys, reason: typeof payload.reason === \"string\" ? payload.reason : null },\n bubbles: true,\n composed: true,\n }),\n );\n }\n}\n", "import { randomUUID } from \"@ag-ui/client\";\nimport {\n type ClientConversationStore,\n SessionStorageStore,\n type WriteFailureReport,\n writeStoredItem,\n} from \"./conversation_store.js\";\n\n/**\n * Storage namespaces already spoken for in this document.\n *\n * Per document rather than per origin, and released on disconnect, because the\n * question it answers is \"is another element on this page using these keys right\n * now\" \u2014 not \"has anything ever used them\". A registry that never released would\n * turn every remount, and every framework re-render that moves the node, into a\n * false collision that costs the element its own conversation.\n *\n * Module-level on purpose, and the one piece of shared mutable state the\n * repository's `CLAUDE.md` exempts from its rule against it: the question is\n * about the *other* live elements, which no instance field can answer. See the\n * three conditions recorded there before adding anything beside it.\n */\nconst CLAIMED_NAMESPACES = new Set<string>();\n\n/** What the storage scope needs from the element that owns it. */\nexport interface StorageScopeHost {\n /** The element's `id`, the namespace it prefers. */\n readonly id: () => string;\n /** The element's `endpoint`, the namespace it falls back to. */\n readonly endpoint: () => string;\n}\n\n/**\n * Which storage keys are this element's: the namespace it claims in the\n * document, the key a layout preference is stored under, and the built-in\n * conversation store scoped to it.\n *\n * Owned one-to-one by an `<ag-ui-chat>`. The one thing it shares is the record\n * of claimed namespaces above, which is what keeps two elements apart.\n */\nexport class StorageScope {\n readonly #host: StorageScopeHost;\n // Per-instance suffix for the origin-scoped storage keys (collapsed / theme /\n // size), so two instances on one origin don't clobber each other. Empty \u21D2 the\n // root keys, for an element with nothing to key on. Resolved on connect; the\n // conversation adds `user-key` on top of it, see conversationNamespace.\n #storageNs = \"\";\n // The entry this element put in CLAIMED_NAMESPACES, to take back out on\n // disconnect. `null` when it claimed nothing (no id, no endpoint, or it lost\n // the claim to an element that mounted first).\n #claimedNs: string | null = null;\n // The fallback namespace minted when the preferred one was already claimed,\n // with the preferred value it was minted for \u2014 so the element keeps it across\n // remounts, but re-resolves if the host answers the warning with an `id`.\n #generatedNs = \"\";\n #generatedFor = \"\";\n // The `sessionStorage`-backed store this scope handed out, which the element\n // may therefore re-scope on a principal change -- while it is still the store\n // in use, which rescopeStore asks, since a host can assign its own at any\n // time. `null` until connecting has met the built-in store at all. A store of\n // the host's own kind is never held here: the element does not know its\n // keying and must not guess at it.\n #builtinStore: SessionStorageStore | null = null;\n readonly #writeFailure: WriteFailureReport = { reported: false };\n\n constructor(host: StorageScopeHost) {\n this.#host = host;\n }\n\n /**\n * Resolve the per-instance storage namespace, before any key is read or\n * written, so this instance doesn't share collapsed/theme/thread state with\n * another on the same origin.\n */\n claim(): void {\n this.#storageNs = this.#claimNamespace();\n }\n\n /**\n * Give the namespace back. A disconnect is not necessarily a farewell \u2014 a\n * DOM move and a framework re-render both look like one \u2014 and an element\n * that could not reclaim its own namespace on the way back in would lose its\n * conversation to a false collision.\n */\n release(): void {\n if (this.#claimedNs !== null) {\n CLAIMED_NAMESPACES.delete(this.#claimedNs);\n this.#claimedNs = null;\n }\n }\n\n /**\n * The conversation store's namespace: this element's, scoped to the principal\n * `key` names.\n *\n * Only the conversation is principal-scoped. The panel's own collapsed / size\n * / theme preferences stay on the element's own namespace, because they are\n * this element's UI state rather than anyone's data \u2014 they carry no word of\n * what was said \u2014 and because they are read once while connecting, so\n * re-scoping them under a live element would rearrange the panel around a\n * user who had only just signed in.\n */\n conversationNamespace(key: string): string {\n return key === \"\" ? this.#storageNs : `${this.#storageNs}#${key}`;\n }\n\n /**\n * Namespace the built-in default store, and hand back the store to use. A\n * host-injected store is used verbatim; the built-in one is remembered\n * either way, because it is the element's own store and a later `user-key`\n * change may move it to another namespace.\n */\n scopeStore(store: ClientConversationStore, key: string): ClientConversationStore {\n if (!(store instanceof SessionStorageStore)) {\n return store;\n }\n const namespace = this.conversationNamespace(key);\n this.#builtinStore = namespace === \"\" ? store : new SessionStorageStore(namespace);\n return this.#builtinStore;\n }\n\n /**\n * Rebuild the built-in store under `namespace`, or `null` when `current` --\n * the store the element is using now, unwrapped from any remote it wrapped\n * it in -- is not the one this scope handed out.\n *\n * Asked of the store in use rather than of what connecting remembered,\n * because the two part company the moment a host assigns a store of its own\n * to a connected element. Remembering was enough to tell a host's store from\n * the built-in one at connect; after it, the built-in one was still\n * remembered, so a key change replaced the host's store with a fresh\n * `sessionStorage` one -- and a host that had chosen to keep message bodies\n * off the client found every one of them cached in the tab again. A store\n * the element did not make holds its data somewhere the element cannot see,\n * and has to scope itself.\n */\n rescopeStore(current: ClientConversationStore, namespace: string): SessionStorageStore | null {\n if (current !== this.#builtinStore) {\n return null;\n }\n this.#builtinStore = new SessionStorageStore(namespace);\n return this.#builtinStore;\n }\n\n /** This instance's namespaced form of an origin-scoped storage key. */\n key(base: string): string {\n return this.#storageNs === \"\" ? base : `${base}:${this.#storageNs}`;\n }\n\n /** Read a namespaced origin-scoped value. */\n readScopedItem(base: string): string | null {\n return sessionStorage.getItem(this.key(base));\n }\n\n /**\n * Read a layout preference: where the widget sits, how big it is, which\n * theme it wears.\n *\n * These live in `localStorage` rather than beside the transcript, because a\n * layout preference is not a conversation. The transcript is deliberately\n * per-tab -- two tabs are two conversations, and closing the tab ends it --\n * and everything else inherited that scoping without earning it. A user who\n * dragged the panel clear of their own UI did it again in the next tab, and\n * again after every restart.\n *\n * Whether the widget is *currently open* stays per-tab with the transcript.\n * It is a statement about this tab rather than a preference: carrying it\n * across would pop the panel open on every new tab because it was opened\n * once, somewhere else.\n *\n * Falls back to the per-tab copy, which is all a browser that denies\n * `localStorage` has.\n */\n readPreference(base: string): string | null {\n try {\n const stored = localStorage.getItem(this.key(base));\n if (stored !== null) {\n return stored;\n }\n } catch {\n // Fall through to the per-tab copy below.\n }\n return this.readScopedItem(base);\n }\n\n /**\n * Persist a layout preference as durably as this browser allows: to\n * `localStorage` so it outlives the tab, and to the per-tab store as well.\n *\n * The second write is not redundancy for its own sake. A privacy mode can\n * deny `localStorage` while allowing `sessionStorage`, and losing the\n * durable copy should degrade to the per-tab behaviour this replaced rather\n * than to no persistence at all. The read above prefers the durable copy, so\n * a tab that has both cannot be shadowed by its own stale one.\n *\n * Neither write is worth an exception. A refused per-tab write warns once\n * per scope rather than once per write, because the size path writes on\n * every step.\n */\n writePreference(base: string, value: string): void {\n const key = this.key(base);\n try {\n localStorage.setItem(key, value);\n } catch {\n // Quota, or a store that denies writes.\n }\n writeStoredItem(key, value, this.#writeFailure);\n }\n\n /** Write a per-tab value under this scope's key, sharing its one refused-write warning. */\n writeSession(base: string, value: string): void {\n writeStoredItem(this.key(base), value, this.#writeFailure);\n }\n\n /**\n * Drop a layout preference from both stores.\n *\n * The mirror of {@link writePreference}, and it has to clear both for the\n * same reason that writes both: leaving either copy behind means the value\n * comes back on the next read.\n */\n clearPreference(base: string): void {\n const key = this.key(base);\n try {\n localStorage.removeItem(key);\n } catch {\n // A store that denies access; the per-tab copy below still goes.\n }\n try {\n sessionStorage.removeItem(key);\n } catch {\n // Nothing left to do: the value was never persisted in the first place.\n }\n }\n\n /**\n * Claim this element's storage namespace: its `id`, else its `endpoint`.\n *\n * The endpoint fallback exists so a lone widget restores its conversation\n * across reloads with nothing asked of the page author. It stops working the\n * moment there are two of them \u2014 a docked support panel and an inline page\n * assistant against one agent mount, neither carrying an `id`, which nothing\n * requires \u2014 because both resolve to the same string and then share a thread\n * pointer, a drawer index and every message key. Whichever mounts second\n * adopts the first's active thread and rehydrates its transcript into its own\n * panel: one conversation's content inside another, on the same page.\n *\n * So the namespace is claimed by the first element to mount under it, and a\n * second is given one of its own plus a warning naming the fix. The first\n * element keeps the endpoint namespace, which is what leaves the ordinary\n * single-element case exactly as it was.\n *\n * The generated namespace is random rather than derived from mount order.\n * That costs the second element its history across reloads \u2014 the warning says\n * so, and an `id` fixes it \u2014 which is the honest trade against an order-based\n * name that would silently hand a stored conversation to whichever element\n * happened to mount second on the next load.\n */\n #claimNamespace(): string {\n const id = this.#host.id();\n const preferred = id !== \"\" ? id : this.#host.endpoint();\n // Nothing to key on, so the root keys: an element with neither an id nor\n // an endpoint cannot send anything, so what it would claim is an empty\n // conversation.\n if (preferred === \"\") {\n return \"\";\n }\n // Already lost this claim once. Keep the fallback rather than drifting back\n // onto a namespace the other element may since have released, which would\n // swap this panel's conversation for that one's.\n if (this.#generatedFor === preferred) {\n return this.#generatedNs;\n }\n if (!CLAIMED_NAMESPACES.has(preferred)) {\n CLAIMED_NAMESPACES.add(preferred);\n this.#claimedNs = preferred;\n return preferred;\n }\n this.#generatedFor = preferred;\n this.#generatedNs = `${preferred}~${randomUUID()}`;\n console.warn(\n `<ag-ui-chat>: another element on this page already stores its ` +\n `conversation under \"${preferred}\", so this one has been given a ` +\n \"throwaway namespace of its own \u2014 the two would otherwise share a \" +\n \"thread pointer, a history drawer and every message. Give each \" +\n \"<ag-ui-chat> its own id to keep them apart and let this one restore \" +\n \"its conversation across reloads.\",\n );\n return this.#generatedNs;\n }\n}\n", "import type { Context, Message, Tool } from \"@ag-ui/core\";\nimport {\n ATTACHMENT_EVENT,\n BAR_HEIGHT_EVENT,\n CHART_ACTIVITY_TYPE,\n COMPACTION_ACTIVITY_TYPE,\n CUSTOM_AGENT_EVENT,\n DOCK_WIDTH_EVENT,\n ICON_MAXIMIZE,\n ICON_MOON,\n ICON_RESTORE,\n ICON_SUN,\n MAXIMIZE_EVENT,\n MESSAGE_ROLE,\n PAGE_MAP_CONTEXT,\n STATE_EVENT,\n STORAGE_ROOT,\n SUBMIT_EVENT,\n SUGGESTIONS_ACTIVITY_TYPE,\n THREAD_EVENT,\n THREAD_TITLE_EVENT,\n TOGGLE_EVENT,\n TOOL_DISPLAY,\n TOOL_GROUP_DISPLAY,\n type ToolGroupDisplayMode,\n UNREAD_EVENT,\n} from \"../constants.js\";\nimport type { Skill } from \"../skills/skill.js\";\nimport { SkillCatalog } from \"../skills/skill_catalog.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type ChatCorner, type ChatSurfaceReport } from \"../tools/chat_surface_tools.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type ClientTool } from \"../tools/client_tool_registry.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type ResolvePageTarget } from \"../tools/page_action_tools.js\";\nimport { createPageMapContext, type PageMap } from \"../tools/page_map.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type PageState } from \"../tools/page_state.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type RouteMap } from \"../tools/route_map.js\";\nimport { ToolCatalog } from \"../tools/tool_catalog.js\";\nimport { ToolDispatch } from \"../tools/tool_dispatch.js\";\nimport { renderChart } from \"../ui/charts/chart_block.js\";\nimport { chartSpecFrom } from \"../ui/charts/chart_spec_from.js\";\nimport { CHART_TOOL_NAME, createChartTool } from \"../ui/charts/chart_tool.js\";\nimport { autoGrow } from \"../ui/composer/auto_grow.js\";\nimport { buildComposer } from \"../ui/composer/build_composer.js\";\nimport { ComposerAttachments } from \"../ui/composer/composer_attachments.js\";\nimport { ComposerVoice } from \"../ui/composer/composer_voice.js\";\nimport { SkillsMenu } from \"../ui/composer/skills_menu.js\";\nimport { TranscriptQuoteOffer } from \"../ui/excerpts/transcript_quote_offer.js\";\nimport { fillUiString } from \"../ui/fill_ui_string.js\";\nimport { CheckpointMenu } from \"../ui/history/checkpoint_menu.js\";\nimport { ConversationHistory } from \"../ui/history/conversation_history.js\";\nimport type { RelativeTimeFormatter } from \"../ui/history/relative_time.js\";\nimport { ThreadDrawer } from \"../ui/history/thread_drawer.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type ApprovalRenderer } from \"../ui/interrupts/approval_card.js\";\nimport { PendingDecision } from \"../ui/interrupts/pending_decision.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type QuestionRenderer } from \"../ui/interrupts/question_card.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type Place } from \"../ui/place/place.js\";\nimport { PlaceChip } from \"../ui/place/place_chip.js\";\nimport { placeFromRoute } from \"../ui/place/place_from_route.js\";\nimport { PanelPlacement } from \"../ui/placement/panel_placement.js\";\nimport { type Surface, surfaceFor } from \"../ui/placement/surface_for.js\";\nimport { RunAnnouncer } from \"../ui/progress/run_announcer.js\";\nimport { renderRunNotice } from \"../ui/progress/run_notice.js\";\nimport { SubAgentProgress } from \"../ui/progress/subagent_progress.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type ToolDisplayMode, type ToolPayloadFormatter } from \"../ui/progress/tool_call_card.js\";\nimport { adoptStyles } from \"../ui/shell/adopt_styles.js\";\nimport { buildHeader } from \"../ui/shell/build_header.js\";\nimport { buildLauncher } from \"../ui/shell/build_launcher.js\";\nimport { collapseGlyph } from \"../ui/shell/collapse_glyph.js\";\nimport { iconElement } from \"../ui/shell/icon_element.js\";\nimport { isUnreadBadgeEnabled } from \"../ui/shell/is_unread_badge_enabled.js\";\nimport { readLauncherIconUrl } from \"../ui/shell/read_launcher_icon_url.js\";\nimport { AnswerActions } from \"../ui/transcript/answer_actions.js\";\nimport { AnswerStream } from \"../ui/transcript/answer_stream.js\";\nimport { renderAttachmentChips } from \"../ui/transcript/attachment_chips.js\";\nimport { buildTranscript } from \"../ui/transcript/build_transcript.js\";\nimport { renderStarterChips } from \"../ui/transcript/starter_chips.js\";\nimport { renderSuggestionChips } from \"../ui/transcript/suggestion_chips.js\";\nimport { Transcript } from \"../ui/transcript/transcript.js\";\nimport { DEFAULT_UI_STRINGS, mergeUiStrings, type UiStrings } from \"../ui/ui_strings.js\";\nimport type { ActivityRegistration } from \"./activity_registration.js\";\nimport { ActivityRegistry } from \"./activity_registry.js\";\nimport type { ActivityRenderer } from \"./activity_renderer.js\";\nimport { AgUiClient } from \"./agui_client.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type AttachmentRef } from \"./attachment.js\";\nimport { ChatRegistration } from \"./chat_registry.js\";\nimport type { ClientSeed } from \"./client_seed.js\";\nimport {\n type ClientConversationStore,\n type NavigationCheckpoint,\n SessionStorageStore,\n type ThreadMeta,\n threadTitleFrom,\n} from \"./conversation_store.js\";\nimport { type AgentFactory, createHttpAgent } from \"./create_http_agent.js\";\nimport type { BarHeightDetail } from \"./events/bar_height_detail.js\";\nimport type { DockWidthDetail } from \"./events/dock_width_detail.js\";\nimport type { MaximizeDetail } from \"./events/maximize_detail.js\";\nimport type { StateDetail } from \"./events/state_detail.js\";\nimport type { SubmitDetail } from \"./events/submit_detail.js\";\nimport type { ThreadDetail } from \"./events/thread_detail.js\";\nimport type { ThreadTitleDetail } from \"./events/thread_title_detail.js\";\nimport type { ToggleDetail } from \"./events/toggle_detail.js\";\nimport type { UnreadDetail } from \"./events/unread_detail.js\";\nimport type { MessageRole } from \"./message_role.js\";\nimport { readFlag } from \"./read_flag.js\";\nimport { readJsonAttribute } from \"./read_json_attribute.js\";\nimport { readMaxToolRounds } from \"./read_max_tool_rounds.js\";\nimport { RemoteConversationStore } from \"./remote_conversation_store.js\";\nimport { RunHandlers } from \"./run_handlers.js\";\nimport { StorageScope } from \"./storage_scope.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type TranscribeHandler } from \"./transcribe_audio.js\";\n// biome-ignore lint/style/useImportType: the emitted declaration file copies this form\nimport { type UploadHandler } from \"./upload_attachment.js\";\nimport { warnOnCrossOriginCredentials, withCredentials } from \"./utils.js\";\n\n/**\n * Attributes read once while connecting, to decide what chrome exists at all.\n *\n * Changing one afterwards is silently ignored: the tray, the mic, the skills\n * menu and the header icon are built during connect and no later read revisits\n * the decision. Observed only so `attributeChangedCallback` can warn.\n *\n * Excludes the attributes that are re-read per use, where a late change works\n * and a warning would be wrong: `data-runs-url`, `data-page-actions`,\n * `data-text-animation`, `data-tool-display`, `endpoint`, and the CSS-reactive\n * `theme` / `collapsed` / `data-tool-group-display`.\n */\nconst CONNECT_TIME_ATTRIBUTES = [\n \"data-attachments-url\",\n \"data-attachment-accept\",\n \"data-attachment-max-bytes\",\n \"data-transcribe-url\",\n \"data-threads-url\",\n \"data-threads-cache\",\n \"data-tools-url\",\n \"data-skills-url\",\n \"data-skills\",\n \"data-prompt-chips\",\n \"data-slash-commands\",\n \"data-theme-toggle\",\n \"data-strings\",\n \"data-icon-url\",\n] as const;\n\n/**\n * The cookie policies `fetch` accepts. Anything else is a configuration\n * mistake, and one that would otherwise surface as an unexplained 401 from a\n * request the browser silently sent anonymously.\n */\nconst CREDENTIALS_MODES: readonly string[] = [\"omit\", \"same-origin\", \"include\"];\n\nconst SERVER_PLACEHOLDER_TITLE = \"New conversation\";\n\n/** What a server derives as a thread's title: the first user text, 60 code points at most. */\nfunction serverTitleFrom(messages: readonly Message[]): string {\n for (const message of messages) {\n const text =\n typeof message.content === \"string\" ? message.content.split(/\\s+/).join(\" \").trim() : \"\";\n if (message.role === \"user\" && text !== \"\") {\n const points = Array.from(text);\n return points.length <= 60 ? text : `${points.slice(0, 59).join(\"\").trimEnd()}\\u2026`;\n }\n }\n return \"\";\n}\n\n/** Whether `value` is one of the three modes `fetch` understands. */\nfunction isCredentialsMode(value: string): value is RequestCredentials {\n return CREDENTIALS_MODES.includes(value);\n}\n\n/** The `title-text` value that makes the header follow the thread on screen. */\nconst TITLE_TEXT_AUTO = \"auto\";\n\n/** The width at and below which every placement but two is the screen. */\nconst PHONE_QUERY = \"(max-width: 600px)\";\n\n/** The anchored conversation list's widest, and its distance from its button and the window. */\nconst THREADS_POPOVER_WIDTH = 320;\nconst THREADS_POPOVER_GAP = 8;\n\n/** Per-tab persistence key for the collapsed state (survives MPA reloads). */\nconst COLLAPSED_KEY = `${STORAGE_ROOT}:collapsed`;\n\n/**\n * Persistence key for the built-in theme toggle. It holds the user's scheme\n * word only: the theme name belongs to the host's markup, and one saved value\n * is restored on every page that shares the key.\n */\nconst THEME_KEY = `${STORAGE_ROOT}:theme`;\n\n/** The scheme words of the `theme` attribute; every other word names a theme. */\nconst SCHEME_WORDS: readonly string[] = [\"light\", \"dark\", \"auto\"];\n\n/**\n * The last scheme word in a saved value, or `undefined` when it names none. A\n * value saved before only the scheme was kept (`\"soft dark\"`) still gives up\n * just its scheme.\n */\nfunction savedScheme(saved: string): string | undefined {\n return saved\n .split(/\\s+/)\n .filter((word) => SCHEME_WORDS.includes(word))\n .at(-1);\n}\n\n/** `theme`'s words with its scheme word, if any, replaced by `scheme`. */\nfunction withScheme(theme: string, scheme: string): string {\n const names = theme.split(/\\s+/).filter((word) => word !== \"\" && !SCHEME_WORDS.includes(word));\n return [...names, scheme].join(\" \");\n}\n\n/**\n * The element a selector names, in the given root first and then the\n * document; null for no match, and for a selector that does not parse, which\n * is the same mistake from the host's side.\n */\nfunction findAnchor(root: Node, selector: string): Element | null {\n try {\n const scope = root instanceof ShadowRoot ? root : document;\n return scope.querySelector(selector) ?? document.querySelector(selector);\n } catch {\n return null;\n }\n}\n\n/**\n * `<ag-ui-chat>` \u2014 a framework-free chat sidebar Web Component over AG-UI.\n *\n * Owns the Shadow DOM shell (header, scrolling message list, input row),\n * builds an {@link AgUiClient} on first send via the overridable\n * {@link agentFactory}, and renders streaming assistant text plus tool-call\n * activity. Emits a {@link SUBMIT_EVENT} for host visibility.\n *\n * The per-run frontend tool catalog and context come from {@link getTools} and\n * {@link getContext}.\n */\nexport class AgUiChat extends HTMLElement {\n /** Agent factory; override to inject a custom or fake agent (tests). */\n agentFactory: AgentFactory = createHttpAgent;\n\n /**\n * Static extra HTTP headers, sent with every request this element makes: the\n * agent run, the thread index and its messages, the tool and skill catalogs,\n * the run index, uploads and transcription.\n *\n * For values fixed for the element's lifetime. A rotating credential belongs\n * in {@link getHeaders} instead \u2014 only a re-assignment updates this, so a\n * token captured here is pinned until the host assigns again.\n */\n headers: Record<string, string> = {};\n\n /**\n * Live header source, called afresh immediately before every request \u2014 the\n * way to supply rotating credentials, with nothing to re-assign or keep in\n * sync.\n *\n * Composes with {@link headers} rather than replacing it: merged per key with\n * `getHeaders()` winning, so a static `X-Client` and a rotating\n * `Authorization` are configured independently and neither drops the other.\n */\n getHeaders: (() => Record<string, string>) | null = null;\n\n /**\n * Origins, besides the page's own, that this element may send {@link headers}\n * and {@link getHeaders} credentials to without saying so on the console.\n *\n * Seven attributes name a URL, and every one of them carries these headers.\n * They are plain HTML, so a page that builds one from a query parameter or\n * from tenant-authored configuration has handed an attacker the destination,\n * and the token leaves on the element's first request. Naming the origins you\n * expect turns that from silent into either confirmed or reported.\n *\n * A notice rather than a refusal: a cross-origin agent is a documented\n * deployment, so refusing would break working installations to defend against\n * a page that is already interpolating untrusted data into its own markup.\n * Leaving this empty costs nothing but one console line per foreign origin.\n */\n trustedOrigins: readonly string[] = [];\n\n /**\n * Permit `<img>` in rendered assistant markdown. **Off by default**: a\n * model-controlled image URL is fetched with no user interaction, which\n * makes it a zero-click exfiltration channel for prompt-injected page\n * data. Enable only when the content source is trusted.\n */\n allowImages = false;\n\n /**\n * Replace the relative timestamps in the thread drawer and the checkpoint\n * panel -- `\"5m ago\"`, `\"2d ago\"` -- with the host's own formatting.\n *\n * The built-in is locale-neutral on purpose: there is no `Intl` anywhere in\n * this component, so it never disagrees with the page it is embedded in by\n * guessing a locale. That is a good default and a bad requirement, which is\n * what this is for.\n *\n * ```js\n * const rtf = new Intl.RelativeTimeFormat(\"de\", { numeric: \"auto\" });\n * chat.formatRelativeTime = (ts) =>\n * rtf.format(Math.round((ts - Date.now()) / 60000), \"minute\");\n * ```\n */\n formatRelativeTime: RelativeTimeFormatter | null = null;\n\n /** When true, destructive tools execute without a confirmation modal. */\n autoConfirm = false;\n\n /**\n * When true, the built-in `ask_user` frontend tool is offered to the agent:\n * calling it renders an inline question card and returns the user's answer.\n * Off by default, like the other built-in tool groups, so the advertised\n * catalog does not change until a host asks for it.\n */\n askUser = false;\n\n /**\n * Optional full replacement for the `ask_user` question UI, resolving with\n * the answer; the same seam as {@link approvalRenderer}, styled via `strings`\n * and the `question*` `::part()`s when left unset. Requires {@link askUser}.\n * A renderer that throws or rejects hands the question to the built-in card,\n * as a failing {@link approvalRenderer} does, unless Stop already fired.\n */\n askUserRenderer: QuestionRenderer | null = null;\n\n /**\n * Optional full replacement for the server-side-tool approval UI: an approval\n * interrupt invokes this instead of the built-in {@link requestApproval}\n * card, resolving `true` to approve or `false` to deny. Style the built-in\n * card via `strings` and the `approval*` `::part()`s instead. The gate itself\n * is enabled server-side; this only changes how the decision is collected.\n */\n approvalRenderer: ApprovalRenderer | null = null;\n\n /**\n * Let the user edit a gated call's arguments before approving it.\n *\n * Off by default and **an assertion about your server**, not a negotiation:\n * AG-UI carries `editedArgs` in the resume payload and gates it on the\n * agent's own `approveWithEdits` capability, which this component never sees\n * -- capabilities are not on the wire it reads. So the host says whether its\n * agent honours them. Turned on against a server that does not, the user\n * would edit arguments it silently discards, which is worse than not\n * offering.\n *\n * Only affects calls whose arguments are known here: an interrupt names a\n * `toolCallId`, and the tool card for that call is where the arguments still\n * are. An interrupt naming no card gets the plain approve/deny.\n */\n approveWithEdits = false;\n\n /**\n * Optional per-call confirmation predicate. When set it is authoritative,\n * deciding from the tool name and args whether this particular call needs\n * confirmation \u2014 so one tool can be instant for some args and confirmed for\n * others, which a static `x-destructive` flag cannot express. When unset the\n * `x-destructive` flag decides. `autoConfirm` short-circuits both.\n */\n confirmPredicate:\n | ((toolName: string, args: Record<string, unknown>) => boolean | Promise<boolean>)\n | null = null;\n\n /**\n * Per-run frontend tool catalog provider. Defaults to the built-in\n * `route.*` tools (when a {@link routeMap} is set) plus the tools registered\n * via {@link registerTool} / {@link registerPageState}; override to supply a\n * fully custom catalog.\n */\n getTools: () => Tool[] = () => this.#tools.defaultTools();\n\n /**\n * Per-run context provider. Defaults to the compact page map, when a\n * {@link getPageMap} provider is set and {@link autoInjectPageMap} is on.\n *\n * Attachments are deliberately not restated here: the server derives its own\n * manifest from the refs riding the messages.\n */\n getContext: () => Context[] = () => [\n ...createPageMapContext(this.getPageMap, this.autoInjectPageMap),\n ];\n\n /**\n * Navigable routes the agent can jump to via the built-in `route.*` tools.\n * While {@link getPlace} is unset, the route matching the current path also\n * stands in as the place: the chip names it and the place entry carries it.\n * No summary of the map itself is sent.\n */\n routeMap: RouteMap = [];\n\n /**\n * Optional client-side router. When set (an SPA), `navigate_to_route` routes\n * in-page and the run loop continues; when unset (an MPA like the admin), it\n * falls back to `window.location` and the resumable-loop machinery applies.\n */\n navigate: ((path: string) => void) | null = null;\n\n /** Provider for the per-run page map; see {@link getContext}. */\n getPageMap: (() => PageMap) | null = null;\n\n /** Whether to auto-inject the page map into context each run. */\n autoInjectPageMap = true;\n\n /**\n * Where in the app the user is. The chip in the composer's tool row draws it,\n * and every tool round sends it as one `place` context entry from the same\n * read, after whatever {@link getContext} returns, so a host that replaces\n * that keeps it. Read before every round, on connect, on expand, when the\n * composer gains focus, on `popstate` and `hashchange`, when the conversation\n * changes, and on {@link refreshPlace}.\n *\n * When unset, the {@link routeMap} route matching `location.pathname` stands\n * in: its title (else its id) as the label, its group as the detail, the\n * path as the href. With neither, no chip is drawn and nothing is sent; a\n * host with a route map that wants no chip sets `() => null`.\n *\n * The chip's eye toggle withholds the place, and with it the page: a round\n * whose place is withheld sends no `page_map` entry, whatever\n * {@link getContext} returns, and offers no `read_page`. It holds for the\n * same place, lapses when a different place is read, and is not persisted.\n */\n getPlace: (() => Place | null) | null = null;\n\n /**\n * Persistence for the conversation + navigation checkpoint. Defaults to\n * per-tab `sessionStorage` so the chat survives full page reloads; inject a\n * server-backed store for cross-tab/device durability.\n */\n conversationStore: ClientConversationStore = new SessionStorageStore();\n\n /**\n * How attached files are uploaded. `null` (default) uses the built-in\n * multipart `POST` to `data-attachments-url`; a custom {@link UploadHandler}\n * swaps the transport without changing the tray, the chips, or the AG-UI\n * wire. When set, the \uD83D\uDCCE affordance appears even with no\n * `data-attachments-url`, and the handler owns its own endpoint and headers.\n */\n uploadHandler: UploadHandler | null = null;\n\n /**\n * How recorded voice clips are transcribed. `null` (default) POSTs the clip\n * to `data-transcribe-url`; a custom {@link TranscribeHandler} swaps the\n * transport without touching the mic button. When set, the \uD83C\uDFA4 affordance\n * appears even with no `data-transcribe-url`.\n */\n transcribeHandler: TranscribeHandler | null = null;\n\n /**\n * Builds the tool result a navigating tool resumes with after the page\n * reloads. Defaults to the landed URL; a host (e.g. the admin package) can\n * override to include a page snapshot or post-reload validation errors.\n */\n navigationResult: (checkpoint: NavigationCheckpoint) => unknown = () => ({\n navigated: true,\n url: window.location.href,\n });\n\n /**\n * Named values used to fill a skill prompt's `{placeholder}`s before send\n * (e.g. `{ model: \"Order\", selected_ids: \"1,2\" }`). A host (the admin) sets\n * this from the current page; a missing placeholder blocks the send.\n */\n skillContext: () => Record<string, unknown> = () => ({});\n\n /**\n * Friendly display labels for tool-call cards, keyed by tool name. The\n * fallback when a tool has no `x-summary` in its own schema, which chiefly\n * means server-side tools: AG-UI streams only the tool-call name, so their\n * schema never reaches the browser. Client tools should prefer `x-summary`.\n */\n toolSummaries: Record<string, string> = {};\n\n /**\n * Optional presentation hook for the two payload regions of a tool-call card\n * -- the arguments and the result. Unset (the default) leaves both\n * pretty-printed as JSON.\n *\n * The seam exists because a wide result has no good rendering as JSON: a\n * thirty-field row is a wall of text where the host wanted a table, or a\n * sentence. `ClientTool.render` cannot answer it -- it is handed the\n * *arguments* only, and a server-side tool has no `ClientTool` at all, so the\n * result region was the one part of the transcript a host could not reach.\n *\n * **Presentation, not translation.** The card and the model already read\n * separate copies of a tool result: the model's is maintained by\n * `@ag-ui/client` from the same event and persisted with the history, and the\n * card has always shown that string reformatted. So a formatter changes what\n * the person reads and nothing the agent reads -- which makes restyling safe\n * and *rewording* a way to make the card disagree with the prose beside it.\n * Rename a value on the server, where it reaches both.\n *\n * Read at render time rather than captured, so a host that sets it from a\n * framework effect after the first card still formats the results that settle\n * afterwards. See {@link ToolPayloadFormatter}.\n */\n formatToolPayload: ToolPayloadFormatter | null = null;\n\n /**\n * Localizable UI strings \u2014 a partial override merged over the English\n * {@link DEFAULT_UI_STRINGS}. Resolved once on connect (so set it before the\n * element is appended); the `data-strings` JSON attribute is the markup\n * equivalent, and this property wins key-by-key over it.\n */\n strings: Partial<UiStrings> = {};\n\n /**\n * Resolve a `scroll_to` / `drag_and_drop` target string to a host-page\n * element (or `null`). Defaults to a CSS-selector lookup; override to map\n * page-map element ids. The page-action tools are opt-in via the\n * `data-page-actions` attribute (`\"scroll\"` / `\"drag\"` / `\"chat\"`).\n */\n resolvePageTarget: ResolvePageTarget = (target) => document.querySelector<HTMLElement>(target);\n\n /**\n * Foreign origins already reported, so the notice is once per origin per\n * element rather than once per request. Per-element rather than module-level,\n * because two elements on one page are two separate configurations.\n */\n #warnedOrigins = new Set<string>();\n /** The resolved string table (defaults \u2190 `data-strings` \u2190 `strings`). */\n #strings: UiStrings = DEFAULT_UI_STRINGS;\n\n /** A delegated sub-agent's progress, hung off the card that delegated. */\n readonly #subagents = new SubAgentProgress({\n card: (callId) => this.#transcript.card(callId),\n strings: () => this.#strings,\n follow: () => this.#transcript.follow(),\n });\n /**\n * The AG-UI activities this element can draw, and the blocks it drew. A field\n * rather than built in the constructor, because the constructor registers the\n * built-in renderers through it.\n */\n readonly #activities = new ActivityRegistry({\n ensureGroup: () => this.#transcript.ensureGroup(),\n afterTranscriptGrew: () => this.#transcript.afterGrew(),\n appendNotice: (icon, text, kind) => this.#transcript.appendNotice(icon, text, kind),\n });\n\n /** The action row under each finished answer, and the one row holding Retry. */\n readonly #actions = new AnswerActions({\n element: this,\n strings: () => this.#strings,\n retry: () => {\n void this.retryLastTurn();\n },\n // Late-bound: the history is built in the constructor, after this field.\n threadId: () => this.#history.threadId,\n follow: () => this.#transcript.follow(),\n });\n\n readonly #root: ShadowRoot;\n /** The built-in stylesheet once rendered, kept so `extraStyles` can re-adopt beside it. */\n #builtInSheet: CSSStyleSheet | null = null;\n /** The host's own sheets, adopted after the built-in one. */\n #extraStyles: readonly CSSStyleSheet[] = [];\n /** The screen-reader-only status region the run and its tool calls report into. */\n readonly #announcer = new RunAnnouncer();\n /** Return-to-foot affordance, shown only once something has been missed. */\n readonly #jumpButton = document.createElement(\"button\");\n /**\n * Quoting a selection into the composer: the offer beside a transcript\n * selection, the same offer over the host page, and the quotation itself.\n * Built in the constructor, once the composer it writes into exists.\n */\n readonly #excerpts: TranscriptQuoteOffer;\n /**\n * Positioning context for {@link AgUiChat.#jumpButton}.\n *\n * The button cannot live in the scrolling list -- it would scroll away with\n * the content it is offering to scroll to -- and it cannot be positioned\n * against the panel either: the panel's foot is below the composer, the skill\n * chips and the footer, so `bottom` measured from there lands the button on\n * top of the composer rather than over the transcript. This wrapper is the\n * only box whose foot *is* the transcript's foot.\n */\n readonly #messagesWrap = document.createElement(\"div\");\n readonly #chat: HTMLDivElement;\n readonly #messages: HTMLDivElement;\n readonly #input: HTMLTextAreaElement;\n readonly #send: HTMLButtonElement;\n readonly #title: HTMLSpanElement;\n readonly #skillsMenu: SkillsMenu;\n readonly #drawer: ThreadDrawer;\n /** Checkpoint panel; rows load only when `data-runs-url` is set. */\n readonly #checkpoints: CheckpointMenu;\n /**\n * Which conversation is on screen and how one gets there: the active thread,\n * the restore from the store, the conversation list's verbs and the\n * checkpoint continuation. Built in the constructor, after the drawer, the\n * checkpoint panel and the run it continues exist.\n */\n readonly #history: ConversationHistory;\n /**\n * The one-line hint above the composer, cleared by the next keystroke.\n *\n * Two things write it -- a skill whose template is short of a field, and a\n * run continuation picked with nothing typed -- and both say the same kind of\n * thing: what the composer still needs before this can go. Its `part` stays\n * `skill-hint`, which the skills feature named and the README documents;\n * renaming a part is breaking, and a second hint element in the same slot\n * would be worse than one whose name is a release older than its job.\n */\n readonly #composerHint: HTMLDivElement;\n /** File-picker button + hidden input + tray slot; the tray mounts on connect. */\n readonly #attachButton: HTMLButtonElement;\n readonly #fileInput: HTMLInputElement;\n readonly #attachSlot: HTMLDivElement;\n /** Optional built-in header theme toggle; shown only with `data-theme-toggle`. */\n readonly #themeToggle: HTMLButtonElement;\n /** What the collapsed widget shrinks to: the floating launcher, or the sidebar rail. */\n readonly #launcher: HTMLButtonElement;\n /** The launcher's unread badge; hidden at zero, while expanded, and when the host opts out. */\n readonly #badge: HTMLSpanElement;\n /** The rail's vertical caption. Rendered only by the sidebar's edge rail and the bottom bar. */\n readonly #railLabel: HTMLSpanElement = document.createElement(\"span\");\n /**\n * The bottom bar under collapse-to=\"bar\": the launcher drawn as a strip, and\n * the history button beside it. Outside the bar it draws no box of its own.\n */\n readonly #dockBar: HTMLDivElement = document.createElement(\"div\");\n /** The bottom bar's history button, which opens the drawer as a popover. */\n readonly #barHistory: HTMLButtonElement = document.createElement(\"button\");\n /**\n * The conversation list's home while collapsed under collapse-to=\"none\": outside\n * the hidden panel, placed beside the host's button. No box of its own.\n */\n readonly #threadsPopover: HTMLDivElement = document.createElement(\"div\");\n /** The button the popover was opened from, whose presses are not outside it. */\n #threadsAnchor: Element | null = null;\n /** The bar height last reported, so the event fires on a change only. */\n #barHeight = 0;\n /** The docked width and edge last reported, so the event fires on a change only. */\n #dockWidth = 0;\n #dockSide: DockWidthDetail[\"side\"] = \"right\";\n /** The element the panel rises from under collapse-to=\"none\", set as a property. */\n #anchor: Element | null = null;\n /** Whether a missing anchor has been reported; once per anchor given. */\n #anchorWarned = false;\n // Unseen answers per thread: finished while collapsed or off screen.\n #unreadByThread = new Map<string, number>();\n /** Empty-state region at the top of the message list; hidden once anything renders. */\n readonly #emptyWrap: HTMLDivElement;\n /**\n * The transcript: bubbles, the open answer group, the pending dots, the\n * reasoning region, the tool cards and the scroller. Built in the\n * constructor, once the list and its empty-state region exist.\n */\n readonly #transcript: Transcript;\n /**\n * Running the tool calls a round produced and answering the server's\n * interrupts. Built in the constructor, after the transcript it draws in.\n */\n readonly #dispatch: ToolDispatch;\n /**\n * The AG-UI event handlers every client this element builds is given, and\n * what one interaction accumulates for the host until it settles. Built in\n * the constructor, after the transcript it draws in.\n */\n readonly #runHandlers: RunHandlers;\n /**\n * The greeting's own text, the fallback content of the `greeting` slot.\n * Rendered under every placement and shown by the stylesheet only where the\n * greeting layout is on, so a placement switch needs nothing from script.\n */\n readonly #greetingText: HTMLSpanElement = document.createElement(\"span\");\n /**\n * Files handed to the composer: the upload tray and the picker, drop and\n * paste routes into it. Built in the constructor; the tray itself only once\n * uploads are wired on connect.\n */\n readonly #attachments: ComposerAttachments;\n\n /**\n * Where the panel and launcher sit and how big the panel is: the drags, the\n * resize grips, and the persisted record of them. Built in the constructor,\n * once the launcher and the shadow root it reaches into exist.\n */\n readonly #placement: PanelPlacement;\n /** The maximized state as applied, which the reflected attribute may run ahead of. */\n #maximized = false;\n /** The maximized state listeners were last told, which a mount settles once. */\n #maximizedHeard = false;\n /** The header's maximize and collapse controls, once rendered. */\n #maximizeControl: { readonly button: HTMLButtonElement; readonly before: HTMLElement } | null =\n null;\n /** The header's collapse control, once rendered, repainted for its placement. */\n #collapseControl: HTMLButtonElement | null = null;\n /** What the user has sent this session, newest first, for arrow-key recall. */\n readonly #sentDrafts: string[] = [];\n /** Typed while a run was in flight, oldest first; sent when it settles. */\n readonly #queued: string[] = [];\n /** The row those show up in, above the composer. */\n readonly #queuedRow: HTMLDivElement = document.createElement(\"div\");\n /** How far back the composer has been walked; null while the user is typing. */\n #recallIndex: number | null = null;\n /**\n * What the walk last put in the composer, read back from it. A walk is live\n * only while the composer still holds exactly this, so a write from anywhere\n * else ends it. Stale while no walk is in progress, which is harmless: the\n * comparison can only ever end a walk, never start one.\n */\n #recalled = \"\";\n\n /**\n * Re-clamp the dragged launcher when the window changes size. Bound once as\n * a field so `removeEventListener` on disconnect gets the same reference.\n */\n readonly #onViewportResize = (): void => {\n if (this.#readyToPlace()) {\n this.#placement.restoreLauncherPosition();\n }\n };\n\n /**\n * The same for a change only the panel's own layout shows: a host's size, a\n * viewport inset token, a line typed in the composer. Not a moment to hand a\n * position back, so a panel under data-launcher-drag=\"false\" stays put.\n */\n readonly #onLayoutChange = (): void => {\n if (this.#readyToPlace()) {\n this.#placement.settleLauncherPosition();\n }\n };\n\n /** Bring the viewport's readings up to date, and say whether placing may follow. */\n #readyToPlace(): boolean {\n this.#placement.publishVisualViewport();\n this.#syncDock();\n // Not while a gesture owns the position: restoring re-applies the stored,\n // pre-drag position, and on a phone the visual viewport changes all through\n // a drag, so the two would fight. Nor while this element has no box: placing\n // would measure a rect of nothing. Showing it reports again.\n return !this.#placement.dragging() && this.#hasBox();\n }\n\n /**\n * Whether this element generates a box at all. Hidden on itself or on any ancestor\n * it does not; a host collapsed to its launcher does, whatever its size, and that\n * launcher still has to be placed, which is why this is not a test of the size.\n */\n #hasBox(): boolean {\n return this.getClientRects().length > 0;\n }\n\n /** Restore for a moment that is not a viewport's, which showing this reports anyway. */\n #restoreIfBoxed(): void {\n if (this.#hasBox()) {\n this.#placement.restoreLauncherPosition();\n }\n }\n\n /** Mic button mount point (input row); the control mounts on connect when enabled. */\n readonly #voiceSlot: HTMLSpanElement;\n /** The composer's mic, mounted on connect when transcription is available. */\n readonly #voice: ComposerVoice;\n /** Whether the element is currently in the DOM; gates the connect-time warning. */\n #connected = false;\n /** A {@link newChat} asked for before the element connected, to start at connect. */\n #newChatOnConnect = false;\n /**\n * Aborted when the element leaves the document, and replaced when it comes\n * back. Every listener connecting adds to a node that outlives the connection\n * goes under this signal, since connecting runs again on every insertion.\n */\n #connection = new AbortController();\n /**\n * Whether the element has connected before, which makes this connection a\n * re-insertion: there is a transcript on screen from last time, and the\n * history replay would draw the conversation a second time beneath it.\n */\n #connectedBefore = false;\n /**\n * The `user-key` whose state the element holds -- the transcript, the recall\n * history, the Always allow waivers and the shared state -- or `null` before\n * the first connect, when it holds nobody's.\n *\n * Not the same thing as the attribute. The attribute names the principal the\n * host says is here now, and it can change while the element is out of the\n * document, where nothing acts on it; this is who the state still belongs\n * to. Connecting compares the two, which is how a key changed while detached\n * still gets the handover a live change gets.\n */\n #principalKey: string | null = null;\n /**\n * The current principal's tenure: replaced on every handover, and captured by\n * each client as it is built. A client outlives the handover that stops it (a\n * stopped run's last save, a tool result, an event already read off the\n * wire), and one whose tenure has passed writes nothing, into either\n * principal's storage or state. An identity rather than the key: a first key\n * is an adoption and keeps saving, and a key that leaves and comes back is a\n * second tenure.\n */\n #tenure: object = {};\n /**\n * The conversation on screen: replaced whenever {@link #resetConversation}\n * clears the transcript for another one, and captured by each frontend tool\n * call as it is dispatched. A call outlives the reset that stops its run, and\n * one resuming after it skips drawing into the new conversation. Not\n * {@link #tenure}: the call still settles its card, clears its checkpoint and\n * returns its result.\n */\n #conversation: object = {};\n /**\n * The remote store `data-threads-url` wrapped around the conversation store,\n * and the store inside it, so connecting again can wrap that store rather\n * than the wrapper.\n */\n #threadStore: { remote: RemoteConversationStore; inner: ClientConversationStore } | null = null;\n\n #client: AgUiClient | null = null;\n // Seed for the next client. Once one exists it owns the live value (the\n // agent applies STATE_SNAPSHOT / STATE_DELTA into it), so this is only the\n // starting point \u2014 `sharedState` reads through to the client when present,\n // and to a running checkpoint continuation before that. Every client mirrors\n // its changes here, which is what the client built after a continuation is\n // seeded from.\n #sharedState: Record<string, unknown> = {};\n // Whether an interaction is in flight (first onRunStart \u2192 onSettled). Drives\n // the Send\u21C4Stop button: `agent.isRunning` is false between frontend-tool\n // rounds, but the user must still be able to stop there.\n #running = false;\n /**\n * The send {@link sendMessage} or the retry {@link retryLastTurn} has taken\n * whose run has not started yet; null otherwise. `running` turns on only a\n * microtask after the run is asked for, and a submit listener or a second\n * call in that gap would start a second run on the same client. Every restore\n * takes it too, through `holdRun`, until the store answers.\n *\n * Let go of once the run starts, since `running` holds from then and a hold\n * past it would refuse a host's follow-up from the run-finished event; or by\n * the send's, retry's or restore's end when its run never starts. An object\n * rather than a flag, so each ending releases only what it took, and how\n * {@link sendMessage} tells the hold it waits on apart: see {@link #restoreHold}.\n */\n #sending: object | null = null;\n /**\n * The hold the latest restore with no run to resume took, and what settles\n * once that restore has ended or been stopped; `null` when the latest\n * restore will resume a run. Only meaningful while `#sending` is that hold:\n * then a host's {@link sendMessage} waits for it rather than refusing.\n */\n #restoreHold: { readonly hold: object; readonly restored: Promise<void> } | null = null;\n /**\n * The thread the latest {@link THREAD_EVENT} reported, which the next one\n * names as the thread it replaced; `null` before the first.\n */\n #shownThread: string | null = null;\n /** The thread on screen's messages as last saved or restored, which name it. */\n #titleMessages: readonly Message[] = [];\n /** Titles renamed here or listed that its messages do not derive, by thread. */\n readonly #givenTitles = new Map<string, string>();\n /** The thread and title {@link threadTitle} last reported. */\n #titled = { threadId: \"\", title: \"\" };\n /** The decision a run is suspended on, which a Stop abandons. */\n readonly #decision = new PendingDecision();\n /** The place chip, kept across connections like the composer it sits in. */\n readonly #place = new PlaceChip();\n /**\n * The frontend tools the agent is offered, what the current round advertised,\n * and the server's labels for its own tools. A field, because the tool\n * registry it holds is reachable from the moment the element exists.\n */\n readonly #tools = new ToolCatalog({\n element: this,\n routeMap: () => this.routeMap,\n navigate: () => this.navigate,\n getPageMap: () => this.getPageMap,\n pageWithheld: () => this.#place.withheld,\n resolvePageTarget: (target) => this.resolvePageTarget(target),\n getTools: () => this.getTools(),\n askUser: () => this.askUser,\n askUserRenderer: () => this.askUserRenderer,\n decision: this.#decision,\n setAsking: (callId, asking) => this.#transcript.setAsking(callId, asking),\n ensureGroup: () => this.#transcript.ensureGroup(),\n strings: () => this.#strings,\n hidePending: () => this.#transcript.hidePending(),\n updateEmptyState: () => this.#transcript.updateEmptyState(),\n follow: () => this.#transcript.follow(),\n fetchInit: (url) => this.#fetchInit(url),\n });\n /** The assistant answer currently streaming into the transcript. */\n readonly #stream = new AnswerStream({\n openBubble: () => this.appendMessage(MESSAGE_ROLE.ASSISTANT, \"\"),\n allowImages: () => this.allowImages,\n follow: () => this.#transcript.follow(),\n });\n // This chat's place among the connected ones, which a free highlight ring reads.\n readonly #chatRegistration = new ChatRegistration(this);\n /**\n * Which storage keys are this element's: the namespace it claims, the keys\n * its layout preferences live under, and the built-in store scoped to them.\n */\n readonly #storage = new StorageScope({\n id: () => this.id,\n endpoint: () => this.endpoint,\n });\n /**\n * The skill catalog: its three sources merged into the menu, and what a pick\n * does to the composer. Built in the constructor, after the menu it fills.\n */\n readonly #skills: SkillCatalog;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: \"open\" });\n this.#chat = document.createElement(\"div\");\n this.#messages = document.createElement(\"div\");\n this.#input = document.createElement(\"textarea\");\n this.#send = document.createElement(\"button\");\n this.#title = document.createElement(\"span\");\n this.#composerHint = document.createElement(\"div\");\n this.#attachButton = document.createElement(\"button\");\n this.#fileInput = document.createElement(\"input\");\n this.#attachSlot = document.createElement(\"div\");\n this.#voiceSlot = document.createElement(\"span\");\n this.#themeToggle = document.createElement(\"button\");\n this.#launcher = document.createElement(\"button\");\n this.#badge = document.createElement(\"span\");\n this.#emptyWrap = document.createElement(\"div\");\n this.#transcript = new Transcript({\n element: this,\n messages: this.#messages,\n emptyWrap: this.#emptyWrap,\n strings: () => this.#strings,\n allowImages: () => this.allowImages,\n resolveTool: (name) => this.#tools.resolve(name),\n toolSummaries: () => this.toolSummaries,\n serverSummary: (name) => this.#tools.summary(name),\n toolDisplay: () => this.toolDisplay,\n toolGroupDisplay: () => this.toolGroupDisplay,\n // A thunk over the live property, not the property itself: the card keeps\n // this for the life of the call, and the result region is filled when the\n // tool settles -- which can be long after a host set the hook.\n formatToolPayload: (payload) => this.formatToolPayload?.(payload) ?? null,\n });\n this.#dispatch = new ToolDispatch({\n element: this,\n transcript: this.#transcript,\n tools: this.#tools,\n decision: this.#decision,\n strings: () => this.#strings,\n announce: (message) => this.#announcer.announce(message),\n autoConfirm: () => this.autoConfirm,\n confirmPredicate: () => this.confirmPredicate,\n navigate: () => this.navigate,\n approveWithEdits: () => this.approveWithEdits,\n approvalRenderer: () => this.approvalRenderer,\n getContext: () => this.#roundContext(),\n conversationStore: () => this.conversationStore,\n threadId: () => this.#history.threadId,\n // Read live and compared, the way each client compares the one it was\n // built with: see #tenure.\n tenure: () => this.#tenure,\n // The same, for the conversation on screen: see #conversation.\n conversation: () => this.#conversation,\n });\n this.#runHandlers = new RunHandlers({\n element: this,\n transcript: this.#transcript,\n stream: this.#stream,\n actions: this.#actions,\n activities: this.#activities,\n subagents: this.#subagents,\n announcer: this.#announcer,\n strings: () => this.#strings,\n running: () => this.#running,\n setRunning: (running) => this.#setRunning(running),\n appendMessage: (role, content) => this.appendMessage(role, content),\n noteUnread: (threadId) => this.#noteUnread(threadId),\n });\n this.#placement = new PanelPlacement({\n element: this,\n launcher: this.#launcher,\n root: this.#root,\n connected: () => this.#connected,\n collapsed: () => this.collapsed,\n collapsible: () => this.#surface().collapseTo !== null,\n strings: () => this.#strings,\n readPreference: (base) => this.#storage.readPreference(base),\n writePreference: (base, value) => this.#storage.writePreference(base, value),\n clearPreference: (base) => this.#storage.clearPreference(base),\n announceSurfaceChange: (text, undo) => this.#announceSurfaceChange(text, undo),\n });\n this.#excerpts = new TranscriptQuoteOffer({\n element: this,\n root: this.#root,\n messages: this.#messages,\n messagesWrap: this.#messagesWrap,\n input: this.#input,\n strings: () => this.#strings,\n autoGrow: () => autoGrow(this.#input),\n quote: (text) => this.quote(text),\n });\n this.#attachments = new ComposerAttachments({\n element: this,\n chat: this.#chat,\n slot: this.#attachSlot,\n fileInput: this.#fileInput,\n button: this.#attachButton,\n strings: () => this.#strings,\n uploadHandler: () => this.uploadHandler,\n headersFor: (url) => this.#headersFor(url),\n credentialsOption: () => this.#credentialsOption(),\n });\n this.#voice = new ComposerVoice({\n element: this,\n slot: this.#voiceSlot,\n input: this.#input,\n strings: () => this.#strings,\n transcribeHandler: () => this.transcribeHandler,\n headersFor: (url) => this.#headersFor(url),\n credentialsOption: () => this.#credentialsOption(),\n onInput: () => this.#onInput(),\n });\n // The compaction notice is a registration, not a branch -- and going through\n // the seam earns it two things it did not have: a reload puts it back (it is\n // content, and content replays), and a server redrawing under the same id\n // replaces it rather than adding a second notice for one event.\n this.registerActivityRenderer({\n type: COMPACTION_ACTIVITY_TYPE,\n render: (content) => {\n const removed = compactionRemoved(content);\n return removed === null\n ? null\n : renderRunNotice(\n \"\\u{1F5DC}\",\n fillUiString(this.#strings.historyCompacted, { count: removed }),\n \"compaction\",\n );\n },\n });\n // Follow-up chips, registered through the same seam for the same reasons:\n // a reload puts them back, and a server pushing a new set under a new id\n // supersedes the old one rather than leaving two offers on screen.\n this.registerActivityRenderer({\n type: SUGGESTIONS_ACTIVITY_TYPE,\n render: (content) =>\n renderSuggestionChips(content, this.#strings, (prompt) => {\n void this.sendMessage(prompt);\n }),\n });\n this.#skillsMenu = new SkillsMenu((skill) => this.#skills.apply(skill));\n this.#skills = new SkillCatalog({\n element: this,\n menu: this.#skillsMenu,\n input: this.#input,\n hint: this.#composerHint,\n strings: () => this.#strings,\n context: () => this.skillContext(),\n flag: (name) => readFlag(this, name),\n readJsonAttribute: (name) => readJsonAttribute(this, name),\n fetchInit: (url) => this.#fetchInit(url),\n send: (content) => {\n void this.sendMessage(content);\n },\n submit: () => {\n void this.#submit();\n },\n autoGrow: () => autoGrow(this.#input),\n });\n this.#drawer = new ThreadDrawer({\n onSelect: (threadId) => {\n // switchThread rejects when the store cannot load the thread, and keeps\n // the old one on screen; a pick has nobody to tell, so it ends here.\n this.#history.switchThread(threadId).catch(() => undefined);\n },\n onNew: () => {\n this.newChat();\n void this.#history.refreshDrawer();\n },\n onRename: (threadId, title) => {\n this.#givenTitles.set(threadId, title);\n this.#retitle();\n this.#history.renameThread(threadId, title);\n },\n onDelete: (threadId) => {\n this.#history.deleteThread(threadId);\n },\n });\n this.#checkpoints = new CheckpointMenu((runId, verb) => {\n // Reported rather than dropped: the send fails when the host's store\n // refuses the first save, and `continueRun` has already let go of the\n // continuation by then, so the panel takes another pick.\n void this.#history.continueRun(runId, verb).catch((error: unknown) => {\n console.warn(\"<ag-ui-chat>: continuing a run failed\", error);\n });\n });\n this.#history = new ConversationHistory({\n element: this,\n drawer: this.#drawer,\n checkpoints: this.#checkpoints,\n transcript: this.#transcript,\n actions: this.#actions,\n activities: this.#activities,\n tools: this.#tools,\n input: this.#input,\n hint: this.#composerHint,\n strings: () => this.#strings,\n conversationStore: () => this.conversationStore,\n formatRelativeTime: () => this.formatRelativeTime,\n navigationResult: () => this.navigationResult,\n headersFor: (url) => this.#headersFor(url),\n requestCredentials: () => this.#requestCredentials(),\n appendMessage: (role, content) => this.appendMessage(role, content),\n // A continuation sends only what the composer holds. The tray is not\n // read, so nothing rides along to be drawn or announced.\n announceTurn: (content) => this.#announceTurn(content, []),\n recordTurn: (content) => this.#recordTurn(content),\n autoGrow: () => autoGrow(this.#input),\n continuationEnded: () => this.#flushQueued(),\n client: () => this.#client,\n ensureClient: () => this.#ensureClient(),\n buildClient: (seed) => this.#buildClient(seed),\n releaseClient: () => {\n this.#client = null;\n },\n // A held send or retry is as much in flight to a pick as a run is: it has\n // asked this element's client for a run that has not started, and a\n // continuation started beside it was a second run in one conversation.\n // So is a restore, which holds through the same field from before the\n // store answers.\n running: () => this.#running || this.#sending !== null,\n // The hold a send takes, taken for every restore: Send parks the turn, a\n // Retry and a pick refuse, and `sendMessage` refuses behind a restore that\n // resumes a run and waits on `restored` for one that does not. The same\n // field rather than a flag, so the resumed run starting (`#setRunning`) or\n // a Stop (`#cancelRun`) lets go of it; a flag the restore cleared would\n // refuse the parked turn once the resumed run settles. Whether the restore\n // was stopped is asked of its own generation, since a waiting send takes\n // this hold over.\n holdRun: (restored) => {\n const hold = {};\n this.#sending = hold;\n this.#restoreHold = restored === null ? null : { hold, restored };\n return {\n release: () => this.#releaseHold(hold),\n };\n },\n cancelRun: () => this.#cancelRun(),\n resetState: () => this.#resetState(),\n setRunning: (running) => this.#setRunning(running),\n threadChanged: (threadId, reason) => this.#dispatchThread(threadId, reason),\n threadsListed: (threads) => {\n this.#takeListedTitle(threads);\n this.#takeListedUnread(threads);\n },\n threadDeleted: (threadId) => this.#forgetUnread([threadId]),\n });\n }\n\n /** Attributes the element reacts to after it has been connected. */\n static get observedAttributes(): string[] {\n return [\n \"title-text\",\n \"placement\",\n \"collapse-to\",\n \"anchor\",\n \"anchor-side\",\n \"maximized\",\n \"data-side\",\n \"data-small-viewport\",\n \"data-threads-search\",\n \"credentials\",\n \"user-key\",\n \"user-name\",\n \"data-tool-group-display\",\n \"data-collapse-icon\",\n \"theme\",\n ...CONNECT_TIME_ATTRIBUTES,\n ];\n }\n\n attributeChangedCallback(name: string, previous: string | null, value: string | null): void {\n if (name === \"credentials\") {\n // Reported the moment the attribute is written \u2014 before connect, and\n // whether it came from markup or the property setter. An unrecognised\n // mode is otherwise inert, and the request it was meant to authorise\n // goes out anonymously with nothing to show for it.\n if (value !== null && !isCredentialsMode(value)) {\n console.error(\n `<ag-ui-chat>: credentials=\"${value}\" is not a fetch credentials mode ` +\n `(${CREDENTIALS_MODES.join(\" / \")}) \u2014 it is being ignored, so requests use ` +\n \"the browser default and cross-origin cookies will not be sent.\",\n );\n }\n return;\n }\n if (name === \"data-tool-group-display\") {\n this.#transcript.refreshStepGroups();\n return;\n }\n if (name === \"data-threads-search\") {\n const mode = this.getAttribute(\"data-threads-search\");\n this.#drawer.setSearchMode(mode === \"always\" || mode === \"never\" ? mode : \"auto\");\n return;\n }\n if (name === \"anchor\") {\n this.#anchorWarned = false;\n this.#syncDock();\n return;\n }\n if (name === \"maximized\") {\n this.#applyMaximized(value !== null);\n return;\n }\n if (name === \"data-collapse-icon\") {\n this.#paintCollapseControl();\n return;\n }\n // Whoever sets the scheme (a host, a picker, the toggle itself), the\n // toggle's glyph has to offer the way out of the one now drawn.\n if (name === \"theme\") {\n if (this.#themeToggle.isConnected) {\n this.#syncThemeGlyph();\n }\n return;\n }\n if (name === \"anchor-side\" || name === \"data-side\" || name === \"data-small-viewport\") {\n this.#paintCollapseControl();\n this.#syncDock();\n return;\n }\n // collapse-to changes the surface the way placement does -- a docked panel\n // has no launcher to drag, and keeps its own dragged spot apart from the\n // corner's, so the same handover applies -- and is live the same way.\n if (name === \"placement\" || name === \"collapse-to\") {\n // Before the size handover, which a maximized panel refuses: a placement\n // without the control takes its own stored size, not none.\n this.#syncMaximizeControl();\n // A placement owns the axes it fixes, so hand those back before anything\n // else: a size dragged under the previous placement would otherwise sit\n // inline and outrank the new one.\n this.#placement.releaseOwnedAxes();\n // A dragged size belongs to its placement; collapse-to keeps it.\n if (name === \"placement\") {\n this.#placement.switchPlacement(previous);\n }\n // Position is owned the same way a size is: a placement that places\n // itself takes back a launcher the user had dragged somewhere else.\n this.#placement.releaseLauncherPosition();\n // Switching into a placement with no collapsed state has to release it,\n // not just stop offering it: the control is gone from the header the\n // moment the attribute changes, so a panel collapsed under the previous\n // placement would have no way back.\n if (this.#surface().collapseTo === null && this.collapsed) {\n this.setCollapsed(false);\n }\n this.#stampCollapseTarget();\n this.#paintCollapseControl();\n if (name === \"collapse-to\") {\n // The strip's label and the popover's home both depend on the target,\n // and neither is re-derived by the dock sync.\n this.#syncLauncher();\n this.#homeDrawer(this.#surface().collapseTo === \"bar\" ? this.#dockBar : null);\n }\n this.#syncDock();\n // Placement also moves the panel, so the edges its layout holds still\n // change with it. Deferred a frame so the new rules have applied.\n requestAnimationFrame(() => this.#placement.syncResizeAnchor());\n return;\n }\n if (name === \"title-text\") {\n this.#paintTitle();\n return;\n }\n if (name === \"user-name\") {\n // Display only, and live: an auth handshake that resolves after mount\n // names the user on screen the moment it does. Before connect the string\n // table is still the defaults, and rendering fills it again from the\n // resolved one.\n this.#syncGreeting();\n return;\n }\n if (name === \"user-key\") {\n // Acted on here only while connected; connecting hands over a change made\n // while detached (see #principalKey). Absent and empty name one principal.\n if (this.#connected && (previous ?? \"\") !== (value ?? \"\")) {\n this.#changePrincipal(previous ?? \"\", value ?? \"\");\n }\n return;\n }\n // Everything else is read once, while connecting, to build chrome. A later\n // change does nothing, which reads as a broken component, so say so.\n if (previous === value || !this.#connected) {\n return;\n }\n console.warn(\n `<ag-ui-chat>: \"${name}\" was changed after the element connected, and is ` +\n \"read only while connecting \u2014 this assignment has no effect. Set it \" +\n \"before the element enters the DOM (in the markup, or on the element \" +\n \"before appending it); frameworks that patch attributes after mount \" +\n \"should bind it at creation. To apply a new value now, remove and \" +\n \"re-insert the element.\",\n );\n }\n\n /**\n * Declare a frontend tool the agent may call.\n *\n * **A handler's thrown message leaves the browser.** When a handler rejects,\n * its `Error.message` is posted back as that call's tool result \u2014 into the\n * conversation, on to the AG-UI endpoint, persisted server-side, and\n * forwarded to the model provider on every later round. That is deliberate,\n * since it is what lets the agent recover from a failure it caused; but it\n * means an internal hostname, a signed URL or a stack-derived path in a\n * rethrown error is disclosed to parties the host never chose. Throw the\n * message you would be content for the model to read, and log the detail.\n */\n registerTool(tool: ClientTool): void {\n this.#tools.register(tool);\n }\n\n /**\n * AG-UI **shared state** for this conversation \u2014 the protocol's own state\n * channel, sent as `RunAgentInput.state` on every run and replaced in place\n * when the server streams `STATE_SNAPSHOT` / `STATE_DELTA`. Assigning seeds\n * the next run; reading returns whatever the agent last applied.\n *\n * Listen for {@link STATE_EVENT} to react to server-driven changes. Distinct\n * from {@link registerPageState}, which exposes host state as ordinary tools.\n */\n get sharedState(): Readonly<Record<string, unknown>> {\n return this.#liveClient()?.state ?? this.#sharedState;\n }\n\n set sharedState(state: Readonly<Record<string, unknown>>) {\n this.#sharedState = { ...state };\n // A client already exists for this conversation \u2014 push it through so the\n // next run sends it, rather than silently waiting for a new conversation.\n // A continuation in flight is that client while it runs: its next round\n // sends what it holds, and the getter reads it back from there.\n this.#liveClient()?.setState(this.#sharedState);\n }\n\n /**\n * The client holding the conversation's live shared state: a checkpoint\n * continuation while one runs, otherwise the conversation's own client, and\n * `null` before either exists. The continuation first, because the state it\n * streams is applied to its own agent. The fallback agrees only because the\n * conversation's client is released at the continuation's first save, so no\n * test can tell them apart; reading the continuation stays right however long\n * that client is kept. The setter's is held by \"reads the shared state it\n * changed while it runs, not the conversation's\" (checkpoints tests).\n */\n #liveClient(): AgUiClient | null {\n return this.#history.continuation ?? this.#client;\n }\n\n /** Bind a piece of host page state to `read_<name>` / `set_<name>` tools. */\n registerPageState(binding: PageState): void {\n this.#tools.registerPageState(binding);\n }\n\n /** The AG-UI endpoint URL, read from the `endpoint` attribute. */\n get endpoint(): string {\n return this.getAttribute(\"endpoint\") ?? \"\";\n }\n\n // Reflecting setter so frameworks (e.g. React 19) that assign matching\n // props as element *properties* don't hit a read-only property. Read at\n // use-time, so a runtime change applies to the next run.\n set endpoint(value: string) {\n this.setAttribute(\"endpoint\", value);\n }\n\n /**\n * Who the stored conversation belongs to, from the `user-key` attribute.\n *\n * Set it to whatever identifies the signed-in principal \u2014 a user id, an\n * account id, a hash of one. The value joins the storage namespace, so two\n * principals in the same tab cannot read each other's transcript, and\n * **changing it purges what the previous one left behind**.\n *\n * That purge is the reason this is a live attribute rather than a\n * connect-time one. `sessionStorage` survives same-tab navigation, so it\n * survives a logout; and a single-page app signs out through its own router\n * without remounting anything, so there is no other moment at which the\n * element could find out. The host naming the new principal \u2014 or dropping the\n * attribute \u2014 is the signal.\n *\n * Absent means exactly today's behaviour, which is why nothing breaks by\n * leaving it off: the conversation is scoped to the element and to nobody in\n * particular, and on a shared workstation it carries into whoever signs in\n * next in the same tab.\n *\n * The first value to arrive is treated as a host naming the user who was\n * already there, not as a handover: the conversation in progress moves into\n * the principal's namespace rather than being destroyed, so an element\n * configured by an async auth handshake keeps what is on screen.\n */\n get userKey(): string {\n return this.getAttribute(\"user-key\") ?? \"\";\n }\n\n set userKey(value: string) {\n this.setAttribute(\"user-key\", value);\n }\n\n /**\n * The signed-in user's display name, from the `user-name` attribute, for the\n * greeting an empty conversation shows under `placement=\"page\"`.\n *\n * Presentation only. Unlike {@link userKey} it scopes nothing and is never\n * sent to the server. Absent or blank means the nameless greeting. Live: a\n * name that arrives after the element connected replaces the greeting on\n * screen.\n */\n get userName(): string {\n return this.getAttribute(\"user-name\") ?? \"\";\n }\n\n set userName(value: string) {\n this.setAttribute(\"user-name\", value);\n }\n\n /** Fill the greeting from the resolved string table and the current name. */\n #syncGreeting(): void {\n const name = this.userName.trim();\n this.#greetingText.textContent =\n name === \"\" ? this.#strings.greetingNoName : fillUiString(this.#strings.greeting, { name });\n }\n\n /**\n * Cookie policy for **every** request this element makes, as `fetch`'s own\n * `credentials` mode (`\"omit\"` / `\"same-origin\"` / `\"include\"`). Mirrored to\n * the `credentials` attribute, so markup embeds can set it without script.\n *\n * `null` (the default) leaves the browser's `same-origin` default in place,\n * which sends no cookies at all to an endpoint on a different origin \u2014 and\n * the request goes out anonymously rather than failing, so the symptom is a\n * 401 from a server that looks correctly configured. A cookie-authenticated\n * cross-origin deployment wants `\"include\"`, plus\n * `Access-Control-Allow-Credentials: true` and a concrete, non-wildcard\n * `Access-Control-Allow-Origin` on the server.\n *\n * Read per request, so a late assignment applies to everything after it.\n * `\"omit\"` cannot be honoured by the built-in upload transport, an\n * `XMLHttpRequest` with only a two-state cookie switch; every other endpoint\n * honours all three modes.\n */\n get credentials(): RequestCredentials | null {\n const attr = this.getAttribute(\"credentials\");\n return attr !== null && isCredentialsMode(attr) ? attr : null;\n }\n\n set credentials(value: RequestCredentials | null) {\n if (value === null) {\n this.removeAttribute(\"credentials\");\n return;\n }\n // Thrown, not warned: an unrecognised mode is inert at request time, and\n // the whole failure this option exists to fix is a request that goes out\n // wrong without saying so. Fail where the mistake was made instead.\n if (!isCredentialsMode(value)) {\n throw new TypeError(\n `<ag-ui-chat>: credentials must be one of ${CREDENTIALS_MODES.map((mode) => `\"${mode}\"`).join(\", \")} ` +\n `(got ${JSON.stringify(value)}).`,\n );\n }\n this.setAttribute(\"credentials\", value);\n }\n\n /**\n * The headers for the request about to go out: the static {@link headers}\n * with {@link getHeaders}'s live values overlaid, per key.\n *\n * Every request site goes through here, so \"how this element authenticates\"\n * is one answer rather than one per endpoint.\n */\n #requestHeaders(): Record<string, string> {\n return { ...this.headers, ...this.getHeaders?.() };\n }\n\n /**\n * The request headers, having first reported the destination if it is\n * foreign: the one path that has both the headers and the URL.\n */\n #headersFor(url: string): Record<string, string> {\n const headers = this.#requestHeaders();\n warnOnCrossOriginCredentials(\n url,\n Object.keys(headers),\n this.trustedOrigins,\n this.#warnedOrigins,\n );\n return headers;\n }\n\n /** The configured cookie policy as `fetch` spells it; `undefined` when unset. */\n #requestCredentials(): RequestCredentials | undefined {\n return this.credentials ?? undefined;\n }\n\n /**\n * The `credentials` entry for an {@link AgentFactory} call, or nothing at all.\n *\n * Spread rather than assigned: `exactOptionalPropertyTypes` rejects an\n * explicit `credentials: undefined`, and a factory should see the field\n * absent \u2014 not present-and-empty \u2014 when no policy is configured. The agent\n * reads it when it is built (first send, thread switch, continuation), by\n * which time any host configuration has landed.\n */\n #credentialsOption(): { credentials?: RequestCredentials } {\n const credentials = this.#requestCredentials();\n return credentials === undefined ? {} : { credentials };\n }\n\n /** The `fetch` init for the element's own plain GETs (catalogs). */\n #fetchInit(url: string): RequestInit | undefined {\n return withCredentials({ headers: this.#headersFor(url) }, this.#requestCredentials());\n }\n\n /**\n * How much detail tool-call cards show, from the `data-tool-display`\n * attribute (`grouped` / `minimal` / `inline` / `compact` / `full`).\n * Defaults to `grouped`, for an absent attribute and for a value the\n * element does not know; `full` is the per-call card default before\n * `grouped` existed.\n *\n * The four card modes are applied by the shadow CSS from the attribute\n * itself, so changing between them restyles every card already in the\n * transcript. Whether calls fold into a step group is decided as each card\n * is built: switching to `grouped` folds only the calls drawn afterwards,\n * and switching away flattens the existing groups, again by CSS.\n */\n get toolDisplay(): ToolDisplayMode {\n const attr = this.getAttribute(\"data-tool-display\");\n if (\n attr === TOOL_DISPLAY.INLINE ||\n attr === TOOL_DISPLAY.MINIMAL ||\n attr === TOOL_DISPLAY.COMPACT ||\n attr === TOOL_DISPLAY.FULL\n ) {\n return attr;\n }\n return TOOL_DISPLAY.GROUPED;\n }\n\n set toolDisplay(value: ToolDisplayMode) {\n this.setAttribute(\"data-tool-display\", value);\n }\n\n /**\n * How an opened step group draws its calls, from the\n * `data-tool-group-display` attribute (`full` / `compact` / `minimal` /\n * `inline`). Defaults to `full`, for an absent attribute and for a value the\n * element does not know, which is what a group drew before the attribute.\n *\n * Read only while `toolDisplay` is `grouped`: under a card mode the groups\n * are flattened into that mode's cards. Applied by the shadow CSS from the\n * attribute itself, so changing it restyles groups already on screen.\n */\n get toolGroupDisplay(): ToolGroupDisplayMode {\n const attr = this.getAttribute(\"data-tool-group-display\");\n if (\n attr === TOOL_GROUP_DISPLAY.INLINE ||\n attr === TOOL_GROUP_DISPLAY.MINIMAL ||\n attr === TOOL_GROUP_DISPLAY.COMPACT\n ) {\n return attr;\n }\n return TOOL_GROUP_DISPLAY.FULL;\n }\n\n set toolGroupDisplay(value: ToolGroupDisplayMode) {\n this.setAttribute(\"data-tool-group-display\", value);\n }\n\n /**\n * The host's own constructed stylesheets, adopted after the built-in one.\n *\n * The escape hatch for structure that neither the tokens nor the parts\n * reach. Per element, like the built-in sheet: two elements on one page can\n * carry different sheets. Constructed sheets are not subject to a\n * `style-src` policy, so this works under the same strict CSP the\n * built-in sheet does. Setting it re-adopts at once; the array is copied, so\n * mutating the one passed in changes nothing until it is set again.\n *\n * Unstable: reaches shadow class names, which may change in any minor.\n */\n get extraStyles(): readonly CSSStyleSheet[] {\n return this.#extraStyles;\n }\n\n set extraStyles(sheets: readonly CSSStyleSheet[]) {\n this.#extraStyles = [...sheets];\n if (this.#builtInSheet !== null) {\n this.#root.adoptedStyleSheets = [this.#builtInSheet, ...this.#extraStyles];\n }\n }\n\n connectedCallback(): void {\n // A fresh signal per connection: disconnecting aborted the last one, and\n // with it every listener the last connection added.\n this.#connection = new AbortController();\n // Coming back is a reload, not a merge, for the reason `reload()` is: the\n // run was cancelled on the way out, and the transcript is rebuilt below\n // from persisted history -- which could only be appended to what is still\n // showing. The composer's recall history is kept, because a move is not a\n // farewell, and the Stop on the way out dropped the queued messages because\n // recall already held them.\n if (this.#connectedBefore) {\n this.#resetConversation();\n }\n this.#connectedBefore = true;\n // Resolve the per-instance storage namespace before any key read/write, so\n // this instance doesn't share collapsed/theme/thread state with another on\n // the same origin.\n this.#storage.claim();\n this.#chatRegistration.join();\n // Restore a dragged size before the panel paints, so it does not snap from\n // the placement default to the user's width on the first frame.\n this.#placement.restoreSize();\n // Position the grip at the corner this layout grows toward. Deferred to a\n // frame so the host's own stylesheet has applied; re-measured on every drag\n // anyway, so a wrong first guess costs a grip in the wrong corner and never\n // a wrong resize.\n requestAnimationFrame(() => {\n // Before the anchor, which the placement stamps itself once a dragged\n // position exists.\n this.#restoreIfBoxed();\n this.#placement.syncResizeAnchor();\n });\n // Resolve the string table before rendering any chrome (defaults are the\n // floor; `data-strings` then the `strings` property layer over them).\n this.#strings = mergeUiStrings({ ...this.#readStringOverrides(), ...this.strings });\n // Restore the scheme the built-in toggle persisted last visit onto the\n // markup's theme name (opt-in only, so it never overrides a host that\n // drives `theme` itself).\n if (this.getAttribute(\"data-theme-toggle\") !== null) {\n const saved = this.#storage.readPreference(THEME_KEY);\n const scheme = saved === null ? undefined : savedScheme(saved);\n if (scheme !== undefined) {\n this.setAttribute(\"theme\", withScheme(this.getAttribute(\"theme\") ?? \"\", scheme));\n }\n }\n this.#render();\n this.#drawer.setStrings(this.#strings);\n this.#checkpoints.setStrings(this.#strings);\n // Gated on the placement, not just on the stored value: the key is\n // namespaced per instance but not per placement, so a tab that collapsed a\n // floating panel and later loaded the same instance as a page would restore\n // a state that placement has no way out of.\n if (this.#surface().collapseTo !== null && this.#startsCollapsed()) {\n this.setAttribute(\"collapsed\", \"\");\n }\n this.#syncLauncher();\n this.#stampCollapseTarget();\n // The bar's height follows its content (the font, a long title), so it is\n // measured rather than known; the observer reports a change of size, and\n // the strip going from drawn to not drawn is one.\n const dockObserver = new ResizeObserver(() => this.#syncDock());\n dockObserver.observe(this.#dockBar);\n this.#connection.signal.addEventListener(\"abort\", () => dockObserver.disconnect());\n // A host's own size arrives with no event. The transcript is watched rather\n // than this element: a page publishing a token from its own observer changes\n // this box after that observer ran, which the browser reports as a loop. The\n // transcript already has an observer, so this adds no report of its own.\n const layoutObserver = new ResizeObserver(this.#onLayoutChange);\n layoutObserver.observe(this.#messages);\n this.#connection.signal.addEventListener(\"abort\", () => layoutObserver.disconnect());\n // The viewport insets arrive the same way, and a page's observer writes them after\n // the window's resize event, so that restore reads the bar as it was. The probe\n // carries them, and an observer on it would be a report on the window for the same\n // reason, so it takes them as a transition instead: heard the next frame, whichever\n // element wrote them and however late.\n this.#placement.probe.addEventListener(\"transitionrun\", this.#onLayoutChange, {\n signal: this.#connection.signal,\n });\n // A resize drag is reported when it ends, and the last frame may change nothing\n // the observer sees.\n const endDrag = (): void => void requestAnimationFrame(() => this.#syncDock());\n window.addEventListener(\"pointerup\", endDrag, { signal: this.#connection.signal });\n window.addEventListener(\"keyup\", endDrag, { signal: this.#connection.signal });\n this.#syncDock();\n // A connect that restored or defaulted to collapsed leaves a state asked for in markup.\n if (this.collapsed) {\n this.setMaximized(false);\n }\n // Under collapse-to=\"none\" the host draws the collapsed state itself, so\n // it has to learn the state the element mounted in -- restored from\n // storage or the placement's default -- without waiting for a change.\n // Dispatched directly rather than through setCollapsed, which would write\n // storage and report the unread count for a state nobody changed.\n if (this.#surface().collapseTo === \"none\") {\n this.#emit<ToggleDetail>(TOGGLE_EVENT, { collapsed: this.collapsed });\n }\n this.#skills.init();\n // A `user-key` changed while detached gets the handover a live change gets,\n // here, the first moment it can: nothing goes out for a detached node, a key\n // that left and came back hands nothing over, and the namespace was just\n // claimed again, so another element's is never purged. A first connect skips\n // it, holding nobody's state. Before the store is scoped, so an adoption\n // moves the conversation before the store mints a thread there.\n const held = this.#principalKey;\n const changed = held !== null && held !== this.userKey;\n if (changed) {\n this.#changePrincipal(held, this.userKey);\n }\n this.#principalKey = this.userKey;\n // Namespace the built-in default store too (a host-injected store is used\n // verbatim). Must precede #wireThreadStore, which wraps the current store.\n this.conversationStore = this.#storage.scopeStore(this.#unwrappedStore(), this.userKey);\n window.addEventListener(\"resize\", this.#onViewportResize);\n // The visual viewport changes without the window resizing -- a keyboard\n // opening, a pinch-zoom, the URL bar collapsing -- and `scroll` is what\n // fires when it is panned rather than resized.\n window.visualViewport?.addEventListener(\"resize\", this.#onViewportResize);\n window.visualViewport?.addEventListener(\"scroll\", this.#onViewportResize);\n this.#placement.publishVisualViewport();\n this.#wireThreadStore();\n this.#attachments.wire(this.#connection.signal);\n this.#voice.wire();\n this.#history.adoptActiveThread();\n // The catalog requests go out a microtask later, so a host configuring\n // through a framework ref still has a chance to be heard \u2014 see #startup.\n queueMicrotask(() => this.#startup());\n // A key changed while the element was away handed it over all the same,\n // and the restore is the arriving principal's: reported as the live change\n // is. An adoption is not a handover, and restores the same conversation.\n void this.#history.rehydrate(changed && held !== \"\" ? \"rescope\" : \"restore\");\n if (changed) {\n // The last of what a live change does: a drawer left open across the\n // move still lists the threads of the principal who left, titles and\n // all, until something reloads it. A plain move leaves it alone, since\n // the list it shows is still this principal's.\n void this.#history.refreshDrawer();\n }\n // Last: everything above reads (and some of it sets) attributes, and none\n // of that should trip the connect-time warning.\n this.#connected = true;\n this.#reportMaximized();\n if (this.#newChatOnConnect) {\n this.#newChatOnConnect = false;\n // After the restore above has started: starting the chat stops it, so\n // the one event is the new chat's and the conversation left stays kept.\n this.newChat();\n }\n }\n\n /**\n * The catalog requests the element issues on startup: the tool labels\n * (`data-tools-url`) and the backend skills (`data-skills-url`).\n *\n * Deliberately one microtask behind `connectedCallback`. A framework ref is\n * attached after the node is inserted but within the same commit, so a\n * request issued from `connectedCallback` itself goes out before `headers`,\n * {@link getHeaders} or {@link credentials} exist and 401s in a way that\n * reads as a server fault. A microtask lands after that commit, still before\n * paint.\n *\n * It is not a fix for configuration arriving later than the commit (a passive\n * effect, an awaited token fetch): configure before insertion, or call\n * {@link reload}, since a longer timer would hide that race rather than close\n * it.\n *\n * The history replay stays in `connectedCallback` on purpose. It renders into\n * the transcript, so deferring it would let a `sendMessage()` in the same\n * task land first and be duplicated by the replay.\n */\n #startup(): void {\n // An element can be inserted and removed inside one task (a discarded\n // render, a double-mount); nothing should go out for a node that has\n // already left the document.\n if (!this.#connected) {\n return;\n }\n void this.#tools.fetchCatalog();\n void this.#skills.fetch();\n }\n\n /**\n * Re-run everything the element loads on startup \u2014 the tool-label catalog,\n * the backend skill catalog and the thread's history \u2014 with the transport\n * configuration as it stands now.\n *\n * For a host that can only configure the element after the fact (a token\n * fetched in a passive effect, an async auth handshake), this re-issues the\n * startup requests authenticated, without removing and re-inserting the node.\n *\n * A reload, not a merge: the in-flight run is cancelled and the transcript is\n * rebuilt from persisted history, so anything streamed since is dropped. Call\n * it once, when configuration lands, not between turns.\n */\n async reload(): Promise<void> {\n this.#cancelRun();\n this.#resetState();\n this.#setRunning(false);\n await Promise.all([\n this.#tools.fetchCatalog(),\n this.#skills.fetch(),\n this.#history.rehydrate(\"restore\"),\n ]);\n }\n\n /**\n * Tear down live resources when the element leaves the DOM: cancel the\n * in-flight run so its stream closes, abort in-flight uploads so they do not\n * orphan server-side files, and release the mic so the browser's recording\n * indicator clears. Without this a removed element leaks all three.\n */\n disconnectedCallback(): void {\n this.#connected = false;\n this.#connection.abort();\n window.removeEventListener(\"resize\", this.#onViewportResize);\n window.visualViewport?.removeEventListener(\"resize\", this.#onViewportResize);\n window.visualViewport?.removeEventListener(\"scroll\", this.#onViewportResize);\n this.#storage.release();\n this.#chatRegistration.leave();\n this.#cancelRun();\n this.#excerpts.detachPageOffer();\n this.#attachments.tray?.dispose();\n this.#voice.dispose();\n this.#transcript.disposeScroller();\n this.#announcer.dispose();\n }\n\n /** Parse the inline `data-strings` JSON overrides (empty when absent/malformed). */\n #readStringOverrides(): Partial<UiStrings> {\n const parsed = readJsonAttribute(this, \"data-strings\");\n // A JSON number or string parses fine and overrides nothing. Not warned\n // about separately: it is the same \"this attribute did not take effect\"\n // as a parse failure, and the warning above already covers the spelling\n // that produces it by accident.\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Partial<UiStrings>) : {};\n }\n\n /**\n * Put `text` into the composer as a markdown quotation, and focus it.\n *\n * Deliberately **not** a send. Quoting is how a question narrows to one part\n * of an answer, so the quotation is the preamble and the question is what\n * comes next -- the caret is left after it, on its own line.\n *\n * This is also the seam for the half of this feature the component cannot\n * build: selection in the **host page**. A widget mounted beside a table can\n * be asked about a row, and nothing in a chat's own transcript can offer\n * that. A host reads its own selection, however it likes, and calls this.\n *\n * No-ops on text that is empty or only whitespace.\n */\n quote(text: string): void {\n this.#excerpts.insert(text);\n }\n\n /**\n * Offer to quote what the user selects in the **host page**, not just in the\n * transcript. Returns a function that stops offering.\n *\n * The same select-then-offer gesture, over a table, a diff, a report -- the\n * surface the user actually works in, which is the half of quoting no hosted\n * chat can reach. Opt-in, because it listens on the host's document and that\n * is theirs to grant.\n *\n * Deliberately **not** a four-line recipe, which is how this shipped first\n * and was wrong: a page listener that quotes every settled selection appends\n * to the composer on every drag made to read, to copy or to fix a typo -- and\n * it cannot tell a selection in the page's prose from one inside the user's\n * own half-typed `<input>`, because Chrome reports a field's internal\n * selection as an ordinary range over the field's *wrapper*. See\n * {@link attachQuoteOffer} for the guards.\n *\n * Detached automatically when the element leaves the document; a host that\n * re-mounts it calls this again.\n */\n offerQuoteInPage(within: HTMLElement = document.body): () => void {\n return this.#excerpts.offerInPage(within);\n }\n\n /**\n * When `data-threads-url` is set, route thread enumeration / load / rename /\n * delete through that server endpoint (wrapping the current store as the\n * client-only fallback), so the history drawer shows durable, cross-device\n * threads. Without it, the client store's per-tab threads are used.\n *\n * `data-threads-cache=\"false\"` drops the local copy of the message bodies \u2014\n * for the deployment that pointed history at a server precisely so that\n * transcripts do not sit in the browser. The client-only concerns (the active\n * thread id, the navigation checkpoint) keep their local store either way.\n */\n #wireThreadStore(): void {\n this.#threadStore = null;\n const url = this.getAttribute(\"data-threads-url\");\n if (url !== null) {\n const inner = this.conversationStore;\n const remote = new RemoteConversationStore(\n url,\n () => this.#headersFor(url),\n inner,\n () => this.#requestCredentials(),\n this.getAttribute(\"data-threads-cache\") !== \"false\",\n );\n this.#threadStore = { remote, inner };\n this.conversationStore = remote;\n }\n }\n\n /**\n * The conversation store without the remote this element wrapped it in, so a\n * re-insertion does not stack a second remote, and a `data-threads-url`\n * removed while detached takes it away. A store the host assigned since\n * comes back as it is.\n */\n #unwrappedStore(): ClientConversationStore {\n const wrapped = this.#threadStore;\n return wrapped !== null && this.conversationStore === wrapped.remote\n ? wrapped.inner\n : this.conversationStore;\n }\n\n /**\n * Replace the host-supplied (client) skill catalog. Merged after the embedded\n * and fetched skills (so a client skill overrides a same-named server one).\n */\n setSkills(skills: readonly Skill[]): void {\n this.#skills.setClientSkills(skills);\n }\n\n /** Whether the widget is collapsed (reflected as the `collapsed` attribute). */\n get collapsed(): boolean {\n return this.hasAttribute(\"collapsed\");\n }\n\n // Property setter (framework interop) \u2014 delegates to setCollapsed so a\n // `collapsed` prop assignment persists + emits the toggle event.\n set collapsed(value: boolean) {\n this.setCollapsed(value);\n }\n\n /**\n * Read {@link getPlace} (or the route map standing in) again and redraw the\n * chip. A single-page app calls this after its router moves, since a\n * `pushState` fires no event; history traversal and hash changes are caught\n * without it. Does nothing before the element connects.\n */\n refreshPlace(): void {\n if (!this.isConnected) {\n return;\n }\n this.#place.update(\n this.getPlace === null\n ? placeFromRoute(this.routeMap, window.location.pathname)\n : this.getPlace(),\n );\n }\n\n /**\n * A round's context: the host's, then the place. A withheld place withholds\n * the page map too, so it is filtered out of whatever the host returned.\n */\n #roundContext(): Context[] {\n const context = this.getContext();\n const kept = this.#place.withheld\n ? context.filter((entry) => entry.description !== PAGE_MAP_CONTEXT)\n : context;\n return [...kept, ...this.#place.context()];\n }\n\n /**\n * Set the collapsed state: reflect the `collapsed` attribute, persist it\n * per-tab, and emit a {@link TOGGLE_EVENT} so a host can mirror the state in\n * its own chrome.\n */\n setCollapsed(collapsed: boolean, options: { readonly announce?: boolean } = {}): void {\n if (collapsed && this.#surface().collapseTo === null) {\n return;\n }\n // Collapsing leaves the maximized state, so the panel reopens at its own size.\n if (collapsed) {\n this.setMaximized(false);\n }\n if (options.announce === true && collapsed && !this.collapsed) {\n // Only when the agent did it, and before the state changes, so the notice\n // lands where the user can still see it. No undo: reading it means\n // expanding, which is what the undo would do. Expanding announces nothing,\n // since the panel arriving is the announcement.\n this.#announceSurfaceChange(this.#strings.chatMinimised, null);\n }\n if (!collapsed) {\n this.refreshPlace();\n // Re-decide which way to open before opening: the viewport may have\n // changed since the launcher was dropped, and this corner is what the\n // panel grows from.\n this.#restoreIfBoxed();\n }\n if (collapsed) {\n this.setAttribute(\"collapsed\", \"\");\n } else {\n // The history popover belongs to the bar only while the panel is away.\n // Opening the panel closes it and takes the drawer back, so the panel\n // lands on the conversation rather than on a list over it.\n this.#homeDrawer();\n this.removeAttribute(\"collapsed\");\n }\n this.#syncDock();\n this.#storage.writeSession(COLLAPSED_KEY, collapsed ? \"1\" : \"0\");\n // Expanding reads the thread on screen; other threads keep their marks.\n // Reported on every toggle, as before, with the threads it cleared.\n this.#unreadChanged(this.#markSeen());\n this.dispatchEvent(\n new CustomEvent<ToggleDetail>(TOGGLE_EVENT, {\n detail: { collapsed },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Answers the user has not seen, totalled across threads: each finished while\n * the panel was collapsed, and is read once its thread is on screen with the\n * panel expanded. The launcher's badge renders this; {@link UNREAD_EVENT}\n * announces every change and the threads it touched, so a host chrome can\n * render its own instead.\n */\n get unread(): number {\n let total = 0;\n for (const count of this.#unreadByThread.values()) {\n total += count;\n }\n return total;\n }\n\n /**\n * The thread on screen; `null` before the element first connects.\n *\n * Only reads. `conversationStore.threadId()` mints and stores a thread when\n * the store points at none, so a host asking which conversation is showing\n * could start one; this never does. {@link THREAD_EVENT} says when it changes.\n */\n get threadId(): string | null {\n const threadId = this.#history.threadId;\n return threadId === \"\" ? null : threadId;\n }\n\n /**\n * The title of the thread on screen; `\"\"` while nothing has been sent in it,\n * and before the element connects.\n *\n * A title renamed here, or one the conversation list shows that the thread's\n * messages do not derive (a server's own), wins. Otherwise it is the first\n * user message, and a bare skill `/token` reads as the catalog's title for\n * that skill, else as the token in words. `title-text=\"auto\"` draws it in the\n * header; {@link THREAD_TITLE_EVENT} says when it changes.\n */\n get threadTitle(): string {\n return this.#titled.title;\n }\n\n /**\n * Whether an interaction is in flight: the composer's own state, the one that\n * shows Stop. It spans every tool round, a retry and a checkpoint\n * continuation as well as a send, which {@link SUBMIT_EVENT} alone does not.\n * Reflected as `data-running` on the element, for a host's CSS.\n */\n get running(): boolean {\n return this.#running;\n }\n\n /**\n * The height of the bottom bar in CSS px, and 0 when none is drawn: under\n * any collapse-to but \"bar\", and on a phone while the panel is open, where\n * the panel is the screen. The bar is fixed over the page, so a host pads\n * its own page by this much; {@link BAR_HEIGHT_EVENT} says when it changes.\n */\n get barHeight(): number {\n return this.#barHeight;\n }\n\n /**\n * The width in CSS px a docked panel covers at rest, and 0 when it covers\n * none of the page: the rail while collapsed to it, the panel while open, 0\n * under every other placement, under collapse-to=\"none\" or a launcher while\n * collapsed, on a phone while open (the panel is the screen) and under\n * --ag-ui-position: static, where the host's layout already makes room. The\n * panel is fixed over the page, so a host pads its own by this much;\n * {@link DOCK_WIDTH_EVENT} says when it changes, never per animation frame.\n */\n get dockWidth(): number {\n return this.#dockWidth;\n }\n\n /**\n * The element the panel rises from under collapse-to=\"none\", right-aligned\n * to it: typically the host's own button in its own bar. Takes precedence\n * over the anchor attribute, which names one by selector. One that resolves\n * to nothing leaves the panel in its placement's own corner, with a console\n * warning.\n */\n get anchor(): Element | null {\n return this.#anchor;\n }\n\n set anchor(value: Element | null) {\n this.#anchor = value;\n this.#anchorWarned = false;\n this.#syncDock();\n }\n\n /** The surface the live placement and collapse-to attributes describe. */\n #surface(): Surface {\n return surfaceFor(this.getAttribute(\"placement\"), this.getAttribute(\"collapse-to\"));\n }\n\n /**\n * Stamp what the panel collapses to as data-collapsed-to, which is what the\n * stylesheet draws the bar and the hidden state from. Resolved here rather\n * than in CSS, because \"bar\" over a sidebar is its rail and \"none\" over a\n * page is no collapse at all, and the stylesheet would have to restate that\n * table.\n */\n #stampCollapseTarget(): void {\n const target = this.#surface().collapseTo;\n if (target === null) {\n this.removeAttribute(\"data-collapsed-to\");\n } else {\n this.setAttribute(\"data-collapsed-to\", target);\n }\n }\n\n /** What the panel covers of the page at rest, from state and the panel's own box. */\n #restingDockWidth(): number {\n const placement = this.getAttribute(\"placement\");\n if (\n (placement !== \"sidebar\" && placement !== \"side\") ||\n !this.#hasBox() ||\n getComputedStyle(this).position === \"static\"\n ) {\n return 0;\n }\n if (this.collapsed) {\n return this.#surface().collapseTo === \"rail\" ? this.#launcher.offsetWidth : 0;\n }\n const phone =\n this.getAttribute(\"data-small-viewport\") !== \"off\" && window.matchMedia(PHONE_QUERY).matches;\n return phone ? 0 : this.#chat.offsetWidth;\n }\n\n /** Tell the host when the docked width, or the edge it docks against, changed. */\n #syncDockWidth(): void {\n // A drag-resize reports once, when it ends.\n if (this.#placement.dragging()) {\n return;\n }\n const width = this.#restingDockWidth();\n const side = this.getAttribute(\"data-side\") === \"left\" ? \"left\" : \"right\";\n if (width === this.#dockWidth && (width === 0 || side === this.#dockSide)) {\n return;\n }\n this.#dockWidth = width;\n this.#dockSide = side;\n this.#emit<DockWidthDetail>(DOCK_WIDTH_EVENT, { width, side });\n }\n\n /** Re-measure the bar or the anchor, and tell the host when the bar's height changed. */\n #syncDock(): void {\n // isConnected rather than the connected flag, which connectedCallback\n // sets only at its end, after the first measurement here.\n if (!this.isConnected) {\n return;\n }\n // With no box there is no bar drawn, which the host still hears of, and nothing to\n // measure: syncing would place a dragged panel from a rect of nothing. Showing this\n // element resizes the bar or the transcript, and their observers sync it then.\n const height = this.#hasBox()\n ? this.#placement.syncDock(this.#dockBar, this.#resolveAnchor())\n : 0;\n this.#syncDockWidth();\n if (height === this.#barHeight) {\n return;\n }\n this.#barHeight = height;\n this.#emit<BarHeightDetail>(BAR_HEIGHT_EVENT, { height });\n }\n\n /**\n * The anchor in force under collapse-to=\"none\": the property, else the\n * attribute's selector, looked up in the root this element lives in and\n * then the document, so a chat inside a framework's shadow root can name a\n * button beside it. Null under any other collapse-to, with nothing given,\n * or when what was given is not in the document -- reported once per anchor.\n */\n #resolveAnchor(): Element | null {\n if (this.#surface().collapseTo !== \"none\") {\n return null;\n }\n const selector = this.getAttribute(\"anchor\") ?? \"\";\n if (this.#anchor === null && selector === \"\") {\n return null;\n }\n const found = this.#anchor ?? findAnchor(this.getRootNode(), selector);\n if (found?.isConnected === true) {\n return found;\n }\n if (!this.#anchorWarned) {\n this.#anchorWarned = true;\n console.warn(\n `<ag-ui-chat>: the anchor ${this.#anchor === null ? `\"${selector}\"` : \"element\"} ` +\n \"is not in the document, so the panel opens from its placement's own corner.\",\n );\n }\n return null;\n }\n\n /**\n * Whether to mount collapsed.\n *\n * A stored choice wins in either direction. With nothing stored, the corner\n * placements, the two with a launcher, start collapsed unless\n * `data-start-open`; the placements that place themselves start open, since a\n * host that docks or embeds the widget has given it room.\n */\n #startsCollapsed(): boolean {\n const stored = this.#storage.readScopedItem(COLLAPSED_KEY);\n if (stored !== null) {\n return stored === \"1\";\n }\n return this.#surface().startsCollapsed && !this.hasAttribute(\"data-start-open\");\n }\n\n /**\n * Describe the panel to whoever is asking -- in practice the agent, through\n * the opt-in chat-surface tools.\n *\n * `movable` folds two separate reasons into the one answer a caller needs:\n * a placement that places itself owns its position, and a panel that fills\n * the screen has nowhere to go. Reporting them apart would make every caller\n * re-derive the same conjunction. A corner panel docked under\n * `collapse-to=\"bar\"` or `\"none\"` is movable on a wide viewport, like the\n * corner panel it is.\n */\n describeSurface(): ChatSurfaceReport {\n return this.#placement.describeSurface();\n }\n\n /**\n * Send the panel to a corner, and report whether it went.\n *\n * A third claimant on the axes a placement and a user drag already share, and\n * it takes them the same way the drag does rather than inventing a second\n * mechanism: the same commit path, so the launcher travels with the panel,\n * the corner it opens from is re-picked, and switching placement hands\n * everything back. What it must not do is claim a move it did not make --\n * hence the boolean, and hence {@link describeSurface} existing so a caller\n * can ask first. A docked panel moves too, within the room above its bar or\n * anchor, and remembers the spot as a header drag would.\n */\n moveTo(corner: ChatCorner, options: { readonly announce?: boolean } = {}): boolean {\n return this.#placement.moveTo(corner, options);\n }\n\n /**\n * Drop the size the user dragged in the current placement, and its stored\n * copy, so the placement's default and the host's `--ag-ui-width` /\n * `--ag-ui-height` apply again. Other placements keep theirs.\n * Under `collapse-to=\"bar\"` or `\"none\"` it also returns a panel the user\n * dragged off its dock to the dock, and forgets the stored spot; a corner\n * panel keeps a dragged position.\n */\n resetSize(): void {\n this.#placement.resetSize();\n this.#syncDock();\n }\n\n /**\n * Whether the panel is maximized (reflected as the `maximized` attribute).\n * Never stored: a reload opens at the placement's own size.\n */\n get maximized(): boolean {\n return this.#maximized;\n }\n\n set maximized(value: boolean) {\n this.setMaximized(value);\n }\n\n /**\n * Grow the open panel to `--ag-ui-maximized-width` / `--ag-ui-maximized-height`,\n * or restore it to the size it had, and emit a {@link MAXIMIZE_EVENT}. Refused\n * where the header offers no control: `page`, `full`, `embedded`, an unknown\n * placement, and a viewport of 600px or less.\n */\n setMaximized(maximized: boolean): void {\n if (maximized) {\n this.setAttribute(\"maximized\", \"\");\n } else {\n this.removeAttribute(\"maximized\");\n }\n }\n\n /** Flip the maximized state. Bound to the built-in header control. */\n toggleMaximized(): void {\n this.setMaximized(!this.#maximized);\n }\n\n /** Whether the header offers the maximize control here, now. */\n #maximizable(): boolean {\n return this.#surface().maximizes !== null && !window.matchMedia(PHONE_QUERY).matches;\n }\n\n /** The one path into and out of the state: the attribute's. */\n #applyMaximized(asked: boolean): void {\n const maximized = asked && this.#maximizable() && !this.collapsed;\n if (asked && !maximized) {\n this.removeAttribute(\"maximized\");\n return;\n }\n if (maximized === this.#maximized) {\n return;\n }\n this.#maximized = maximized;\n if (this.#connected) {\n if (maximized) {\n this.#placement.enterMaximized();\n } else {\n this.#placement.leaveMaximized();\n }\n this.#syncDock();\n }\n this.#paintMaximizeControl();\n this.#reportMaximized();\n }\n\n /** Tell listeners the state once it differs from what they last heard; a mount defers it. */\n #reportMaximized(): void {\n if (!this.#connected || this.#maximized === this.#maximizedHeard) {\n return;\n }\n this.#maximizedHeard = this.#maximized;\n this.#emit<MaximizeDetail>(MAXIMIZE_EVENT, { maximized: this.#maximized });\n }\n\n /** Offer the control where a placement has one and leave the state where it has not. */\n #syncMaximizeControl(): void {\n const offered = this.#maximizable();\n if (!offered) {\n this.setMaximized(false);\n }\n const control = this.#maximizeControl;\n if (control === null) {\n return;\n }\n if (!offered) {\n control.button.remove();\n } else if (!control.button.isConnected) {\n control.before.before(control.button);\n }\n }\n\n /** Name the control for what pressing it does now. */\n #paintMaximizeControl(): void {\n const button = this.#maximizeControl?.button;\n if (button === undefined) {\n return;\n }\n const label = this.#maximized ? this.#strings.restore : this.#strings.maximize;\n button.title = label;\n button.setAttribute(\"aria-label\", label);\n fillSlotFallback(button, this.#maximized ? ICON_RESTORE : ICON_MAXIMIZE);\n }\n\n /** Draw the collapse mark data-collapse-icon chooses, or the placement's default. */\n #paintCollapseControl(): void {\n const button = this.#collapseControl;\n if (button === null) {\n return;\n }\n const glyph = collapseGlyph(\n this.getAttribute(\"data-collapse-icon\"),\n this.getAttribute(\"placement\"),\n this.getAttribute(\"data-side\"),\n );\n fillSlotFallback(button, glyph);\n }\n\n /** Flip the collapsed state. Bound to the built-in header toggle. */\n toggleCollapsed(): void {\n this.setCollapsed(!this.collapsed);\n }\n\n /**\n * Flip the scheme word of the `theme` attribute between `light` and `dark`\n * and persist the choice per tab. Bound to the optional built-in header theme\n * toggle (`data-theme-toggle`). The theme name and any host words are kept:\n * `soft` becomes `soft dark`, and `soft dark` becomes `soft light`. With no\n * scheme word (`auto`, or a host rule setting `color-scheme` on the element),\n * it flips away from the scheme the panel is drawn in.\n */\n toggleTheme(): void {\n // Only the scheme word flips, so a named theme survives the toggle:\n // \"soft\" becomes \"soft dark\", and \"soft dark\" becomes \"soft light\". And\n // only the scheme word is saved: the name is the host's, and a name saved\n // on one page would replace another page's theme on restore.\n const theme = this.getAttribute(\"theme\") ?? \"\";\n const scheme = this.#drawnScheme() === \"dark\" ? \"light\" : \"dark\";\n this.setAttribute(\"theme\", withScheme(theme, scheme));\n this.#storage.writePreference(THEME_KEY, scheme);\n }\n\n /**\n * Move the element's client state from one principal to another.\n *\n * `sessionStorage` outlives a logout and nothing remounts, so the host naming\n * the new principal is the only signal the element gets.\n *\n * A live change runs all of it. connectedCallback runs it for a key changed\n * while detached, before the store is scoped and before `#connected` is set\n * (which `live` reads), and there only the half about what storage and the\n * element still hold: the arriving half is what connecting goes on to do.\n */\n #changePrincipal(previousKey: string, nextKey: string): void {\n this.#principalKey = nextKey;\n const live = this.#connected;\n const previous = this.#storage.conversationNamespace(previousKey);\n const next = this.#storage.conversationNamespace(nextKey);\n if (previousKey === \"\") {\n // Absent to present is not a handover. It is the documented late\n // configuration shape \u2014 the element mounts, an auth handshake resolves,\n // and only then is the user known \u2014 so the conversation already on screen\n // belongs to this principal and moves with them. Moving rather than\n // copying also matters: a copy left behind under the unscoped namespace\n // is a transcript the next key-less mount would happily adopt.\n SessionStorageStore.adopt(previous, next);\n if (live) {\n this.#rescopeStore(next);\n }\n return;\n }\n // First, ahead of the purge: from here on, nothing a client built for the\n // previous principal does is written anywhere. See #tenure.\n this.#tenure = {};\n SessionStorageStore.purge(previous);\n if (live) {\n this.#rescopeStore(next);\n }\n // An Always allow is the previous principal's decision too, and it lives in\n // memory rather than in the store just purged, so it has to be forgotten\n // here or it outlives them. The adoption above keeps it, for the same\n // reason it keeps the conversation: the same person is still there.\n this.#dispatch.forgetWaivers();\n // The transcript on screen, the run in flight and the replayed history all\n // belong to the principal who just left. Purging storage without clearing\n // these would leave the previous user's conversation visible to the new one.\n this.#cancelRun();\n this.#resetState();\n // Shared state too, and only here (New chat keeps it): it seeds the next\n // client, so it would go out as the new principal's first run state.\n this.#sharedState = {};\n // And the unsent turn, also only here: the previous principal's words.\n // Through the input handler, so the hint and slash palette come down too.\n this.#input.value = \"\";\n this.#onInput();\n this.#setRunning(false);\n // The previous principal's marks go with their threads, unread: nobody saw them.\n this.#forgetUnread([...this.#unreadByThread.keys()], true);\n if (!live) {\n return;\n }\n // A recording in progress is theirs too: taking the mic down ends it\n // untranscribed, and a fresh one leaves the next principal a working\n // control. A detached change has been through both already.\n this.#voice.dispose();\n this.#voice.wire();\n this.#history.adoptActiveThread();\n void this.#history.rehydrate(\"rescope\");\n void this.#history.refreshDrawer();\n }\n\n /**\n * Rebuild the `sessionStorage` store under `namespace`, re-wrapping it for\n * `data-threads-url` exactly as connecting did.\n *\n * A store the host assigned scopes itself and is left alone, except a plain\n * `SessionStorageStore` assigned before connecting, which connecting took for\n * the element's own; so the store in use is what the scope is asked about.\n */\n #rescopeStore(namespace: string): void {\n const store = this.#storage.rescopeStore(this.#unwrappedStore(), namespace);\n if (store === null) {\n return;\n }\n this.conversationStore = store;\n this.#wireThreadStore();\n }\n\n /**\n * The scheme the panel is drawn in, which the toggle flips and its glyph\n * offers the way out of. A scheme word decides it, since the scheme rules\n * hold against a host's. Without one the panel follows whatever sets its\n * color-scheme: a host rule on the element, auto's \"light dark\", or the\n * light default. Both schemes allowed means the system picks. Read before\n * the shadow styles apply too (the glyph is drawn first), when the computed\n * value carries only a host rule, so auto is answered from its word.\n */\n #drawnScheme(): \"light\" | \"dark\" {\n const words = (this.getAttribute(\"theme\") ?? \"\").split(/\\s+/);\n if (words.includes(\"dark\")) {\n return \"dark\";\n }\n if (words.includes(\"light\")) {\n return \"light\";\n }\n const declared = getComputedStyle(this).colorScheme.split(/\\s+/);\n const dark = declared.includes(\"dark\");\n if (dark !== declared.includes(\"light\")) {\n return dark ? \"dark\" : \"light\";\n }\n if (dark || words.includes(\"auto\")) {\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n }\n return \"light\";\n }\n\n /** Reflect the current theme on the toggle: show the destination's glyph. */\n #syncThemeGlyph(): void {\n const dark = this.#drawnScheme() === \"dark\";\n // Replaced wholesale rather than toggling a class: the two marks are\n // different paths, not one path in two states, and the slot has to keep\n // working so a host can still supply its own.\n this.#themeToggle.replaceChildren(\n iconElement(\"theme\", \"theme-icon\", dark ? ICON_SUN : ICON_MOON, null),\n );\n }\n\n /**\n * Open the thread-history drawer: the imperative route to the control that\n * renders as `::part(history-button)`.\n *\n * A host that hides `::part(header)` for its own title bar hides the history,\n * new-chat and collapse buttons with it. Each has a method so that chrome can\n * be rebuilt: this one, {@link openCheckpoints}, {@link newChat},\n * {@link toggleCollapsed} and {@link toggleTheme}.\n */\n openThreads(options: { readonly anchor?: Element } = {}): void {\n // Collapsed into the bar, the list opens as a popover over the bar rather\n // than expanding the panel: the same drawer, moved beside the bar, since\n // nothing inside the hidden panel can be drawn. Under the host's own bar it\n // opens beside the host's button, and a pick leaves the panel to the host.\n const target = this.#surface().collapseTo;\n const anchor = options.anchor ?? this.#resolveAnchor();\n // An embedded chat collapsed under none is not drawn at all, popover included.\n const drawn = this.getAttribute(\"placement\") !== \"embedded\";\n if (this.collapsed && target === \"bar\") {\n this.#dockBar.append(this.#drawer.element);\n } else if (this.collapsed && target === \"none\" && anchor !== null && drawn) {\n this.#threadsAnchor = anchor;\n this.#threadsPopover.append(this.#drawer.element);\n this.#placeThreadsPopover();\n } else {\n if (this.collapsed && target === \"none\") {\n console.warn(\n drawn\n ? '<ag-ui-chat>: openThreads() under collapse-to=\"none\" needs an anchor to open ' +\n \"beside; pass openThreads({ anchor }) or set the anchor attribute.\"\n : '<ag-ui-chat>: openThreads() under placement=\"embedded\" and collapse-to=\"none\" ' +\n \"has no popover: the collapsed chat is not drawn. Expand it first.\",\n );\n }\n this.#homeDrawer();\n }\n this.#history.openThreads();\n }\n\n /**\n * Stand the popover on its button: below one in the top half of the viewport,\n * above one in the bottom half, right-aligned to it and held inside the window.\n */\n #placeThreadsPopover(): void {\n const anchor = this.#threadsAnchor;\n if (anchor === null || this.#drawer.element.parentNode !== this.#threadsPopover) {\n return;\n }\n const rect = anchor.getBoundingClientRect();\n const width = document.documentElement.clientWidth;\n const height = document.documentElement.clientHeight;\n const below = rect.top + rect.height / 2 < height / 2;\n const list = Math.min(THREADS_POPOVER_WIDTH, width - 2 * THREADS_POPOVER_GAP);\n const right = Math.min(\n Math.max(THREADS_POPOVER_GAP, width - rect.right),\n width - THREADS_POPOVER_GAP - list,\n );\n const room = (below ? height - rect.bottom : rect.top) - 2 * THREADS_POPOVER_GAP;\n this.style.setProperty(\n \"--_threads-top\",\n below ? `${rect.bottom + THREADS_POPOVER_GAP}px` : \"auto\",\n );\n this.style.setProperty(\n \"--_threads-bottom\",\n below ? \"auto\" : `${height - rect.top + THREADS_POPOVER_GAP}px`,\n );\n this.style.setProperty(\"--_threads-right\", `${Math.max(THREADS_POPOVER_GAP, right)}px`);\n this.style.setProperty(\"--_threads-room\", `${Math.max(0, room)}px`);\n }\n\n /**\n * Put the drawer back in the panel, where every surface but the bar's\n * popover draws it. A popover still open is closed first: the list was\n * opened over the bar, and carried into the panel it would cover the\n * conversation the user asked to see.\n */\n #homeDrawer(keep: Node | null = null): void {\n const away = this.#drawer.element.parentNode;\n if (away !== keep && (away === this.#dockBar || away === this.#threadsPopover)) {\n this.#drawer.close();\n this.#chat.insertBefore(this.#drawer.element, this.#checkpoints.element);\n this.#threadsAnchor = null;\n for (const name of [\"top\", \"bottom\", \"right\", \"room\"]) {\n this.style.removeProperty(`--_threads-${name}`);\n }\n }\n }\n\n /**\n * Open the checkpoints panel (the `::part(checkpoints-button)` route).\n *\n * It lists the runs the `data-runs-url` server reports as continuable;\n * without that attribute the built-in button is never rendered and this opens\n * an empty panel.\n */\n openCheckpoints(): void {\n this.#history.openCheckpoints();\n }\n\n /** Close the conversation list, if it is open. */\n closeThreads(): void {\n this.#drawer.close();\n }\n\n /** Close the checkpoints panel, if it is open. */\n closeCheckpoints(): void {\n this.#checkpoints.close();\n }\n\n /**\n * Put a stored thread on screen, as picking it in the conversation list does,\n * for a host that lists conversations in its own chrome.\n *\n * Resolves once the thread has been replayed, when {@link THREAD_EVENT} has\n * fired; a second call for the thread already loading settles with that load.\n * If the store rejects the load, the element stays on the thread it was on,\n * fires nothing, and the promise rejects with the store's error.\n * **A run in flight is cancelled**, as the list and {@link newChat} do;\n * a host that would rather wait reads {@link running} first. The thread\n * already on screen is left alone, and so is everything before the element\n * connects, since until then it has no store to read the thread from.\n */\n switchThread(threadId: string): Promise<void> {\n if (!this.#connected) {\n return Promise.resolve();\n }\n return this.#history.switchThread(threadId);\n }\n\n /**\n * Delete a stored thread, as the conversation list's delete does. Deleting the\n * thread on screen cancels its run and puts a fresh thread in its place, and\n * {@link THREAD_EVENT} reports it; deleting another leaves the screen alone.\n * Does nothing before the element connects.\n */\n deleteThread(threadId: string): void {\n if (!this.#connected) {\n return;\n }\n this.#history.deleteThread(threadId);\n }\n\n /**\n * Open the checkpoints panel, or close it if it is already open \u2014 what the\n * built-in checkpoints button does, because a control that opens a panel is read as the\n * control that also dismisses it. {@link openCheckpoints} stays open-only for a\n * host that means exactly that.\n */\n toggleCheckpoints(): void {\n if (this.#checkpoints.open_) {\n this.#checkpoints.close();\n return;\n }\n this.openCheckpoints();\n }\n\n /**\n * Start a fresh conversation: drop the in-memory run state, clear the\n * transcript, and mint a new thread id.\n *\n * The conversation being left is kept, and stays in the history drawer to\n * return to. Deleting one is the drawer row's own action; a button that\n * starts something new must not be the button that destroys what was there.\n *\n * Focus moves to the composer, unless the widget is collapsed and the\n * composer is not on screen: starting a conversation is a request to type\n * one. The page is not scrolled to bring the composer into view.\n */\n newChat(): void {\n // Before the element connects it has no store scoped to its namespace and\n // no thread to leave, and minting one would write to the unscoped store and\n // fire an event for a thread it does not yet show. Connecting starts it.\n if (!this.#connected) {\n this.#newChatOnConnect = true;\n return;\n }\n // Stop any in-flight run first \u2014 discarding the client mid-run would\n // leave the old agent streaming into a cleared transcript.\n this.#cancelRun();\n this.#history.reapUnsent();\n this.#resetState();\n this.#history.startThread();\n this.#setRunning(false);\n this.#dispatchThread(this.#history.threadId, \"new\");\n // Whichever control started it, focus returns to the emptied field, without\n // scrolling: a host resetting a chat further down the page did not ask for\n // the page to move or a phone keyboard to open.\n if (!this.collapsed) {\n this.#input.focus({ preventScroll: true });\n }\n }\n\n /** Drop the in-memory run + transcript, leaving the thread id untouched. */\n #resetState(): void {\n this.#resetConversation();\n // The composer's own history goes with the conversation it was typed\n // into. The path that makes this more than tidiness is the `user-key`\n // rescope, which purges storage and wipes the transcript precisely so the\n // previous principal's words are not visible to the next one -- and would\n // otherwise leave every one of them a single ArrowUp away.\n this.#sentDrafts.length = 0;\n this.#recallIndex = null;\n }\n\n /**\n * Drop the in-memory run and transcript, and nothing the user typed.\n *\n * Split from {@link #resetState} for re-insertion, which rebuilds the\n * conversation from history but is not a new one, so the composer's recall\n * history stays.\n */\n #resetConversation(): void {\n this.#client = null;\n // Every path here has just cancelled the run, but a cancelled run ends\n // later: once its request closes, or once a host tool's handler returns.\n // Whatever it says then is about the conversation being cleared, so it must\n // not draw into this one, put a new run's Stop back to Send, or report the\n // new conversation's tools as its own.\n this.#runHandlers.detach();\n // A frontend tool call of that run can resume later still, for the same\n // reason, and must not draw into this one either: see #conversation.\n this.#conversation = {};\n this.#clearTranscript();\n this.#history.forgetRestored();\n }\n\n /**\n * Wipe the rendered transcript and everything that indexes into it.\n *\n * Split from {@link #resetState} because a retry re-renders the transcript\n * while keeping the *client*: dropping the client there would take the\n * agent's message list with it, which is the thing being truncated.\n */\n #clearTranscript(): void {\n // Before the transcript goes: a render still queued would otherwise fire\n // against the wiped list and open a fresh bubble holding the discarded\n // conversation's last tokens.\n this.#stream.end();\n this.#transcript.releaseTurn();\n // The panels go with the cards they hung off.\n this.#subagents.clear();\n this.#transcript.forgetCards();\n this.#activities.clearBlocks();\n this.#actions.forget();\n this.#attachments.tray?.clear();\n // Returning to an empty conversation snaps back to the centre: only the send\n // that left it travels. And whatever restore was holding the layout back is\n // no longer this transcript's, so a new chat started mid-restore greets the\n // user rather than waiting on a load it has abandoned.\n this.removeAttribute(\"data-composer-settling\");\n this.removeAttribute(\"data-restoring\");\n // Keep the empty-state region; everything else clears.\n this.#transcript.empty();\n }\n\n /**\n * Ask the same question again and replace the answer.\n *\n * History is truncated to the most recent user message inclusive and the run\n * repeats, so the agent answers what it was asked rather than being told its\n * last answer was wrong. Returns `false` when there is nothing to retry, or\n * while anything that holds a send is in flight: a run, a send or another\n * retry whose run has not started yet, a checkpoint continuation, or a\n * restore of the stored conversation that is still loading. It does not wait\n * for a restore as a send does: nothing is on screen to retry yet, and after\n * the load it would re-ask the previous visit's last question. Also `false`\n * when host code it\n * runs before its run starts -- the store's save, or an activity or tool\n * renderer the replay draws through -- has stopped it by starting a new chat\n * or changing `user-key`. A tool or context provider that stops it does so\n * inside the client's resume, past the last point this can see: nothing is\n * sent, and this resolves `true`, because both a run starting and a Stop let\n * go of the hold it checks. Rejects with the store's error when the store\n * refuses the save, and then the conversation is as it was.\n *\n * Public because a host with its own message UI wants the same button, and\n * because the failed-run notice reaches it from outside the action row.\n *\n * **A retried turn re-runs its tools**, which for a page-driving agent is not\n * neutral: the previous attempt already clicked what it clicked, and this\n * does not undo it. Confirmation still applies, so a destructive tool asks\n * again -- unless the user waived it for this session.\n */\n async retryLastTurn(): Promise<boolean> {\n // Refused for whatever refuses a send, since it starts a run on the same\n // client: a held send and a picked checkpoint's continuation included.\n if (this.#busy()) {\n return false;\n }\n // Held from here as a send is, since the run starts a microtask after it is\n // asked for. Released once it starts, by `#setRunning`, and below otherwise.\n const hold = {};\n this.#sending = hold;\n try {\n const client = this.#ensureClient();\n const kept = client.truncateToLastUser();\n if (kept === null) {\n return false;\n }\n // The truncation saved through the host's store, whose code may have\n // started a new chat or changed `user-key`, and so stopped the Retry.\n if (this.#sending !== hold) {\n return false;\n }\n // Re-render between the truncation and the run: the kept turns replay as\n // restored history (static, no entrance animation), and only the new\n // answer arrives live. Streaming into the old transcript would put the\n // new answer underneath the one it replaces.\n this.#clearTranscript();\n for (const message of kept) {\n this.#history.replay(message);\n // A replay draws through host renderers, which can stop it the same way.\n if (this.#sending !== hold) {\n return false;\n }\n }\n await client.resume();\n return true;\n } finally {\n // Only its own hold, as a send's end releases only its own. A turn the\n // composer queued behind it is sent from here when its run never started,\n // because no run settles to send it.\n this.#releaseHold(hold);\n }\n }\n\n /**\n * Append a message bubble and return it.\n *\n * Assistant content renders as sanitised markdown/HTML; user content stays\n * literal text, which also avoids rendering user-authored markup.\n *\n * Assistant bubbles land in the current answer group, opening one if needed;\n * a user bubble closes the prior group and sits directly in the list, the\n * well wrapping only the assistant turn.\n */\n appendMessage(role: MessageRole, content: string): HTMLDivElement {\n return this.#transcript.append(role, content);\n }\n\n /**\n * Build the chrome, from the attributes as they stand.\n *\n * Runs on every connect, not once, because removing and re-inserting the\n * element is the documented way to apply a connect-time attribute written\n * late. So it has to build the same element the second time as the first:\n * the elements made here are new each time, the long-lived ones it fills\n * are filled with `replaceChildren` rather than appended to, and every\n * listener on a long-lived one goes under the connection's signal.\n */\n #render(): void {\n const { signal } = this.#connection;\n this.#chat.className = \"chat\";\n this.#chat.setAttribute(\"part\", \"panel\");\n\n const titleText = this.#titleText();\n const themed = this.getAttribute(\"data-theme-toggle\") !== null;\n const { header, checkpoints, maximize, collapse } = buildHeader({\n host: this,\n title: this.#title,\n titleText,\n iconUrl: this.getAttribute(\"data-icon-url\"),\n strings: this.#strings,\n // Asks the history's run index rather than re-testing the attribute, so\n // \"configured\" means one thing everywhere (an empty value is unset, not a\n // relative URL to the current page).\n withCheckpoints: this.#history.runs() !== null,\n themeToggle: themed ? this.#themeToggle : null,\n signal,\n onHistory: () => this.openThreads(),\n onCheckpoints: () => this.toggleCheckpoints(),\n onNewChat: () => this.newChat(),\n onCollapse: () => this.toggleCollapsed(),\n onMaximize: () => this.toggleMaximized(),\n onToggleTheme: () => this.toggleTheme(),\n });\n if (themed) {\n this.#syncThemeGlyph();\n }\n\n // A panel is a window and a header is its title bar.\n this.#placement.enablePanelDrag(header);\n this.#maximizeControl = { button: maximize, before: collapse };\n this.#collapseControl = collapse;\n this.#paintCollapseControl();\n this.#syncMaximizeControl();\n this.#paintMaximizeControl();\n window\n .matchMedia(PHONE_QUERY)\n .addEventListener(\"change\", () => this.#syncMaximizeControl(), { signal });\n\n buildTranscript({\n messages: this.#messages,\n jumpButton: this.#jumpButton,\n emptyWrap: this.#emptyWrap,\n greetingText: this.#greetingText,\n starters: renderStarterChips(this, this.#strings, (prompt) => {\n void this.sendMessage(prompt);\n }),\n strings: this.#strings,\n });\n this.#syncGreeting();\n\n // The quote offer, and the transcript's settled selections it listens for.\n this.#excerpts.mount(signal);\n\n // Built here rather than at field initialisation: the viewport has to exist\n // and the observer has to have something to observe.\n this.#transcript.mountScroller(this.#jumpButton, signal);\n\n this.#announcer.mount();\n\n this.#messages.append(this.#emptyWrap);\n // Stamped from the first frame, so a page that mounts empty is laid out as\n // empty rather than switching to it on the first change.\n this.#transcript.updateEmptyState();\n\n const inputRow = buildComposer({\n input: this.#input,\n send: this.#send,\n attachButton: this.#attachButton,\n fileInput: this.#fileInput,\n voiceSlot: this.#voiceSlot,\n place: this.#place.element,\n hint: this.#composerHint,\n queuedRow: this.#queuedRow,\n attachSlot: this.#attachSlot,\n strings: this.#strings,\n signal,\n onKeydown: (event) => this.#onKeydown(event),\n onInput: () => this.#onInput(),\n onSend: () => {\n // One button, two states: Send while idle, Stop while a run is in\n // flight (no layout change).\n if (this.#running) {\n this.#cancelRun();\n return;\n }\n void this.#submit();\n },\n onFilesPicked: () => this.#attachments.onFilesPicked(),\n });\n\n this.#place.mount(signal, this.#strings);\n this.#input.addEventListener(\"focus\", () => this.refreshPlace(), { signal });\n window.addEventListener(\"popstate\", () => this.refreshPlace(), { signal });\n window.addEventListener(\"hashchange\", () => this.refreshPlace(), { signal });\n this.refreshPlace();\n\n // Host content against the input, after everything of the turn being\n // written. A bare slot, whose own box is none, so an empty one takes no\n // space and the greeting layout carries a filled one with the composer.\n const aboveComposer = document.createElement(\"slot\");\n aboveComposer.name = \"above-composer\";\n\n const footer = document.createElement(\"slot\");\n footer.name = \"footer\";\n\n this.#messagesWrap.className = \"messages-wrap\";\n // Sibling of the list inside a shared box, not a child of it: the\n // affordance offering to scroll must not scroll away with the content.\n this.#messagesWrap.replaceChildren(this.#messages, this.#jumpButton, this.#excerpts.button);\n\n // Composer surfaces sit just above the input: the skills palette (opens on\n // `/`), the chips, the hint saying what the composer still needs, the\n // queued messages and the pending-attachments tray, then the host's own\n // content directly over the input.\n this.#chat.replaceChildren(\n header,\n this.#messagesWrap,\n this.#skillsMenu.palette,\n this.#skillsMenu.chips,\n this.#composerHint,\n this.#queuedRow,\n this.#attachSlot,\n aboveComposer,\n inputRow,\n footer,\n this.#drawer.element,\n this.#checkpoints.element,\n );\n\n // Clicking away dismisses the checkpoints popover. Escape already did, and the\n // drawer has a backdrop that swallows the click \u2014 this popover has neither, so\n // it could only be closed by answering it.\n //\n // `pointerdown`, and the header button excluded: pointerdown runs *before* the\n // button's own click, so closing here and toggling there would land back open.\n // Composed path rather than `target`, because the event is retargeted at the\n // shadow boundary and every one of these nodes is inside it.\n this.#chat.addEventListener(\n \"pointerdown\",\n (event) => {\n if (!this.#checkpoints.open_) {\n return;\n }\n const path = event.composedPath();\n if (path.includes(this.#checkpoints.element) || path.includes(checkpoints)) {\n return;\n }\n this.#checkpoints.close();\n },\n { signal },\n );\n\n buildLauncher({\n launcher: this.#launcher,\n badge: this.#badge,\n railLabel: this.#railLabel,\n bar: this.#dockBar,\n barHistory: this.#barHistory,\n barPlace: this.#place.barElement,\n titleText,\n iconUrl: readLauncherIconUrl(this),\n strings: this.#strings,\n signal,\n // The bar stays on screen with the panel open, as the way to minimise\n // it, so its strip toggles; everywhere else the launcher is only drawn\n // while collapsed and only ever opens.\n onOpen: () => this.setCollapsed(this.#surface().collapseTo === \"bar\" && !this.collapsed),\n // The bar's history button toggles: the popover has no backdrop, and a\n // press on the bar is not a press outside it, so this is how the button\n // that opened the list closes it again. openThreads() stays open-only.\n onHistory: () => {\n if (this.#drawer.isOpen()) {\n this.#drawer.close();\n } else {\n this.openThreads();\n }\n },\n });\n // Neither popover has a backdrop to catch a click away, so a press outside\n // closes it, as Escape already does. The bar, or the list and the host's\n // button, are not outside: that button toggles the list itself.\n document.addEventListener(\n \"pointerdown\",\n (event) => {\n const away = this.#drawer.element.parentNode;\n if (!this.#drawer.isOpen() || (away !== this.#dockBar && away !== this.#threadsPopover)) {\n return;\n }\n const path = event.composedPath();\n const own: readonly (Node | null)[] =\n away === this.#dockBar ? [away] : [away, this.#threadsAnchor];\n if (!path.some((node) => own.includes(node as Node))) {\n this.#drawer.close();\n }\n },\n { signal },\n );\n window.addEventListener(\"resize\", () => this.#placeThreadsPopover(), { signal });\n this.#placement.enableLauncherDrag(signal);\n\n this.#placement.mountResizeGrips(this.#chat);\n this.#builtInSheet = adoptStyles(this.#root, this.#extraStyles);\n const probe = this.#placement.probe;\n probe.className = \"viewport-probe\";\n probe.setAttribute(\"aria-hidden\", \"true\");\n // A transition, so a token changing is an event. On the corners of a box with no\n // size, which draw nothing: a margin would push it out by the token again, and that\n // is scroll on a page or a card holding the chat. Not on the padding, which the\n // viewport is read from and has to stay instant.\n probe.style.borderRadius =\n \"var(--_viewport-inset-top) var(--_viewport-inset-right) var(--_viewport-inset-bottom) var(--_viewport-inset-left)\";\n probe.style.transition = \"border-radius 1ms\";\n this.#threadsPopover.className = \"threads-popover\";\n this.#root.replaceChildren(\n probe,\n this.#announcer.region,\n this.#chat,\n this.#dockBar,\n this.#threadsPopover,\n );\n }\n\n /**\n * Reflect the collapsed state and the unread count on the launcher.\n *\n * The count is also the launcher's accessible name: a badge that only exists\n * as a coloured dot says nothing to a screen reader, and \"Expand\" alone would\n * be a lie once answers are waiting behind it.\n */\n #syncLauncher(): void {\n this.#launcher.setAttribute(\"aria-expanded\", String(!this.collapsed));\n const unread = this.unread;\n // Past 9 the exact number stops being information and starts being a\n // layout problem \u2014 the badge is a circle, not a field.\n this.#badge.textContent = unread > 9 ? \"9+\" : String(unread);\n // Only on the collapsed launcher: an open panel can now hold another\n // thread's unseen answers, and the launcher behind it is not where to say so.\n this.#badge.hidden = unread === 0 || !this.collapsed || !isUnreadBadgeEnabled(this);\n const label =\n !this.collapsed && this.#surface().collapseTo === \"bar\"\n ? this.#strings.collapse\n : this.#badge.hidden\n ? this.#strings.expand\n : fillUiString(this.#strings.expandUnread, { count: unread });\n this.#launcher.setAttribute(\"aria-label\", label);\n this.#launcher.title = label;\n }\n\n /** Dispatch a bubbling, composed event for the host to hear. */\n #emit<T>(type: string, detail: T): void {\n this.dispatchEvent(new CustomEvent<T>(type, { detail, bubbles: true, composed: true }));\n }\n\n /**\n * Repaint the badge and tell the host the total, naming `threadIds`, the\n * threads whose marks changed.\n *\n * The count is kept whether or not the badge renders it, so `unread` stays\n * truthful for a host chrome and switching the badge on mid-session doesn't\n * start from a number that was never counted.\n */\n #unreadChanged(threadIds: readonly string[]): void {\n this.#syncLauncher();\n this.#emit<UnreadDetail>(UNREAD_EVENT, { unread: this.unread, threadIds });\n }\n\n /**\n * Note an answer that finished on `threadId`: read as it lands when that\n * thread is on screen in an expanded panel, otherwise one more unseen.\n */\n #noteUnread(threadId: string): void {\n if (this.#inView(threadId)) {\n this.conversationStore.markRead?.(threadId);\n return;\n }\n this.#unreadByThread.set(threadId, (this.#unreadByThread.get(threadId) ?? 0) + 1);\n this.#unreadChanged([threadId]);\n }\n\n /**\n * Whether `threadId` is in front of the user: drawn on screen, with no switch\n * away from it in flight, in an expanded panel. On screen while collapsed is\n * not read.\n */\n #inView(threadId: string): boolean {\n return !this.collapsed && threadId === this.#shownThread && threadId === this.#history.threadId;\n }\n\n /** Clear the marks of the thread in view, telling the store; the threads cleared. */\n #markSeen(): string[] {\n const threadId = this.#shownThread;\n if (threadId === null || !this.#inView(threadId) || !this.#unreadByThread.delete(threadId)) {\n return [];\n }\n this.conversationStore.markRead?.(threadId);\n return [threadId];\n }\n\n /**\n * Drop the marks of `threadIds` without reading them (a deleted thread, a\n * principal who left). Reported when any had marks, or always when `report`.\n */\n #forgetUnread(threadIds: readonly string[], report = false): void {\n const dropped = threadIds.filter((threadId) => this.#unreadByThread.delete(threadId));\n if (dropped.length > 0 || report) {\n this.#unreadChanged(dropped);\n }\n }\n\n /**\n * Take the threads a store lists as unread that this page has not counted:\n * one mark each, or read at once when the thread is in view.\n */\n #takeListedUnread(threads: readonly ThreadMeta[]): void {\n const marked: string[] = [];\n for (const { threadId, unread } of threads) {\n if (unread !== true || this.#unreadByThread.has(threadId)) {\n continue;\n }\n if (this.#inView(threadId)) {\n this.conversationStore.markRead?.(threadId);\n } else {\n this.#unreadByThread.set(threadId, 1);\n marked.push(threadId);\n }\n }\n if (marked.length > 0) {\n this.#unreadChanged(marked);\n }\n }\n\n /**\n * Forward input changes to the skills palette and clear any stale hint.\n *\n * Typing is the answer to every hint that surface carries -- a skill short of\n * a field, a continuation short of its next turn -- so the keystroke that\n * starts answering it is the right moment to take it down.\n */\n #onInput(): void {\n this.#skillsMenu.onInput(this.#input.value);\n this.#composerHint.hidden = true;\n autoGrow(this.#input);\n // Typing puts the composer back in the user's hands: the next ArrowUp\n // starts from the newest turn again rather than continuing a walk through\n // history the user has since edited. Needed beside the walk's own check\n // below, which compares text: an edit typed and then deleted leaves the\n // turn there unchanged, and the user has still taken the box back.\n this.#recallIndex = null;\n }\n\n #onKeydown(event: KeyboardEvent): void {\n // The skills palette consumes arrows/enter/escape while open.\n if (this.#skillsMenu.onKeydown(event)) {\n event.preventDefault();\n return;\n }\n // Escape-to-cancel \u2014 only reachable when the palette is closed (it\n // consumed the key above otherwise), so the two Escapes don't clash.\n if (event.key === \"Escape\" && this.#running) {\n event.preventDefault();\n this.#cancelRun();\n return;\n }\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n void this.#submit();\n return;\n }\n this.#recallHistory(event);\n }\n\n /**\n * Walk back through what the user has already sent, on the arrow keys.\n *\n * Only from an empty composer, and only with the palette closed -- which the\n * caller has already established, since the palette consumes arrows while it\n * is open. Both conditions matter: arrows inside text are how you move the\n * caret, and taking them would break editing to add a shortcut.\n *\n * The drafts are the user's own turns in this conversation, newest first,\n * which is what every shell and every coding agent means by this. Arrowing\n * forward past the newest empties the composer again rather than sticking on\n * it, so the way out is the same key that got you in.\n *\n * A walk ends with any write into the composer that is not its own, so that\n * whatever was written is never replaced by the next step.\n */\n #recallHistory(event: KeyboardEvent): void {\n const back = event.key === \"ArrowUp\";\n if ((!back && event.key !== \"ArrowDown\") || this.#skillsMenu.isOpen()) {\n return;\n }\n const drafts = this.#sentDrafts;\n if (drafts.length === 0) {\n return;\n }\n // The walk checks the composer rather than trusting every writer to end it:\n // a quotation, a prefill, dictation and the host page all write it too.\n if (this.#input.value !== this.#recalled) {\n this.#recallIndex = null;\n }\n // An empty composer is the only safe entry: anything typed is the user's,\n // and replacing it with a past turn would lose it without asking.\n if (this.#recallIndex === null && (!back || this.#input.value !== \"\")) {\n return;\n }\n const next = this.#recallIndex === null ? 0 : this.#recallIndex + (back ? 1 : -1);\n if (next >= drafts.length) {\n return;\n }\n event.preventDefault();\n this.#recallIndex = next < 0 ? null : next;\n // Asserted: `next` is bounded on both sides above, so a default is unreachable.\n this.#input.value = next < 0 ? \"\" : (drafts[next] as string);\n // Read back rather than taken from the draft, so a value the textarea\n // normalises on the way in -- its line endings -- still reads as the\n // walk's own on the next step instead of ending it.\n this.#recalled = this.#input.value;\n this.#input.setSelectionRange(this.#input.value.length, this.#input.value.length);\n autoGrow(this.#input);\n }\n\n /**\n * Stop the in-flight run: decline any confirmation card awaiting a decision\n * (the loop is suspended on it), then cancel the client run \u2014 the abort\n * closes the streaming request, which is AG-UI's cancel (the server\n * observes the disconnect).\n */\n #cancelRun(): void {\n // Stopping discards what was waiting, and loses nothing: a queued turn\n // entered the recall history as it left the composer. Also reached from\n // disconnectedCallback, where a DOM move is not a farewell either.\n this.#queued.length = 0;\n this.#renderQueued();\n this.#decision.abort();\n this.#client?.cancel();\n // A send whose run has not started is ended here too, because nothing else\n // can reach it: the cancel above lands on a client that has not been asked\n // for the run yet, and a client forgets a Stop when it is next asked for one.\n // This is how a submit listener that starts a new chat, switches thread or\n // moves the element stops the send it is hearing about.\n this.#sending = null;\n // A checkpoint continuation is as much the run in flight -- the composer\n // offers Stop for it -- but it runs on a client the element does not hold.\n this.#history.stopContinuation();\n }\n\n /**\n * Say the conversation on screen changed: {@link THREAD_EVENT}.\n *\n * The thread it replaced is the one last reported, rather than the one the\n * element last pointed at: a switch superseded before it replayed never drew\n * its thread.\n */\n #dispatchThread(threadId: string, reason: ThreadDetail[\"reason\"]): void {\n const detail: ThreadDetail = { threadId, previousThreadId: this.#shownThread, reason };\n this.#shownThread = threadId;\n const seen = this.#markSeen();\n if (seen.length > 0) {\n this.#unreadChanged(seen);\n }\n // The chip always names the live page, whichever conversation is on screen.\n this.refreshPlace();\n this.#titleMessages = this.#history.restored;\n // Settled before the thread event so its listeners read the new title,\n // and announced after it, as the change that follows from the switch.\n const retitled = this.#settleTitle();\n this.#emit<ThreadDetail>(THREAD_EVENT, detail);\n if (retitled) {\n this.#announceTitle();\n }\n // A picked thread may carry a title its messages do not derive (renamed\n // elsewhere, or named by a server). On restore only from the element's own\n // sessionStorage store, where the read is local: a remote one is a GET per page load.\n if (\n reason === \"switch\" ||\n (reason === \"restore\" && this.conversationStore instanceof SessionStorageStore)\n ) {\n void this.#history.refreshDrawer();\n }\n }\n\n /** The header and rail text: the fixed `title-text`, or the thread's under `\"auto\"`. */\n #titleText(): string {\n // `#strings` is the resolved table once connected, the English defaults before then.\n const fixed = this.getAttribute(\"title-text\");\n if (fixed !== TITLE_TEXT_AUTO) {\n return fixed ?? this.#strings.title;\n }\n return this.#titled.title === \"\" ? this.#strings.title : this.#titled.title;\n }\n\n #paintTitle(): void {\n this.#title.textContent = this.#titleText();\n this.#railLabel.textContent = this.#title.textContent;\n }\n\n /**\n * Recompute {@link threadTitle} and repaint; `true` when it changed. A new\n * thread counts as a change unless both titles are empty, so a switch\n * between two same-named threads is still reported.\n */\n #settleTitle(): boolean {\n const threadId = this.#history.threadId;\n const title =\n this.#givenTitles.get(threadId) ??\n threadTitleFrom(this.#titleMessages, (name) => this.#skills.title(name));\n const previous = this.#titled;\n if (title === previous.title && (threadId === previous.threadId || title === \"\")) {\n return false;\n }\n this.#titled = { threadId, title };\n this.#paintTitle();\n return true;\n }\n\n #announceTitle(): void {\n this.#emit<ThreadTitleDetail>(THREAD_TITLE_EVENT, { ...this.#titled });\n }\n\n /** {@link #settleTitle}, announcing the change if there was one. */\n #retitle(): void {\n if (this.#settleTitle()) {\n this.#announceTitle();\n }\n }\n\n /**\n * Keep the list's title for the thread on screen when it is a rename or a title\n * the server chose. A server's own derivation of the first message (cut at 60\n * code points) or its placeholder is not one: the element's own title stays.\n */\n #takeListedTitle(threads: readonly ThreadMeta[]): void {\n const threadId = this.#history.threadId;\n const row = threads.find((thread) => thread.threadId === threadId);\n if (row === undefined || this.#titleMessages.length === 0) {\n return;\n }\n const derived = [\n threadTitleFrom(this.#titleMessages),\n serverTitleFrom(this.#titleMessages),\n SERVER_PLACEHOLDER_TITLE,\n ];\n if (derived.includes(row.title)) {\n return;\n }\n this.#givenTitles.set(threadId, row.title);\n this.#retitle();\n }\n\n /**\n * Swap the composer button between Send (idle) and Stop (running).\n *\n * The glyph is swapped by CSS from `data-state` \u2014 both are mounted \u2014 so this\n * only has to move the accessible name, which is the button's whole label now\n * that it carries no text.\n */\n #setRunning(running: boolean): void {\n const settled = this.#running && !running;\n this.#running = running;\n // The send that asked for this run is covered from here until it settles,\n // so its hold ends now, and a host's follow-up from run-finished is heard.\n if (running) {\n this.#sending = null;\n }\n const label = running ? this.#strings.stop : this.#strings.send;\n this.#send.title = label;\n this.#send.setAttribute(\"aria-label\", label);\n this.#send.dataset[\"state\"] = running ? \"running\" : \"idle\";\n // For a host's CSS, as `data-empty` is: the same state, on the element.\n this.toggleAttribute(\"data-running\", running);\n if (settled) {\n this.#flushQueued();\n }\n }\n\n /** Let go of `hold` if it is still the one held, and send what queued behind it. */\n #releaseHold(hold: object): void {\n if (this.#sending === hold) {\n this.#sending = null;\n this.#flushQueued();\n }\n }\n\n /** Whether a run, a send or retry held short of its run, or a continuation is in flight. */\n #busy(): boolean {\n return this.#running || this.#sending !== null || this.#history.continuation !== null;\n }\n\n /**\n * Send the next message that was typed while the run was going.\n *\n * One at a time, through the same path as anything else: each queued turn\n * starts a run of its own, and the next is sent when *that* one settles. Any\n * other shape would be a second sender racing the guard above.\n */\n #flushQueued(): void {\n // Guarded here rather than at each caller, because this is what takes the\n // turn off the queue: a caller that ran while something was still in\n // flight would shift a turn off and lose it to the no-op in `sendMessage`.\n // A continuation settles its run before the element lets go of it, so the\n // settle below arrives while `continuation` is still set, and the release\n // that follows is what drains.\n if (this.#running || this.#history.continuation !== null) {\n return;\n }\n const next = this.#queued.shift();\n this.#renderQueued();\n if (next !== undefined) {\n void this.sendMessage(next);\n }\n }\n\n /**\n * Draw what is waiting, as chips that can be taken back.\n *\n * Visible and removable, because a message the user typed and cannot see is\n * a message they will type again -- and one they changed their mind about\n * has to be retractable before it is sent on their behalf.\n */\n #renderQueued(): void {\n this.#queuedRow.replaceChildren();\n this.#queuedRow.hidden = this.#queued.length === 0;\n for (const [index, text] of this.#queued.entries()) {\n const chip = document.createElement(\"button\");\n chip.type = \"button\";\n chip.className = \"queued-chip\";\n chip.setAttribute(\"part\", \"queued-chip\");\n chip.textContent = text;\n chip.title = fillUiString(this.#strings.removeQueued, { text });\n chip.setAttribute(\"aria-label\", chip.title);\n chip.addEventListener(\"click\", () => {\n this.#queued.splice(index, 1);\n this.#renderQueued();\n });\n this.#queuedRow.appendChild(chip);\n }\n }\n\n /**\n * Put a turn that has left the composer at the front of the recall history,\n * and start the next walk from it.\n *\n * Every turn the user typed and pressed a key to send comes through here:\n * sent at once, queued behind a run, or sent to continue a checkpoint. A\n * host's own `sendMessage` does not, because its text was never in the\n * composer, and the arrow keys walk back through what the user wrote there.\n */\n #recordTurn(content: string): void {\n // A repeat of the last one is not a second entry: the point is to reach\n // what was said, not how often. Nothing is recorded for an attachment sent\n // with no text, which has nothing for the composer to hold.\n if (content !== \"\" && this.#sentDrafts[0] !== content) {\n this.#sentDrafts.unshift(content);\n }\n // A press sends without an input event, which is what ends a walk\n // otherwise. Left where it was, the next ArrowUp stepped past the turn just\n // taken, or past whichever one now sits where it had walked to.\n this.#recallIndex = null;\n }\n\n async #submit(): Promise<void> {\n const content = this.#input.value.trim();\n const attachments = this.#attachments.tray?.readyRefs() ?? [];\n // Allow an attachments-only message (no typed text), but nothing empty.\n if (content === \"\" && attachments.length === 0) {\n return;\n }\n // The single choke point for Enter and Send. A second run cannot start\n // while a run, a held send or a picked checkpoint is in flight: it would\n // orphan the first, which is unabortable, and corrupt its pending tool\n // cards. So the turn queues. Text only: an attachment is the tray's state,\n // with no second copy to park. Recorded for recall first, since it leaves\n // the box either way and the queue sends it through `sendMessage`, which\n // records nothing.\n this.#recordTurn(content);\n if (this.#busy()) {\n if (content !== \"\") {\n this.#queued.push(content);\n this.#renderQueued();\n this.#input.value = \"\";\n autoGrow(this.#input);\n }\n return;\n }\n this.#input.value = \"\";\n autoGrow(this.#input);\n // A file still uploading does not ride along (`readyRefs()` returns only\n // settled ones), so say so while `hasPending()` still describes this send.\n if (this.#attachments.tray?.hasPending() === true) {\n this.#transcript.appendNotice(\n \"\\u{1F4CE}\",\n fillUiString(this.#strings.attachmentsStillUploading, {\n n: this.#attachments.tray.pendingCount(),\n }),\n \"attachment-pending\",\n );\n }\n // The refs ride the message from here; drop the settled chips, keep any\n // still uploading for a follow-up message.\n this.#attachments.tray?.clearReady();\n await this.sendMessage(content, attachments);\n }\n\n /**\n * Send a message as if the user had typed it \u2014 renders the user bubble,\n * dispatches {@link SUBMIT_EVENT}, and starts the run.\n *\n * The programmatic half of the composer, for a host driving its own input.\n * Everything the built-in Send does happens here; Send reads the composer,\n * clears it, and calls this.\n *\n * `attachments` are durable {@link AttachmentRef}s \u2014 what {@link attachFile}\n * resolves to and what {@link ATTACHMENT_EVENT} reports.\n *\n * Resolves `true` once the turn has been handed to the client for its run,\n * which is when the interaction settles, frontend-tool rounds included; a\n * run a tool or context provider then stops still counts, as it does for\n * {@link retryLastTurn}. Resolves `false` when nothing was sent.\n *\n * Nothing is sent for an empty message, nor while a run or a picked\n * checkpoint's continuation is in flight, since a second concurrent run\n * would orphan the first. A send is in flight from the moment it is taken\n * rather than from its run's start, so nothing is sent from a\n * {@link SUBMIT_EVENT} listener or for a second call in the same task\n * either. Nor with no `endpoint`, which says so in the transcript. Nor\n * behind a reload's restore that will resume a run a navigating tool\n * interrupted, since that restore ends by starting the run.\n *\n * **While the element restores a stored conversation with no run to resume\n * -- on connect, {@link reload}, a thread picked from the drawer, a change\n * from one `user-key` to another -- it waits, then sends.** The turn has to follow the\n * conversation it is part of: sent at once, it went out without it, the\n * conversation was then drawn under it, and its save replaced the stored\n * one. So the bubble, the {@link SUBMIT_EVENT} and the request all come after\n * the replay, by the length of the store's load. A New chat, a thread\n * switch, a change from one `user-key` to another, a reload or the element\n * leaving the page while it waits drops it, resolving `false`: the\n * conversation it was addressed to is no longer on screen. Leaving the page\n * resolves it only once the load answers or the element is back, since\n * that is when the restore learns it was stopped. A first `user-key` on an\n * anonymous conversation adopts it rather than replacing it, and stops\n * nothing. A second call while one waits is\n * refused, as a second call in the same task is.\n *\n * Unlike the built-in Send it does not queue: it returns, and the caller\n * keeps what it tried to send. Nor does it consult the tray -- what you pass\n * is what is sent.\n */\n async sendMessage(content: string, attachments: readonly AttachmentRef[] = []): Promise<boolean> {\n if (content === \"\" && attachments.length === 0) {\n return false;\n }\n const restore = this.#restoreHold;\n if (restore !== null && this.#sending === restore.hold) {\n // Taken over from the restore, so a second host call is refused, the\n // built-in Send parks behind this one rather than going first, and the\n // restore's own release when it ends lets go of nothing -- this send's\n // run settling, or its end, is what sends the parked turn.\n const waiting = {};\n this.#sending = waiting;\n await restore.restored;\n // Anything that stopped the restore let go of this too, by the Stop\n // that New chat, a thread switch, a principal handover, a reload and the\n // element leaving all reach. Otherwise let go of here and the guards\n // asked again from the top, as for a call made now. Held by \"drops the\n // waiting send and the queued turn when New chat is pressed\".\n if (this.#sending !== waiting) {\n return false;\n }\n this.#sending = null;\n return this.sendMessage(content, attachments);\n }\n if (this.#busy()) {\n return false;\n }\n const send = {};\n this.#sending = send;\n try {\n // Only a send travels. Every other way out of the empty state -- a\n // restored transcript, a thread picked from the drawer, a resumed\n // checkpoint -- is a change of context rather than a continuation of what\n // the user was doing, and snaps. Armed before the bubble lands so both\n // writes reach the same style recalculation, which is what makes the\n // change a transition rather than a jump.\n if (this.#transcript.isEmpty()) {\n this.setAttribute(\"data-composer-settling\", \"\");\n }\n // Taken before the announcement, because its listeners run here: a host's\n // own send from one is refused as overlapping this one, as it would be\n // from any later moment of it.\n this.#announceTurn(content, attachments);\n // A listener can also have stopped it -- New chat, a thread switch, a\n // change of principal, moving the element. All of them reach the Stop,\n // which let go of this send, and the turn would otherwise go out into the\n // conversation that replaced it, or from an element nothing can stop.\n if (this.#sending !== send) {\n return false;\n }\n // Read where the request is made, which says why nothing was sent when\n // there is no endpoint to send to.\n const connected = this.endpoint !== \"\";\n await this.#client_send(content, attachments);\n return connected;\n } finally {\n // Still held here only if its run never started: no endpoint, or a\n // client or store that threw before asking for one. No run settles\n // then, so this is what sends a turn queued behind it. Not released if\n // it is no longer this send's: the run starting let go of it, or a Stop\n // did, and the field may hold the next send by now.\n this.#releaseHold(send);\n }\n }\n\n /**\n * Put a turn the user sent on screen, and tell the host it was sent.\n *\n * The half of a send that does not depend on where it goes, so both senders\n * take it from here: {@link sendMessage}, and a checkpoint continuation, which\n * posts to the resume or fork endpoint on a client of its own.\n *\n * Arming the composer's travel stays with {@link sendMessage}: continuing a\n * run is a change of context, and docks at once.\n */\n #announceTurn(content: string, attachments: readonly AttachmentRef[]): void {\n const bubble = this.appendMessage(MESSAGE_ROLE.USER, content);\n if (attachments.length > 0) {\n bubble.appendChild(renderAttachmentChips(attachments));\n }\n this.#emit<SubmitDetail>(SUBMIT_EVENT, { content, attachments });\n }\n\n /**\n * Queue a file for upload into the attachment tray, exactly as the file\n * picker and drag-and-drop do \u2014 validation, progress chip, and all.\n *\n * Returns `false` when uploads are not configured (no `data-attachments-url`\n * and no {@link uploadHandler}) \u2014 the only signal a host gets, since the tray\n * does not exist to report anything then.\n *\n * Uploading is asynchronous: watch {@link ATTACHMENT_EVENT} for the resulting\n * {@link AttachmentRef} and pass it to {@link sendMessage} once `pending`\n * reaches zero.\n */\n attachFile(file: File): boolean {\n return this.#attachments.attach(file);\n }\n\n /**\n * Hand the message to the client, or say why it is going nowhere.\n *\n * With no `endpoint`, the bubble and {@link SUBMIT_EVENT} have already\n * happened, so the send looks made. The console tells the developer which\n * attribute is missing and the transcript tells the reader, on every\n * attempt: a once-only report is silence for each one after.\n */\n async #client_send(content: string, attachments: readonly AttachmentRef[]): Promise<void> {\n if (this.endpoint === \"\") {\n console.error(\n \"<ag-ui-chat>: no endpoint is set, so this message was not sent and no \" +\n \"request was made. Point the element at your AG-UI mount with the \" +\n 'endpoint attribute (endpoint=\"/agent/\"), or assign chat.endpoint ' +\n \"before sending.\",\n );\n this.#transcript.appendNotice(\"\u26A0\", this.#strings.notConnected, \"not-connected\");\n return;\n }\n await this.#ensureClient().send(content, attachments);\n }\n\n #ensureClient(): AgUiClient {\n if (this.#client === null) {\n this.#client = this.#buildClient({\n endpoint: this.endpoint,\n initialMessages: this.#history.restored,\n // Its history is the whole conversation, so nothing goes ahead of it.\n follows: [],\n });\n }\n return this.#client;\n }\n\n /**\n * Build a client for the conversation on screen: the one construction shared\n * by the conversation's own client and every checkpoint continuation.\n *\n * One construction, so the two cannot drift apart; what differs is the seed.\n */\n #buildClient(seed: ClientSeed): AgUiClient {\n // Fixed when the client is built: a stopped run saves once its request\n // closes, and read live that save would land under New chat's thread.\n const threadId = this.#history.threadId;\n // Fixed for the same reason, and checked by every write below: see #tenure.\n // The thread id alone cannot do it, because the store is still read live --\n // it has to be, since an adoption rescopes it under a run that keeps going.\n const tenure = this.#tenure;\n const agent = this.agentFactory({\n endpoint: seed.endpoint,\n headers: this.#requestHeaders(),\n // Live getter: the client is built once and cached, but a rotated\n // token must still reach every request \u2014 the factory's fetch wrapper\n // re-reads this on each call.\n getHeaders: () => this.#requestHeaders(),\n trustedOrigins: this.trustedOrigins,\n ...this.#credentialsOption(),\n threadId,\n initialMessages: seed.initialMessages,\n initialState: this.#sharedState,\n });\n return new AgUiClient({\n agent,\n handlers: this.#runHandlers.forClient(threadId),\n // The place is read here because the client asks for the tools first,\n // so the round's tools and context answer from the same read.\n getTools: () => {\n this.refreshPlace();\n return this.#tools.advertise();\n },\n getContext: () => this.#dispatch.buildContext(),\n executeTool: (call) => this.#dispatch.execute(call),\n resolveInterrupts: (interrupts) => this.#dispatch.resolveInterrupts(interrupts),\n // Every client saves the whole conversation, since a store keeps one list\n // per thread: a continuation writes the one it continues ahead of its own.\n // Every save reaches the store through here, so this is the one tenure\n // gate for them, `onSaved` (the next client's seed) included.\n onPersist: (messages) => {\n if (tenure !== this.#tenure) {\n return;\n }\n const conversation = [...seed.follows, ...messages];\n this.conversationStore.saveMessages(threadId, conversation);\n if (threadId === this.#history.threadId) {\n this.#titleMessages = conversation;\n this.#retitle();\n }\n seed.onSaved?.(conversation);\n },\n // Shared state is the next principal's first `RunAgentInput.state`, and\n // the handover has just emptied it. A snapshot already read off the wire\n // is applied after the Stop, and would put it back.\n onStateChanged: (state) => {\n if (tenure === this.#tenure) {\n this.#onSharedStateChanged(state);\n }\n },\n connectionLostMessage: this.#strings.connectionLost,\n unfinishedMessage: this.#strings.callNotFinished,\n declinedMessage: this.#strings.declinedAction,\n maxToolRounds: readMaxToolRounds(this),\n });\n }\n\n /** Mirror the agent's applied state and tell the host it moved. */\n #onSharedStateChanged(state: Readonly<Record<string, unknown>>): void {\n this.#sharedState = { ...state };\n this.#emit<StateDetail>(STATE_EVENT, { state: this.#sharedState });\n }\n\n /**\n * Say that the agent rearranged the user's window, and offer the way back.\n *\n * Only on the agent's path. A host calling {@link moveTo} is arranging its\n * own page and does not need telling what it just did; an agent doing it\n * mid-conversation is the case where a panel appears to move on its own.\n */\n #announceSurfaceChange(text: string, undo: (() => void) | null): void {\n this.#transcript.appendNotice(\n \"\u2922\",\n text,\n \"surface\",\n undo === null ? undefined : { label: this.#strings.undo, onActivate: undo },\n );\n }\n\n /**\n * Turn on chart rendering, by whichever route this consumer wants.\n *\n * Both routes converge on one renderer deliberately. Built apart they become\n * two chart implementations with two sets of bugs, and the choice between them\n * is about *where the data lives* rather than how a bar should look:\n *\n * - `\"tool\"` registers the built-in `render_chart`. The agent decides a chart\n * helps and calls it, so the numbers are in its context and it can discuss\n * them afterwards. Costs one model round, and works over any transport.\n * - `\"activity\"` draws a server-pushed `ACTIVITY_SNAPSHOT` of type `chart`.\n * No round trip, and the data never enters the model's context at all \u2014\n * which is what makes it the one for a large or sensitive dataset. Only this\n * route can update a chart in place as the server computes.\n *\n * Off unless asked for, both of them: a component that renders whatever\n * arrives is not something to switch on for everybody.\n */\n enableCharts(routes: readonly (\"tool\" | \"activity\")[] = [\"tool\", \"activity\"]): void {\n const first = !this.#activities.has(CHART_ACTIVITY_TYPE) && !this.#tools.has(CHART_TOOL_NAME);\n if (routes.includes(\"activity\")) {\n // The chart is a registration like any host's, not a privileged branch.\n // If the built-in cannot be expressed through the seam, the seam is not\n // one -- so this is the test as much as the feature.\n this.registerActivityRenderer({\n type: CHART_ACTIVITY_TYPE,\n render: (content) => {\n const spec = chartSpecFrom(content);\n return spec === null ? null : renderChart(spec);\n },\n removedNotice: this.#strings.chartUndrawable,\n });\n }\n if (routes.includes(\"tool\")) {\n this.registerTool(createChartTool());\n }\n // Called after connecting, the history already replayed with charts off,\n // so redraw rather than make the obvious call order wrong.\n if (first && this.isConnected) {\n this.reload();\n }\n }\n\n /**\n * Teach this element to draw one kind of AG-UI activity.\n *\n * `activity_type` is one of exactly two fields the protocol leaves an open\n * string, and it is the **content** one: an activity is materialised into a\n * message, persisted with the thread, and replayed on every restore. Its\n * sibling `CUSTOM` carries an imperative and is dispatched to the page\n * instead ({@link CUSTOM_AGENT_EVENT}).\n *\n * That asymmetry decides which carrier a server should use. Content has a\n * place in the conversation and should come back; an imperative has no place\n * and no meaning once acted on.\n *\n * ```js\n * chat.registerActivityRenderer({\n * type: \"build_status\",\n * render: (content) => {\n * const el = document.createElement(\"div\");\n * el.textContent = `Build ${content.status}`;\n * return el;\n * },\n * });\n * ```\n *\n * Registering a type twice replaces the earlier renderer, so a host can\n * override a built-in -- `chart` and `compaction` are registrations like any\n * other, not privileged branches.\n *\n * \u26A0 `render` runs again on every thread load. See {@link ActivityRenderer}\n * for what that requires of it.\n */\n registerActivityRenderer(registration: ActivityRegistration): void {\n this.#activities.register(registration);\n }\n\n /**\n * Activity types that arrived with nobody registered to draw them.\n *\n * Deliberately the only trace an unhandled activity leaves. Ignoring an\n * unknown name is the protocol's own answer and the whole point of an open\n * field, so warning would fire on every forward-compatible server -- but\n * \"nothing happened and nothing was said\" is impossible to debug, so the set\n * is readable. Accumulates for the element's lifetime, across threads.\n */\n get unhandledActivityTypes(): readonly string[] {\n return this.#activities.unhandledTypes();\n }\n}\n\n/** Draw `html` as the fallback of the button's slots, so a host's own projected icon still wins. */\nfunction fillSlotFallback(button: HTMLElement, html: string): void {\n for (const slot of button.querySelectorAll(\"slot\")) {\n slot.innerHTML = html;\n }\n}\n\n/** The `removed` count from a compaction activity payload, or `null` if absent. */\nfunction compactionRemoved(content: unknown): number | null {\n const removed = (content as { removed?: unknown } | null | undefined)?.removed;\n return typeof removed === \"number\" ? removed : null;\n}\n", "import { ELEMENT_TAG } from \"../constants.js\";\nimport { AgUiChat } from \"./ag_ui_chat.js\";\n\n/**\n * Register the `<ag-ui-chat>` Custom Element.\n *\n * Idempotent: a second call, or one after this package's `AgUiChat` already\n * holds the tag, is a no-op. If another class holds the tag it throws naming\n * the tag, because two copies of the element on one page (two bundles, or this\n * package beside its predecessor) would otherwise run the other one. The class\n * is not named: in a minified bundle its name is a one-letter identifier.\n * Registration is an explicit step rather than an import side effect, so\n * importing the package defines nothing and stays tree-shakeable.\n */\nexport function defineChat(): void {\n const existing = customElements.get(ELEMENT_TAG);\n if (existing === undefined) {\n customElements.define(ELEMENT_TAG, AgUiChat);\n } else if (existing !== AgUiChat) {\n throw new Error(\n `<${ELEMENT_TAG}> is already defined by another class: ` +\n \"a second copy of this package, or another package, is on the page\",\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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MO,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA7B,IAAM,oBAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACClC,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDhC,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACE7B,IAAM,iBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACF/B,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACChC,IAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDpC,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACChC,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACE7B,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAhC,IAAM,cAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACH5B,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACChC,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDhC,IAAM,cAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACC5B,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACD9B,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA9B,IAAM,iBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA/B,IAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAtC,IAAM,oBAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAlC,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACFjC,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA7B,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACC7B,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA7B,IAAM,iBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA/B,IAAM,iBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA/B,IAAM,cAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACD5B,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA9B,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACS9B,IAAM,aAAa;AAAA,EACxB,QAAQ;AAAA,EACR,OAAO;AACT;;;ACTO,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA,EAInC,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,EAIjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,EAIjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,EAIjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAejB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,EAIjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA;;;ACvEZ,IAAM,eAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA,EAIhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA,EAIhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA,EAIhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;;;AChHX,IAAM,gBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA9B,IAAM,cAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA5B,IAAM,cAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACE5B,IAAM,yBAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDvC,IAAM,kBAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACChC,IAAM,wBAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACDtC,IAAM,iBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA/B,IAAM,oBAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuDlC,IAAM,SAAiB;AAAA;AAAA;AAAA,EAG5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,E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",
|
|
6
|
+
"names": ["text", "text", "text", "text", "text", "button", "text", "button", "randomUUID", "restored", "randomUUID", "text", "confirm", "text", "DRAG_THRESHOLD", "boxAt", "STEP", "COARSE_STEP", "inset", "held", "text", "button", "button", "inner", "text", "text", "text", "text", "randomUUID", "randomUUID", "text", "inner", "button"]
|
|
7
|
+
}
|