@artooi/agents-web-components 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/LICENSE +21 -0
- package/README.md +4397 -2
- package/dist/agents-web-components.bundle.js +5708 -0
- package/dist/agents-web-components.bundle.js.map +7 -0
- package/dist/bundle.d.ts +3 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/chat.d.ts +3 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +16373 -0
- package/dist/chat.js.map +7 -0
- package/dist/chunk-ARNLFGCC.js +7715 -0
- package/dist/chunk-ARNLFGCC.js.map +7 -0
- package/dist/constants.d.ts +575 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/core/activity_registration.d.ts +19 -0
- package/dist/core/activity_registration.d.ts.map +1 -0
- package/dist/core/activity_registry.d.ts +46 -0
- package/dist/core/activity_registry.d.ts.map +1 -0
- package/dist/core/activity_renderer.d.ts +20 -0
- package/dist/core/activity_renderer.d.ts.map +1 -0
- package/dist/core/ag_ui_chat.d.ts +836 -0
- package/dist/core/ag_ui_chat.d.ts.map +1 -0
- package/dist/core/agui_client.d.ts +370 -0
- package/dist/core/agui_client.d.ts.map +1 -0
- package/dist/core/attachment.d.ts +42 -0
- package/dist/core/attachment.d.ts.map +1 -0
- package/dist/core/chat_registry.d.ts +23 -0
- package/dist/core/chat_registry.d.ts.map +1 -0
- package/dist/core/client_seed.d.ts +27 -0
- package/dist/core/client_seed.d.ts.map +1 -0
- package/dist/core/conversation_store.d.ts +195 -0
- package/dist/core/conversation_store.d.ts.map +1 -0
- package/dist/core/create_http_agent.d.ts +57 -0
- package/dist/core/create_http_agent.d.ts.map +1 -0
- package/dist/core/define_chat.d.ts +13 -0
- package/dist/core/define_chat.d.ts.map +1 -0
- package/dist/core/events/attachments_detail.d.ts +9 -0
- package/dist/core/events/attachments_detail.d.ts.map +1 -0
- package/dist/core/events/bar_height_detail.d.ts +6 -0
- package/dist/core/events/bar_height_detail.d.ts.map +1 -0
- package/dist/core/events/custom_agent_detail.d.ts +8 -0
- package/dist/core/events/custom_agent_detail.d.ts.map +1 -0
- package/dist/core/events/dock_width_detail.d.ts +8 -0
- package/dist/core/events/dock_width_detail.d.ts.map +1 -0
- package/dist/core/events/feedback_detail.d.ts +28 -0
- package/dist/core/events/feedback_detail.d.ts.map +1 -0
- package/dist/core/events/invalidate_detail.d.ts +16 -0
- package/dist/core/events/invalidate_detail.d.ts.map +1 -0
- package/dist/core/events/maximize_detail.d.ts +5 -0
- package/dist/core/events/maximize_detail.d.ts.map +1 -0
- package/dist/core/events/run_finished_detail.d.ts +36 -0
- package/dist/core/events/run_finished_detail.d.ts.map +1 -0
- package/dist/core/events/state_detail.d.ts +5 -0
- package/dist/core/events/state_detail.d.ts.map +1 -0
- package/dist/core/events/submit_detail.d.ts +8 -0
- package/dist/core/events/submit_detail.d.ts.map +1 -0
- package/dist/core/events/thread_detail.d.ts +27 -0
- package/dist/core/events/thread_detail.d.ts.map +1 -0
- package/dist/core/events/thread_title_detail.d.ts +8 -0
- package/dist/core/events/thread_title_detail.d.ts.map +1 -0
- package/dist/core/events/toggle_detail.d.ts +5 -0
- package/dist/core/events/toggle_detail.d.ts.map +1 -0
- package/dist/core/events/tool_run.d.ts +11 -0
- package/dist/core/events/tool_run.d.ts.map +1 -0
- package/dist/core/events/unread_detail.d.ts +11 -0
- package/dist/core/events/unread_detail.d.ts.map +1 -0
- package/dist/core/message_role.d.ts +4 -0
- package/dist/core/message_role.d.ts.map +1 -0
- package/dist/core/read_flag.d.ts +11 -0
- package/dist/core/read_flag.d.ts.map +1 -0
- package/dist/core/read_json_attribute.d.ts +15 -0
- package/dist/core/read_json_attribute.d.ts.map +1 -0
- package/dist/core/read_max_tool_rounds.d.ts +9 -0
- package/dist/core/read_max_tool_rounds.d.ts.map +1 -0
- package/dist/core/remote_conversation_store.d.ts +71 -0
- package/dist/core/remote_conversation_store.d.ts.map +1 -0
- package/dist/core/run_handlers.d.ts +85 -0
- package/dist/core/run_handlers.d.ts.map +1 -0
- package/dist/core/run_index.d.ts +58 -0
- package/dist/core/run_index.d.ts.map +1 -0
- package/dist/core/storage_scope.d.ts +118 -0
- package/dist/core/storage_scope.d.ts.map +1 -0
- package/dist/core/tool_outcome.d.ts +27 -0
- package/dist/core/tool_outcome.d.ts.map +1 -0
- package/dist/core/transcribe_audio.d.ts +32 -0
- package/dist/core/transcribe_audio.d.ts.map +1 -0
- package/dist/core/upload_attachment.d.ts +44 -0
- package/dist/core/upload_attachment.d.ts.map +1 -0
- package/dist/core/utils.d.ts +117 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/dom/animations.d.ts +122 -0
- package/dist/dom/animations.d.ts.map +1 -0
- package/dist/dom/dom_driver.d.ts +28 -0
- package/dist/dom/dom_driver.d.ts.map +1 -0
- package/dist/dom/highlight_overlay.d.ts +39 -0
- package/dist/dom/highlight_overlay.d.ts.map +1 -0
- package/dist/dom/native_setter.d.ts +5 -0
- package/dist/dom/native_setter.d.ts.map +1 -0
- package/dist/dom/ring_color.d.ts +16 -0
- package/dist/dom/ring_color.d.ts.map +1 -0
- package/dist/dom/utils.d.ts +3 -0
- package/dist/dom/utils.d.ts.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +223 -0
- package/dist/index.js.map +7 -0
- package/dist/skills/fill_template.d.ts +16 -0
- package/dist/skills/fill_template.d.ts.map +1 -0
- package/dist/skills/parse_skills.d.ts +8 -0
- package/dist/skills/parse_skills.d.ts.map +1 -0
- package/dist/skills/skill.d.ts +33 -0
- package/dist/skills/skill.d.ts.map +1 -0
- package/dist/skills/skill_catalog.d.ts +69 -0
- package/dist/skills/skill_catalog.d.ts.map +1 -0
- package/dist/skills/skill_name_from.d.ts +12 -0
- package/dist/skills/skill_name_from.d.ts.map +1 -0
- package/dist/tools/chat_surface_tools.d.ts +77 -0
- package/dist/tools/chat_surface_tools.d.ts.map +1 -0
- package/dist/tools/client_tool_registry.d.ts +58 -0
- package/dist/tools/client_tool_registry.d.ts.map +1 -0
- package/dist/tools/is_destructive.d.ts +14 -0
- package/dist/tools/is_destructive.d.ts.map +1 -0
- package/dist/tools/is_navigates.d.ts +9 -0
- package/dist/tools/is_navigates.d.ts.map +1 -0
- package/dist/tools/page_action_tools.d.ts +30 -0
- package/dist/tools/page_action_tools.d.ts.map +1 -0
- package/dist/tools/page_map.d.ts +16 -0
- package/dist/tools/page_map.d.ts.map +1 -0
- package/dist/tools/page_state.d.ts +27 -0
- package/dist/tools/page_state.d.ts.map +1 -0
- package/dist/tools/parse_tool_catalog.d.ts +21 -0
- package/dist/tools/parse_tool_catalog.d.ts.map +1 -0
- package/dist/tools/route_map.d.ts +37 -0
- package/dist/tools/route_map.d.ts.map +1 -0
- package/dist/tools/tool_catalog.d.ts +86 -0
- package/dist/tools/tool_catalog.d.ts.map +1 -0
- package/dist/tools/tool_dispatch.d.ts +82 -0
- package/dist/tools/tool_dispatch.d.ts.map +1 -0
- package/dist/ui/charts/chart_block.d.ts +57 -0
- package/dist/ui/charts/chart_block.d.ts.map +1 -0
- package/dist/ui/charts/chart_spec_from.d.ts +12 -0
- package/dist/ui/charts/chart_spec_from.d.ts.map +1 -0
- package/dist/ui/charts/chart_styles.d.ts +2 -0
- package/dist/ui/charts/chart_styles.d.ts.map +1 -0
- package/dist/ui/charts/chart_tool.d.ts +15 -0
- package/dist/ui/charts/chart_tool.d.ts.map +1 -0
- package/dist/ui/composer/attachment_styles.d.ts +2 -0
- package/dist/ui/composer/attachment_styles.d.ts.map +1 -0
- package/dist/ui/composer/attachment_tray.d.ts +53 -0
- package/dist/ui/composer/attachment_tray.d.ts.map +1 -0
- package/dist/ui/composer/auto_grow.d.ts +10 -0
- package/dist/ui/composer/auto_grow.d.ts.map +1 -0
- package/dist/ui/composer/build_composer.d.ts +32 -0
- package/dist/ui/composer/build_composer.d.ts.map +1 -0
- package/dist/ui/composer/composer_attachments.d.ts +57 -0
- package/dist/ui/composer/composer_attachments.d.ts.map +1 -0
- package/dist/ui/composer/composer_styles.d.ts +2 -0
- package/dist/ui/composer/composer_styles.d.ts.map +1 -0
- package/dist/ui/composer/composer_voice.d.ts +48 -0
- package/dist/ui/composer/composer_voice.d.ts.map +1 -0
- package/dist/ui/composer/skill_styles.d.ts +2 -0
- package/dist/ui/composer/skill_styles.d.ts.map +1 -0
- package/dist/ui/composer/skills_menu.d.ts +34 -0
- package/dist/ui/composer/skills_menu.d.ts.map +1 -0
- package/dist/ui/composer/voice_input.d.ts +46 -0
- package/dist/ui/composer/voice_input.d.ts.map +1 -0
- package/dist/ui/excerpts/attach_copy_buttons.d.ts +13 -0
- package/dist/ui/excerpts/attach_copy_buttons.d.ts.map +1 -0
- package/dist/ui/excerpts/copy_payload.d.ts +30 -0
- package/dist/ui/excerpts/copy_payload.d.ts.map +1 -0
- package/dist/ui/excerpts/page_quote_offer.d.ts +33 -0
- package/dist/ui/excerpts/page_quote_offer.d.ts.map +1 -0
- package/dist/ui/excerpts/place_offer.d.ts +9 -0
- package/dist/ui/excerpts/place_offer.d.ts.map +1 -0
- package/dist/ui/excerpts/quote_selection.d.ts +66 -0
- package/dist/ui/excerpts/quote_selection.d.ts.map +1 -0
- package/dist/ui/excerpts/transcript_quote_offer.d.ts +57 -0
- package/dist/ui/excerpts/transcript_quote_offer.d.ts.map +1 -0
- package/dist/ui/fill_ui_string.d.ts +32 -0
- package/dist/ui/fill_ui_string.d.ts.map +1 -0
- package/dist/ui/history/checkpoint_menu.d.ts +41 -0
- package/dist/ui/history/checkpoint_menu.d.ts.map +1 -0
- package/dist/ui/history/conversation_history.d.ts +317 -0
- package/dist/ui/history/conversation_history.d.ts.map +1 -0
- package/dist/ui/history/history_styles.d.ts +2 -0
- package/dist/ui/history/history_styles.d.ts.map +1 -0
- package/dist/ui/history/relative_time.d.ts +23 -0
- package/dist/ui/history/relative_time.d.ts.map +1 -0
- package/dist/ui/history/thread_drawer.d.ts +64 -0
- package/dist/ui/history/thread_drawer.d.ts.map +1 -0
- package/dist/ui/history/utils.d.ts +2 -0
- package/dist/ui/history/utils.d.ts.map +1 -0
- package/dist/ui/interrupts/approval_card.d.ts +64 -0
- package/dist/ui/interrupts/approval_card.d.ts.map +1 -0
- package/dist/ui/interrupts/approval_styles.d.ts +2 -0
- package/dist/ui/interrupts/approval_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/confirmation_card.d.ts +51 -0
- package/dist/ui/interrupts/confirmation_card.d.ts.map +1 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts +2 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/pending_decision.d.ts +22 -0
- package/dist/ui/interrupts/pending_decision.d.ts.map +1 -0
- package/dist/ui/interrupts/question_card.d.ts +49 -0
- package/dist/ui/interrupts/question_card.d.ts.map +1 -0
- package/dist/ui/interrupts/question_styles.d.ts +2 -0
- package/dist/ui/interrupts/question_styles.d.ts.map +1 -0
- package/dist/ui/place/place.d.ts +17 -0
- package/dist/ui/place/place.d.ts.map +1 -0
- package/dist/ui/place/place_chip.d.ts +26 -0
- package/dist/ui/place/place_chip.d.ts.map +1 -0
- package/dist/ui/place/place_from_route.d.ts +9 -0
- package/dist/ui/place/place_from_route.d.ts.map +1 -0
- package/dist/ui/place/place_styles.d.ts +2 -0
- package/dist/ui/place/place_styles.d.ts.map +1 -0
- package/dist/ui/placement/clamp_launcher.d.ts +20 -0
- package/dist/ui/placement/clamp_launcher.d.ts.map +1 -0
- package/dist/ui/placement/clamp_panel.d.ts +13 -0
- package/dist/ui/placement/clamp_panel.d.ts.map +1 -0
- package/dist/ui/placement/collapse_styles.d.ts +2 -0
- package/dist/ui/placement/collapse_styles.d.ts.map +1 -0
- package/dist/ui/placement/dock_styles.d.ts +2 -0
- package/dist/ui/placement/dock_styles.d.ts.map +1 -0
- package/dist/ui/placement/embedded_styles.d.ts +2 -0
- package/dist/ui/placement/embedded_styles.d.ts.map +1 -0
- package/dist/ui/placement/launcher_drag.d.ts +49 -0
- package/dist/ui/placement/launcher_drag.d.ts.map +1 -0
- package/dist/ui/placement/launcher_placement.d.ts +77 -0
- package/dist/ui/placement/launcher_placement.d.ts.map +1 -0
- package/dist/ui/placement/launcher_styles.d.ts +2 -0
- package/dist/ui/placement/launcher_styles.d.ts.map +1 -0
- package/dist/ui/placement/page_styles.d.ts +2 -0
- package/dist/ui/placement/page_styles.d.ts.map +1 -0
- package/dist/ui/placement/panel_drag.d.ts +40 -0
- package/dist/ui/placement/panel_drag.d.ts.map +1 -0
- package/dist/ui/placement/panel_placement.d.ts +173 -0
- package/dist/ui/placement/panel_placement.d.ts.map +1 -0
- package/dist/ui/placement/place_widget.d.ts +31 -0
- package/dist/ui/placement/place_widget.d.ts.map +1 -0
- package/dist/ui/placement/preset_styles.d.ts +2 -0
- package/dist/ui/placement/preset_styles.d.ts.map +1 -0
- package/dist/ui/placement/resize_handle.d.ts +78 -0
- package/dist/ui/placement/resize_handle.d.ts.map +1 -0
- package/dist/ui/placement/resize_styles.d.ts +2 -0
- package/dist/ui/placement/resize_styles.d.ts.map +1 -0
- package/dist/ui/placement/sidebar_styles.d.ts +2 -0
- package/dist/ui/placement/sidebar_styles.d.ts.map +1 -0
- package/dist/ui/placement/small_viewport_styles.d.ts +2 -0
- package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -0
- package/dist/ui/placement/surface_for.d.ts +93 -0
- package/dist/ui/placement/surface_for.d.ts.map +1 -0
- package/dist/ui/progress/prettify_tool_name.d.ts +11 -0
- package/dist/ui/progress/prettify_tool_name.d.ts.map +1 -0
- package/dist/ui/progress/run_announcer.d.ts +41 -0
- package/dist/ui/progress/run_announcer.d.ts.map +1 -0
- package/dist/ui/progress/run_notice.d.ts +21 -0
- package/dist/ui/progress/run_notice.d.ts.map +1 -0
- package/dist/ui/progress/run_notice_styles.d.ts +2 -0
- package/dist/ui/progress/run_notice_styles.d.ts.map +1 -0
- package/dist/ui/progress/subagent_panel.d.ts +101 -0
- package/dist/ui/progress/subagent_panel.d.ts.map +1 -0
- package/dist/ui/progress/subagent_progress.d.ts +57 -0
- package/dist/ui/progress/subagent_progress.d.ts.map +1 -0
- package/dist/ui/progress/subagent_update.d.ts +28 -0
- package/dist/ui/progress/subagent_update.d.ts.map +1 -0
- package/dist/ui/progress/thoughts_block.d.ts +57 -0
- package/dist/ui/progress/thoughts_block.d.ts.map +1 -0
- package/dist/ui/progress/thoughts_styles.d.ts +2 -0
- package/dist/ui/progress/thoughts_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_call_card.d.ts +167 -0
- package/dist/ui/progress/tool_call_card.d.ts.map +1 -0
- package/dist/ui/progress/tool_group_styles.d.ts +2 -0
- package/dist/ui/progress/tool_group_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_group.d.ts +50 -0
- package/dist/ui/progress/tool_step_group.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_styles.d.ts +2 -0
- package/dist/ui/progress/tool_step_styles.d.ts.map +1 -0
- package/dist/ui/shell/adopt_styles.d.ts +28 -0
- package/dist/ui/shell/adopt_styles.d.ts.map +1 -0
- package/dist/ui/shell/build_header.d.ts +45 -0
- package/dist/ui/shell/build_header.d.ts.map +1 -0
- package/dist/ui/shell/build_launcher.d.ts +33 -0
- package/dist/ui/shell/build_launcher.d.ts.map +1 -0
- package/dist/ui/shell/collapse_glyph.d.ts +14 -0
- package/dist/ui/shell/collapse_glyph.d.ts.map +1 -0
- package/dist/ui/shell/frame_styles.d.ts +2 -0
- package/dist/ui/shell/frame_styles.d.ts.map +1 -0
- package/dist/ui/shell/glyph_slot.d.ts +7 -0
- package/dist/ui/shell/glyph_slot.d.ts.map +1 -0
- package/dist/ui/shell/header_button.d.ts +11 -0
- package/dist/ui/shell/header_button.d.ts.map +1 -0
- package/dist/ui/shell/icon_element.d.ts +12 -0
- package/dist/ui/shell/icon_element.d.ts.map +1 -0
- package/dist/ui/shell/is_unread_badge_enabled.d.ts +10 -0
- package/dist/ui/shell/is_unread_badge_enabled.d.ts.map +1 -0
- package/dist/ui/shell/read_launcher_icon_url.d.ts +8 -0
- package/dist/ui/shell/read_launcher_icon_url.d.ts.map +1 -0
- package/dist/ui/shell/theme_styles.d.ts +2 -0
- package/dist/ui/shell/theme_styles.d.ts.map +1 -0
- package/dist/ui/shell/token_styles.d.ts +2 -0
- package/dist/ui/shell/token_styles.d.ts.map +1 -0
- package/dist/ui/styles.d.ts +2 -0
- package/dist/ui/styles.d.ts.map +1 -0
- package/dist/ui/themes/classic_styles.d.ts +2 -0
- package/dist/ui/themes/classic_styles.d.ts.map +1 -0
- package/dist/ui/themes/classic_tokens.d.ts +2 -0
- package/dist/ui/themes/classic_tokens.d.ts.map +1 -0
- package/dist/ui/themes/code_tokens.d.ts +2 -0
- package/dist/ui/themes/code_tokens.d.ts.map +1 -0
- package/dist/ui/themes/ledger_styles.d.ts +2 -0
- package/dist/ui/themes/ledger_styles.d.ts.map +1 -0
- package/dist/ui/themes/ledger_tokens.d.ts +2 -0
- package/dist/ui/themes/ledger_tokens.d.ts.map +1 -0
- package/dist/ui/themes/modern_styles.d.ts +2 -0
- package/dist/ui/themes/modern_styles.d.ts.map +1 -0
- package/dist/ui/themes/quiet_styles.d.ts +2 -0
- package/dist/ui/themes/quiet_styles.d.ts.map +1 -0
- package/dist/ui/themes/scheme_styles.d.ts +2 -0
- package/dist/ui/themes/scheme_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_styles.d.ts +2 -0
- package/dist/ui/themes/soft_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_tokens.d.ts +2 -0
- package/dist/ui/themes/soft_tokens.d.ts.map +1 -0
- package/dist/ui/themes/theme_hosts.d.ts +15 -0
- package/dist/ui/themes/theme_hosts.d.ts.map +1 -0
- package/dist/ui/transcript/answer_actions.d.ts +50 -0
- package/dist/ui/transcript/answer_actions.d.ts.map +1 -0
- package/dist/ui/transcript/answer_stream.d.ts +56 -0
- package/dist/ui/transcript/answer_stream.d.ts.map +1 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts +2 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts.map +1 -0
- package/dist/ui/transcript/attachment_chips.d.ts +21 -0
- package/dist/ui/transcript/attachment_chips.d.ts.map +1 -0
- package/dist/ui/transcript/build_transcript.d.ts +21 -0
- package/dist/ui/transcript/build_transcript.d.ts.map +1 -0
- package/dist/ui/transcript/greeting_styles.d.ts +2 -0
- package/dist/ui/transcript/greeting_styles.d.ts.map +1 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts +13 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts.map +1 -0
- package/dist/ui/transcript/message_action_styles.d.ts +2 -0
- package/dist/ui/transcript/message_action_styles.d.ts.map +1 -0
- package/dist/ui/transcript/message_actions.d.ts +74 -0
- package/dist/ui/transcript/message_actions.d.ts.map +1 -0
- package/dist/ui/transcript/message_styles.d.ts +2 -0
- package/dist/ui/transcript/message_styles.d.ts.map +1 -0
- package/dist/ui/transcript/render_markdown.d.ts +40 -0
- package/dist/ui/transcript/render_markdown.d.ts.map +1 -0
- package/dist/ui/transcript/render_or_warn.d.ts +16 -0
- package/dist/ui/transcript/render_or_warn.d.ts.map +1 -0
- package/dist/ui/transcript/reveal_words.d.ts +8 -0
- package/dist/ui/transcript/reveal_words.d.ts.map +1 -0
- package/dist/ui/transcript/starter_chips.d.ts +21 -0
- package/dist/ui/transcript/starter_chips.d.ts.map +1 -0
- package/dist/ui/transcript/stick_to_bottom.d.ts +55 -0
- package/dist/ui/transcript/stick_to_bottom.d.ts.map +1 -0
- package/dist/ui/transcript/suggestion_chips.d.ts +29 -0
- package/dist/ui/transcript/suggestion_chips.d.ts.map +1 -0
- package/dist/ui/transcript/transcript.d.ts +196 -0
- package/dist/ui/transcript/transcript.d.ts.map +1 -0
- package/dist/ui/transcript/transcript_styles.d.ts +2 -0
- package/dist/ui/transcript/transcript_styles.d.ts.map +1 -0
- package/dist/ui/ui_strings.d.ts +352 -0
- package/dist/ui/ui_strings.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +86 -3
- package/src/bundle.ts +2 -0
- package/src/chat.ts +2 -0
- package/src/constants.ts +650 -0
- package/src/core/activity_registration.ts +19 -0
- package/src/core/activity_registry.ts +133 -0
- package/src/core/activity_renderer.ts +19 -0
- package/src/core/ag_ui_chat.ts +3966 -0
- package/src/core/agui_client.ts +1028 -0
- package/src/core/attachment.ts +62 -0
- package/src/core/chat_registry.ts +53 -0
- package/src/core/client_seed.ts +27 -0
- package/src/core/conversation_store.ts +478 -0
- package/src/core/create_http_agent.ts +97 -0
- package/src/core/define_chat.ts +25 -0
- package/src/core/events/attachments_detail.ts +9 -0
- package/src/core/events/bar_height_detail.ts +5 -0
- package/src/core/events/custom_agent_detail.ts +7 -0
- package/src/core/events/dock_width_detail.ts +7 -0
- package/src/core/events/feedback_detail.ts +27 -0
- package/src/core/events/invalidate_detail.ts +15 -0
- package/src/core/events/maximize_detail.ts +4 -0
- package/src/core/events/run_finished_detail.ts +36 -0
- package/src/core/events/state_detail.ts +4 -0
- package/src/core/events/submit_detail.ts +8 -0
- package/src/core/events/thread_detail.ts +26 -0
- package/src/core/events/thread_title_detail.ts +7 -0
- package/src/core/events/toggle_detail.ts +4 -0
- package/src/core/events/tool_run.ts +10 -0
- package/src/core/events/unread_detail.ts +10 -0
- package/src/core/message_role.ts +4 -0
- package/src/core/read_flag.ts +13 -0
- package/src/core/read_json_attribute.ts +30 -0
- package/src/core/read_max_tool_rounds.ts +13 -0
- package/src/core/remote_conversation_store.ts +279 -0
- package/src/core/run_handlers.ts +524 -0
- package/src/core/run_index.ts +114 -0
- package/src/core/storage_scope.ts +291 -0
- package/src/core/tool_outcome.ts +39 -0
- package/src/core/transcribe_audio.ts +76 -0
- package/src/core/upload_attachment.ts +130 -0
- package/src/core/utils.ts +230 -0
- package/src/dom/animations.ts +341 -0
- package/src/dom/dom_driver.ts +91 -0
- package/src/dom/highlight_overlay.ts +204 -0
- package/src/dom/native_setter.ts +40 -0
- package/src/dom/ring_color.ts +206 -0
- package/src/dom/utils.ts +5 -0
- package/src/index.ts +220 -0
- package/src/skills/fill_template.ts +31 -0
- package/src/skills/parse_skills.ts +31 -0
- package/src/skills/skill.ts +32 -0
- package/src/skills/skill_catalog.ts +172 -0
- package/src/skills/skill_name_from.ts +19 -0
- package/src/tools/chat_surface_tools.ts +183 -0
- package/src/tools/client_tool_registry.ts +80 -0
- package/src/tools/is_destructive.ts +17 -0
- package/src/tools/is_navigates.ts +12 -0
- package/src/tools/page_action_tools.ts +123 -0
- package/src/tools/page_map.ts +26 -0
- package/src/tools/page_state.ts +57 -0
- package/src/tools/parse_tool_catalog.ts +41 -0
- package/src/tools/route_map.ts +132 -0
- package/src/tools/tool_catalog.ts +334 -0
- package/src/tools/tool_dispatch.ts +453 -0
- package/src/ui/charts/chart_block.ts +519 -0
- package/src/ui/charts/chart_spec_from.ts +125 -0
- package/src/ui/charts/chart_styles.ts +63 -0
- package/src/ui/charts/chart_tool.ts +72 -0
- package/src/ui/composer/attachment_styles.ts +71 -0
- package/src/ui/composer/attachment_tray.ts +295 -0
- package/src/ui/composer/auto_grow.ts +12 -0
- package/src/ui/composer/build_composer.ts +114 -0
- package/src/ui/composer/composer_attachments.ts +324 -0
- package/src/ui/composer/composer_styles.ts +177 -0
- package/src/ui/composer/composer_voice.ts +93 -0
- package/src/ui/composer/skill_styles.ts +120 -0
- package/src/ui/composer/skills_menu.ts +188 -0
- package/src/ui/composer/voice_input.ts +282 -0
- package/src/ui/excerpts/attach_copy_buttons.ts +73 -0
- package/src/ui/excerpts/copy_payload.ts +156 -0
- package/src/ui/excerpts/page_quote_offer.ts +203 -0
- package/src/ui/excerpts/place_offer.ts +24 -0
- package/src/ui/excerpts/quote_selection.ts +345 -0
- package/src/ui/excerpts/transcript_quote_offer.ts +175 -0
- package/src/ui/fill_ui_string.ts +41 -0
- package/src/ui/history/checkpoint_menu.ts +300 -0
- package/src/ui/history/conversation_history.ts +1169 -0
- package/src/ui/history/history_styles.ts +492 -0
- package/src/ui/history/relative_time.ts +50 -0
- package/src/ui/history/thread_drawer.ts +471 -0
- package/src/ui/history/utils.ts +11 -0
- package/src/ui/interrupts/approval_card.ts +202 -0
- package/src/ui/interrupts/approval_styles.ts +52 -0
- package/src/ui/interrupts/confirmation_card.ts +138 -0
- package/src/ui/interrupts/confirmation_styles.ts +114 -0
- package/src/ui/interrupts/pending_decision.ts +33 -0
- package/src/ui/interrupts/question_card.ts +213 -0
- package/src/ui/interrupts/question_styles.ts +73 -0
- package/src/ui/place/place.ts +16 -0
- package/src/ui/place/place_chip.ts +146 -0
- package/src/ui/place/place_from_route.ts +27 -0
- package/src/ui/place/place_styles.ts +108 -0
- package/src/ui/placement/clamp_launcher.ts +38 -0
- package/src/ui/placement/clamp_panel.ts +30 -0
- package/src/ui/placement/collapse_styles.ts +472 -0
- package/src/ui/placement/dock_styles.ts +116 -0
- package/src/ui/placement/embedded_styles.ts +14 -0
- package/src/ui/placement/launcher_drag.ts +206 -0
- package/src/ui/placement/launcher_placement.ts +133 -0
- package/src/ui/placement/launcher_styles.ts +189 -0
- package/src/ui/placement/page_styles.ts +47 -0
- package/src/ui/placement/panel_drag.ts +138 -0
- package/src/ui/placement/panel_placement.ts +1975 -0
- package/src/ui/placement/place_widget.ts +64 -0
- package/src/ui/placement/preset_styles.ts +49 -0
- package/src/ui/placement/resize_handle.ts +229 -0
- package/src/ui/placement/resize_styles.ts +201 -0
- package/src/ui/placement/sidebar_styles.ts +113 -0
- package/src/ui/placement/small_viewport_styles.ts +70 -0
- package/src/ui/placement/surface_for.ts +183 -0
- package/src/ui/progress/prettify_tool_name.ts +16 -0
- package/src/ui/progress/run_announcer.ts +67 -0
- package/src/ui/progress/run_notice.ts +61 -0
- package/src/ui/progress/run_notice_styles.ts +52 -0
- package/src/ui/progress/subagent_panel.ts +227 -0
- package/src/ui/progress/subagent_progress.ts +200 -0
- package/src/ui/progress/subagent_update.ts +89 -0
- package/src/ui/progress/thoughts_block.ts +165 -0
- package/src/ui/progress/thoughts_styles.ts +74 -0
- package/src/ui/progress/tool_call_card.ts +429 -0
- package/src/ui/progress/tool_group_styles.ts +313 -0
- package/src/ui/progress/tool_step_group.ts +317 -0
- package/src/ui/progress/tool_step_styles.ts +486 -0
- package/src/ui/shell/adopt_styles.ts +34 -0
- package/src/ui/shell/build_header.ts +121 -0
- package/src/ui/shell/build_launcher.ts +79 -0
- package/src/ui/shell/collapse_glyph.ts +42 -0
- package/src/ui/shell/frame_styles.ts +147 -0
- package/src/ui/shell/glyph_slot.ts +12 -0
- package/src/ui/shell/header_button.ts +22 -0
- package/src/ui/shell/icon_element.ts +33 -0
- package/src/ui/shell/is_unread_badge_enabled.ts +11 -0
- package/src/ui/shell/read_launcher_icon_url.ts +9 -0
- package/src/ui/shell/theme_styles.ts +11 -0
- package/src/ui/shell/token_styles.ts +480 -0
- package/src/ui/styles.ts +110 -0
- package/src/ui/themes/classic_styles.ts +32 -0
- package/src/ui/themes/classic_tokens.ts +51 -0
- package/src/ui/themes/code_tokens.ts +21 -0
- package/src/ui/themes/ledger_styles.ts +169 -0
- package/src/ui/themes/ledger_tokens.ts +33 -0
- package/src/ui/themes/modern_styles.ts +80 -0
- package/src/ui/themes/quiet_styles.ts +118 -0
- package/src/ui/themes/scheme_styles.ts +26 -0
- package/src/ui/themes/soft_styles.ts +149 -0
- package/src/ui/themes/soft_tokens.ts +29 -0
- package/src/ui/themes/theme_hosts.ts +14 -0
- package/src/ui/transcript/answer_actions.ts +165 -0
- package/src/ui/transcript/answer_stream.ts +123 -0
- package/src/ui/transcript/attachment_chip_styles.ts +116 -0
- package/src/ui/transcript/attachment_chips.ts +82 -0
- package/src/ui/transcript/build_transcript.ts +67 -0
- package/src/ui/transcript/greeting_styles.ts +171 -0
- package/src/ui/transcript/groups_tool_steps.ts +16 -0
- package/src/ui/transcript/message_action_styles.ts +155 -0
- package/src/ui/transcript/message_actions.ts +234 -0
- package/src/ui/transcript/message_styles.ts +262 -0
- package/src/ui/transcript/render_markdown.ts +181 -0
- package/src/ui/transcript/render_or_warn.ts +22 -0
- package/src/ui/transcript/reveal_words.ts +41 -0
- package/src/ui/transcript/starter_chips.ts +42 -0
- package/src/ui/transcript/stick_to_bottom.ts +126 -0
- package/src/ui/transcript/suggestion_chips.ts +73 -0
- package/src/ui/transcript/transcript.ts +555 -0
- package/src/ui/transcript/transcript_styles.ts +153 -0
- package/src/ui/ui_strings.ts +550 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
// Messages: the answer well, incoming-text animations, rendered markdown,
|
|
2
|
+
// code blocks and their copy button, tables, and the pending dots.
|
|
3
|
+
export const MESSAGE_STYLES: string = `
|
|
4
|
+
/* ── Answer group / well ─────────────────────────────────────────
|
|
5
|
+
One .answer per assistant turn wraps the streamed text, its tool cards,
|
|
6
|
+
and the pending indicator so a whole answer reads (and can be boxed) as one
|
|
7
|
+
unit. A flex column on the message-list gap, stretched to the list width so
|
|
8
|
+
its children keep their own left/right alignment. data-answer-well opts into
|
|
9
|
+
the bordered "well"; without it the turn renders as a flat stack. */
|
|
10
|
+
.answer {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
gap: var(--_space);
|
|
14
|
+
align-self: stretch;
|
|
15
|
+
min-width: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:host([data-answer-well]) .answer {
|
|
19
|
+
padding: var(--_pad);
|
|
20
|
+
background: var(--_well-bg);
|
|
21
|
+
border: 1px solid var(--_well-border);
|
|
22
|
+
border-radius: var(--_well-radius);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.message {
|
|
26
|
+
max-width: 80%;
|
|
27
|
+
padding: var(--_msg-pad);
|
|
28
|
+
border-radius: var(--_msg-radius);
|
|
29
|
+
line-height: 1.4;
|
|
30
|
+
white-space: pre-wrap;
|
|
31
|
+
/* overflow-wrap, not word-break, and the difference is the whole reason a
|
|
32
|
+
markdown table used to be unreadable.
|
|
33
|
+
|
|
34
|
+
Both stop one long unbroken token blowing out the bubble, which is all this
|
|
35
|
+
is for. But word-break: break-word is the legacy spelling of "break
|
|
36
|
+
anywhere", and breaking anywhere drops the *min-content* width of every
|
|
37
|
+
descendant to one character. A table's column algorithm takes min-content
|
|
38
|
+
as an input, so the table always fitted max-width: 100%, the overflow-x:
|
|
39
|
+
auto below it never had anything to scroll, and the columns absorbed the
|
|
40
|
+
pressure by rendering one letter per line instead. A seven-column header
|
|
41
|
+
came out 162px tall.
|
|
42
|
+
|
|
43
|
+
overflow-wrap: break-word breaks a word only when it would otherwise
|
|
44
|
+
overflow its line, and leaves min-content alone -- so the bubble is still
|
|
45
|
+
protected and the table is free to be wider than the panel and scroll. */
|
|
46
|
+
overflow-wrap: break-word;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ── Incoming-text animations (data-text-animation) ─────────────────────── */
|
|
50
|
+
/* .message--restored (rehydrated history) is excluded: entrance animations are
|
|
51
|
+
for freshly-arriving messages, not the whole transcript replaying on reload.
|
|
52
|
+
Word mode is excluded implicitly — restored bubbles aren't wrapped. */
|
|
53
|
+
:host([data-text-animation="fade"]) .message--assistant:not(.message--restored) {
|
|
54
|
+
animation: ag-ui-msg-fade 0.25s ease both;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes ag-ui-msg-fade {
|
|
58
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
59
|
+
to { opacity: 1; transform: none; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.message--assistant .word {
|
|
63
|
+
animation: ag-ui-word-in 0.3s ease both;
|
|
64
|
+
animation-delay: calc(var(--ag-ui-word-index, 0) * 35ms);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes ag-ui-word-in {
|
|
68
|
+
from { opacity: 0; }
|
|
69
|
+
to { opacity: 1; }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (prefers-reduced-motion: reduce) {
|
|
73
|
+
:host([data-text-animation="fade"]) .message--assistant,
|
|
74
|
+
.message--assistant .word {
|
|
75
|
+
animation: none;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.message--user {
|
|
80
|
+
align-self: flex-end;
|
|
81
|
+
background: var(--_user-bg);
|
|
82
|
+
color: var(--_user-fg);
|
|
83
|
+
border-bottom-right-radius: 4px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.message--assistant {
|
|
87
|
+
align-self: flex-start;
|
|
88
|
+
background: var(--_assistant-bg);
|
|
89
|
+
border-bottom-left-radius: 4px;
|
|
90
|
+
/* Assistant bubbles hold rendered markdown/HTML, so collapse the source
|
|
91
|
+
whitespace the renderer leaves between block tags. */
|
|
92
|
+
white-space: normal;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Rendered-markdown elements inside an assistant bubble. */
|
|
96
|
+
.message--assistant > :first-child {
|
|
97
|
+
margin-top: 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.message--assistant > :last-child {
|
|
101
|
+
margin-bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.message--assistant p,
|
|
105
|
+
.message--assistant ul,
|
|
106
|
+
.message--assistant ol,
|
|
107
|
+
.message--assistant blockquote,
|
|
108
|
+
.message--assistant pre {
|
|
109
|
+
margin: 0.5em 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.message--assistant ul,
|
|
113
|
+
.message--assistant ol {
|
|
114
|
+
padding-left: 1.3em;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.message--assistant a {
|
|
118
|
+
color: var(--_accent);
|
|
119
|
+
text-decoration: underline;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.message--assistant code {
|
|
123
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
124
|
+
font-size: 0.92em;
|
|
125
|
+
background: rgba(127, 127, 127, 0.16);
|
|
126
|
+
padding: 1px 4px;
|
|
127
|
+
border-radius: 4px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.message--assistant pre {
|
|
131
|
+
padding: 8px 10px;
|
|
132
|
+
overflow: auto;
|
|
133
|
+
background: var(--_bg);
|
|
134
|
+
border: 1px solid var(--_border);
|
|
135
|
+
border-radius: 6px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.message--assistant pre code {
|
|
139
|
+
background: none;
|
|
140
|
+
padding: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* The copy button sits inside the block, so it scrolls with wide code rather
|
|
144
|
+
than floating over the bubble. Positioning is on the pre; the button only
|
|
145
|
+
appears once one has been attached. */
|
|
146
|
+
.message--assistant pre.has-copy {
|
|
147
|
+
position: relative;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* The only reader of --ag-ui-surface and --ag-ui-text. Their defaults are
|
|
151
|
+
transparent and the body foreground, which is what this button rendered as
|
|
152
|
+
before either token existed; changing them repaints only this control. */
|
|
153
|
+
.code-copy {
|
|
154
|
+
position: absolute;
|
|
155
|
+
top: 4px;
|
|
156
|
+
right: 4px;
|
|
157
|
+
padding: 2px 8px;
|
|
158
|
+
font: inherit;
|
|
159
|
+
font-size: 0.75em;
|
|
160
|
+
line-height: 1.6;
|
|
161
|
+
color: var(--_muted);
|
|
162
|
+
background: var(--_surface);
|
|
163
|
+
border: 1px solid var(--_border);
|
|
164
|
+
border-radius: 4px;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
opacity: 0;
|
|
167
|
+
transition: opacity 0.12s ease;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Revealed on hover or keyboard focus. Focus matters as much as hover here:
|
|
171
|
+
hidden-until-hover is invisible to a keyboard user otherwise. */
|
|
172
|
+
.message--assistant pre.has-copy:hover .code-copy,
|
|
173
|
+
.code-copy:focus-visible {
|
|
174
|
+
opacity: 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.code-copy:hover {
|
|
178
|
+
color: var(--_text);
|
|
179
|
+
background: var(--_hover);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.code-copy[data-state="copied"] {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
color: var(--_text);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.code-copy[data-state="failed"] {
|
|
188
|
+
opacity: 1;
|
|
189
|
+
color: var(--_danger, var(--_text));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.message--assistant blockquote {
|
|
193
|
+
padding-left: 10px;
|
|
194
|
+
border-left: 3px solid var(--_border);
|
|
195
|
+
color: var(--_muted);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Markdown tables. table/thead/tbody/tr/th/td are all in the sanitizer's
|
|
199
|
+
ALLOWED_TAGS, so an agent can emit one. A wide table must scroll inside its
|
|
200
|
+
own box rather than stretch the message: the bubble is width-constrained, so
|
|
201
|
+
without this the columns either crush or push the layout sideways. */
|
|
202
|
+
.message--assistant table {
|
|
203
|
+
display: block;
|
|
204
|
+
width: fit-content;
|
|
205
|
+
max-width: 100%;
|
|
206
|
+
overflow-x: auto;
|
|
207
|
+
border-collapse: collapse;
|
|
208
|
+
font-size: 0.95em;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.message--assistant th,
|
|
212
|
+
.message--assistant td {
|
|
213
|
+
padding: 6px 10px;
|
|
214
|
+
border: 1px solid var(--_border);
|
|
215
|
+
text-align: left;
|
|
216
|
+
vertical-align: top;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.message--assistant th {
|
|
220
|
+
background: var(--_hover);
|
|
221
|
+
font-weight: 600;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.pending {
|
|
225
|
+
align-self: flex-start;
|
|
226
|
+
display: inline-flex;
|
|
227
|
+
gap: 4px;
|
|
228
|
+
align-items: center;
|
|
229
|
+
padding: 12px 14px;
|
|
230
|
+
background: var(--_assistant-bg);
|
|
231
|
+
border-radius: 14px;
|
|
232
|
+
border-bottom-left-radius: 4px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.pending-dot {
|
|
236
|
+
width: 6px;
|
|
237
|
+
height: 6px;
|
|
238
|
+
border-radius: 50%;
|
|
239
|
+
background: var(--_muted);
|
|
240
|
+
animation: ag-ui-pending 1.2s infinite ease-in-out both;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.pending-dot:nth-child(2) {
|
|
244
|
+
animation-delay: 0.16s;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.pending-dot:nth-child(3) {
|
|
248
|
+
animation-delay: 0.32s;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@keyframes ag-ui-pending {
|
|
252
|
+
0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }
|
|
253
|
+
40% { opacity: 1; transform: translateY(-3px); }
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@media (prefers-reduced-motion: reduce) {
|
|
257
|
+
.pending-dot {
|
|
258
|
+
animation: none;
|
|
259
|
+
opacity: 0.6;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Sanitisation is verified only in the `chromium` project: DOMPurify silently
|
|
2
|
+
// sanitises nothing under happy-dom, so CLAUDE.md has the root cause.
|
|
3
|
+
import DOMPurify, { type Config, type DOMPurify as Purifier } from "dompurify";
|
|
4
|
+
import { Marked } from "marked";
|
|
5
|
+
|
|
6
|
+
// A local instance, so configuration never leaks into a host's deduped `marked`.
|
|
7
|
+
// Never mutated; per-call construction would re-pay setup on every streaming render.
|
|
8
|
+
const parser = new Marked({ gfm: true, breaks: true });
|
|
9
|
+
|
|
10
|
+
// Conservative allowlist for assistant chat content. Rendering untrusted
|
|
11
|
+
// model/tool output as HTML is an XSS surface and this sanitiser is the only
|
|
12
|
+
// thing standing in front of it, so `iframe`, `style` and all scripting stay
|
|
13
|
+
// out.
|
|
14
|
+
//
|
|
15
|
+
// `img` is excluded by default: a model-controlled image URL is fetched with no
|
|
16
|
+
// user interaction, turning prompt-injected page data into a zero-click
|
|
17
|
+
// exfiltration channel. Hosts that trust their content opt in via `allowImages`.
|
|
18
|
+
const ALLOWED_TAGS = [
|
|
19
|
+
"a",
|
|
20
|
+
"p",
|
|
21
|
+
"br",
|
|
22
|
+
"strong",
|
|
23
|
+
"em",
|
|
24
|
+
"b",
|
|
25
|
+
"i",
|
|
26
|
+
"u",
|
|
27
|
+
"s",
|
|
28
|
+
"del",
|
|
29
|
+
"code",
|
|
30
|
+
"pre",
|
|
31
|
+
"ul",
|
|
32
|
+
"ol",
|
|
33
|
+
"li",
|
|
34
|
+
"blockquote",
|
|
35
|
+
"h1",
|
|
36
|
+
"h2",
|
|
37
|
+
"h3",
|
|
38
|
+
"h4",
|
|
39
|
+
"h5",
|
|
40
|
+
"h6",
|
|
41
|
+
"hr",
|
|
42
|
+
"span",
|
|
43
|
+
"table",
|
|
44
|
+
"thead",
|
|
45
|
+
"tbody",
|
|
46
|
+
"tr",
|
|
47
|
+
"th",
|
|
48
|
+
"td",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
// `target` and `rel` are on the list because {@link harden} writes them onto
|
|
52
|
+
// every link. An attribute the returned markup carries but the config does not
|
|
53
|
+
// name would be markup the sanitiser never approved — which is the whole defect
|
|
54
|
+
// the hook exists to avoid.
|
|
55
|
+
//
|
|
56
|
+
// `class` is here only for marked's `language-*` code-fence hint, and `harden`
|
|
57
|
+
// narrows it to exactly that. Left wide, it is a chrome-forgery channel: the
|
|
58
|
+
// shadow stylesheet's component classes are unscoped selectors, so a `<span
|
|
59
|
+
// class="approval-btn approval-btn--approve">` in model output resolves to the
|
|
60
|
+
// same pixels as the real human-in-the-loop approval button, inside the surface
|
|
61
|
+
// where the user decides whether to approve.
|
|
62
|
+
const ALLOWED_ATTR = ["href", "title", "class", "target", "rel"];
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The sanitiser's declared allowlist — and, because {@link harden} runs inside
|
|
66
|
+
* the sanitiser rather than after it, its *effective* one too.
|
|
67
|
+
*
|
|
68
|
+
* `ALLOW_DATA_ATTR` and `ALLOW_ARIA_ATTR` default to `true`, which would admit
|
|
69
|
+
* every `data-*` and `aria-*` attribute on top of the five named above. Both
|
|
70
|
+
* matter here: the cards drive their resolved / expanded / status appearance off
|
|
71
|
+
* `[data-resolved]`, `[data-status]` and `[data-expanded]`, and an `aria-label`
|
|
72
|
+
* on model output makes a screen reader announce something other than what is on
|
|
73
|
+
* screen. Turning them off is what makes the declared list the real one.
|
|
74
|
+
*
|
|
75
|
+
* Exported so a test can assert the returned markup is a fixed point of it.
|
|
76
|
+
*/
|
|
77
|
+
export const SANITIZE_CONFIG: Config = {
|
|
78
|
+
ALLOWED_TAGS,
|
|
79
|
+
ALLOWED_ATTR,
|
|
80
|
+
ALLOW_DATA_ATTR: false,
|
|
81
|
+
ALLOW_ARIA_ATTR: false,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/** {@link SANITIZE_CONFIG} plus the images a host opts into. */
|
|
85
|
+
export const SANITIZE_CONFIG_WITH_IMAGES: Config = {
|
|
86
|
+
...SANITIZE_CONFIG,
|
|
87
|
+
ALLOWED_TAGS: [...ALLOWED_TAGS, "img"],
|
|
88
|
+
ALLOWED_ATTR: [...ALLOWED_ATTR, "src", "alt", "width", "height"],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/** The one class value markdown is allowed to carry, and where it may sit. */
|
|
92
|
+
const LANGUAGE_CLASS = /^language-[A-Za-z0-9_+#.-]+$/;
|
|
93
|
+
const LANGUAGE_HOSTS = new Set(["CODE", "PRE"]);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Per-element hardening, run *inside* the sanitiser.
|
|
97
|
+
*
|
|
98
|
+
* It belongs here rather than in a pass over the finished string because
|
|
99
|
+
* DOMPurify must be the last thing to touch the markup: anything edited in
|
|
100
|
+
* afterwards is inserted into the document without the sanitiser ever having
|
|
101
|
+
* seen it, and re-parsing sanitiser output is the shape every mXSS bypass takes.
|
|
102
|
+
* Running as a hook means DOMPurify serialises the result of these edits, so
|
|
103
|
+
* what the caller inserts is exactly what it approved.
|
|
104
|
+
*
|
|
105
|
+
* Two jobs:
|
|
106
|
+
*
|
|
107
|
+
* - links open in a new tab and never hand over their opener. `target`/`rel` are
|
|
108
|
+
* this module's to write, so they are stripped from everything else rather
|
|
109
|
+
* than inherited from the model's own markup;
|
|
110
|
+
* - `class` is narrowed to the code-fence language hint on `code`/`pre`, the
|
|
111
|
+
* only thing it is allowed for, and dropped everywhere else so model output
|
|
112
|
+
* cannot adopt the component's own chrome.
|
|
113
|
+
*/
|
|
114
|
+
function harden(node: Element): void {
|
|
115
|
+
if (node.nodeName === "A" && node.hasAttribute("href")) {
|
|
116
|
+
node.setAttribute("target", "_blank");
|
|
117
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
118
|
+
} else {
|
|
119
|
+
node.removeAttribute("target");
|
|
120
|
+
node.removeAttribute("rel");
|
|
121
|
+
}
|
|
122
|
+
const classes = node.getAttribute("class");
|
|
123
|
+
if (classes === null) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const kept = LANGUAGE_HOSTS.has(node.nodeName)
|
|
127
|
+
? classes.split(/\s+/).filter((token) => LANGUAGE_CLASS.test(token))
|
|
128
|
+
: [];
|
|
129
|
+
if (kept.length === 0) {
|
|
130
|
+
node.removeAttribute("class");
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
node.setAttribute("class", kept.join(" "));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// A memo, not state: DOMPurify's default export is a singleton that `addHook`
|
|
137
|
+
// mutates for every caller sharing the copy, host app included, so this module
|
|
138
|
+
// builds its own instance. The hook is added before the instance is published
|
|
139
|
+
// and nothing touches it afterwards, so every element reads the same value.
|
|
140
|
+
// Built on first render, because an instance made without a DOM has no
|
|
141
|
+
// `addHook` and an eager one would make a server-side `import` throw.
|
|
142
|
+
let memo: Purifier | undefined;
|
|
143
|
+
|
|
144
|
+
function sanitizer(): Purifier {
|
|
145
|
+
if (memo === undefined) {
|
|
146
|
+
const built = DOMPurify();
|
|
147
|
+
built.addHook("afterSanitizeAttributes", harden);
|
|
148
|
+
memo = built;
|
|
149
|
+
}
|
|
150
|
+
return memo;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Options for {@link renderMarkdown}. */
|
|
154
|
+
export interface RenderMarkdownOptions {
|
|
155
|
+
/**
|
|
156
|
+
* Permit `<img>` tags (and their `src`/`alt`/`width`/`height` attributes) in
|
|
157
|
+
* the sanitised output. Off by default; see the exfiltration note on the
|
|
158
|
+
* allowlist above. Only enable for trusted content sources.
|
|
159
|
+
*/
|
|
160
|
+
readonly allowImages?: boolean;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Render markdown (and any embedded raw HTML) to a sanitised HTML string.
|
|
165
|
+
*
|
|
166
|
+
* Markdown syntax and literal HTML share one path: `marked` emits HTML, then
|
|
167
|
+
* DOMPurify strips everything outside {@link SANITIZE_CONFIG} — scripts, event
|
|
168
|
+
* handlers, `javascript:` URLs, `data-*`/`aria-*`, and every class but a code
|
|
169
|
+
* fence's `language-*` hint. Links come out with `target="_blank"` and
|
|
170
|
+
* `rel="noopener noreferrer"`.
|
|
171
|
+
*
|
|
172
|
+
* The returned string is the sanitiser's own output, trimmed. Nothing edits it
|
|
173
|
+
* afterwards, so what a caller inserts is what DOMPurify approved.
|
|
174
|
+
*/
|
|
175
|
+
export function renderMarkdown(text: string, options?: RenderMarkdownOptions): string {
|
|
176
|
+
const allowImages = options?.allowImages === true;
|
|
177
|
+
const rendered = parser.parse(text, { async: false });
|
|
178
|
+
return sanitizer()
|
|
179
|
+
.sanitize(rendered, allowImages ? SANITIZE_CONFIG_WITH_IMAGES : SANITIZE_CONFIG)
|
|
180
|
+
.trim();
|
|
181
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call a consumer's renderer, turning a throw into "nothing drawn".
|
|
3
|
+
*
|
|
4
|
+
* `render` is consumer code -- a host's activity renderer, a tool's `render` --
|
|
5
|
+
* and both call sites run inside the history replay, where a throw abandons the
|
|
6
|
+
* loop and takes every later turn of the transcript with it -- silently, and
|
|
7
|
+
* again on every reload. One thing that fails to draw is worth losing; the rest
|
|
8
|
+
* of the conversation is not. Reported so the failure is findable rather than
|
|
9
|
+
* merely survived.
|
|
10
|
+
*
|
|
11
|
+
* @param render - The consumer's renderer, already bound to its input.
|
|
12
|
+
* @param subject - What was being drawn, for the warning: `tool <name>` or
|
|
13
|
+
* `activity <type>`.
|
|
14
|
+
*/
|
|
15
|
+
export function renderOrWarn(render: () => Node | null, subject: string): Node | null {
|
|
16
|
+
try {
|
|
17
|
+
return render();
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.warn(`ag-ui-chat: render failed for ${subject}`, error);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Collect the text nodes under ``root`` with their parents (depth-first). */
|
|
2
|
+
function collectTextNodes(root: Node, out: { node: Text; parent: Node }[]): void {
|
|
3
|
+
for (const child of Array.from(root.childNodes)) {
|
|
4
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
5
|
+
out.push({ node: child as Text, parent: root });
|
|
6
|
+
} else {
|
|
7
|
+
collectTextNodes(child, out);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Wrap each word under ``root`` in `<span class="word" style="--ag-ui-word-index: N">`
|
|
14
|
+
* so CSS can reveal them one-by-one (staggered by the index). Whitespace is
|
|
15
|
+
* preserved as plain text. Used for the `word` text-animation mode on a
|
|
16
|
+
* completed assistant message; pure DOM, idempotent enough to re-run.
|
|
17
|
+
*/
|
|
18
|
+
export function wrapWords(root: HTMLElement): void {
|
|
19
|
+
const texts: { node: Text; parent: Node }[] = [];
|
|
20
|
+
collectTextNodes(root, texts);
|
|
21
|
+
let index = 0;
|
|
22
|
+
for (const { node, parent } of texts) {
|
|
23
|
+
const fragment = document.createDocumentFragment();
|
|
24
|
+
for (const part of node.data.split(/(\s+)/)) {
|
|
25
|
+
if (part === "") {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (/\s/.test(part)) {
|
|
29
|
+
fragment.appendChild(document.createTextNode(part));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const span = document.createElement("span");
|
|
33
|
+
span.className = "word";
|
|
34
|
+
span.style.setProperty("--ag-ui-word-index", String(index));
|
|
35
|
+
span.textContent = part;
|
|
36
|
+
fragment.appendChild(span);
|
|
37
|
+
index += 1;
|
|
38
|
+
}
|
|
39
|
+
parent.replaceChild(fragment, node);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { UiStrings } from "../ui_strings.js";
|
|
2
|
+
import { renderSuggestionChips } from "./suggestion_chips.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The prompts offered on an empty transcript, from `element`'s `data-starters`.
|
|
6
|
+
*
|
|
7
|
+
* Different from the suggestion chips a run pushes, which are follow-ups to
|
|
8
|
+
* something already said. These answer the blank-page question instead, and
|
|
9
|
+
* they are the host's rather than the model's -- only the host knows what its
|
|
10
|
+
* page is for. Shares the renderer, the count and the length limit, because
|
|
11
|
+
* two rows of prompt chips that behaved differently would be the harder
|
|
12
|
+
* thing to explain.
|
|
13
|
+
*
|
|
14
|
+
* Read once at connect: it is content for a state the widget is in before
|
|
15
|
+
* anything happens, and a host that wants it to change has `slot="empty"`.
|
|
16
|
+
*
|
|
17
|
+
* Parses the attribute itself rather than through the element's JSON attribute
|
|
18
|
+
* reader, because the warning is its own: it says no starters are shown and
|
|
19
|
+
* gives an example of the shape, where the shared one says a built-in default
|
|
20
|
+
* is in use, which for this attribute there is not.
|
|
21
|
+
*/
|
|
22
|
+
export function renderStarterChips(
|
|
23
|
+
element: Element,
|
|
24
|
+
strings: UiStrings,
|
|
25
|
+
onPick: (prompt: string) => void,
|
|
26
|
+
): HTMLElement | null {
|
|
27
|
+
const raw = element.getAttribute("data-starters");
|
|
28
|
+
if (raw === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
let parsed: unknown;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(raw);
|
|
34
|
+
} catch {
|
|
35
|
+
console.warn(
|
|
36
|
+
"<ag-ui-chat>: data-starters is not valid JSON, so no starters are shown. " +
|
|
37
|
+
"It takes an array of strings, e.g. data-starters='[\"Summarise this page\"]'.",
|
|
38
|
+
);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return renderSuggestionChips({ prompts: parsed }, strings, onPick);
|
|
42
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/** A transcript that follows new content, unless the reader has other ideas. */
|
|
2
|
+
export interface StickToBottom {
|
|
3
|
+
/**
|
|
4
|
+
* New content arrived. Scrolls to the bottom only while following, so
|
|
5
|
+
* reading older messages during a run is no longer undone on the next token.
|
|
6
|
+
*/
|
|
7
|
+
readonly follow: () => void;
|
|
8
|
+
/** Go to the bottom and resume following, whatever the reader was doing. */
|
|
9
|
+
readonly jump: () => void;
|
|
10
|
+
/** Whether the transcript is currently following new content. */
|
|
11
|
+
readonly following: () => boolean;
|
|
12
|
+
readonly dispose: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface StickToBottomOptions {
|
|
16
|
+
/** The scrolling element -- the message list. */
|
|
17
|
+
readonly viewport: HTMLElement;
|
|
18
|
+
/**
|
|
19
|
+
* Called whenever the answer to "should a jump-to-latest affordance show?"
|
|
20
|
+
* changes. True means the reader has scrolled away *and* has since missed
|
|
21
|
+
* something; scrolling up through a settled transcript is not a reason to
|
|
22
|
+
* nag.
|
|
23
|
+
*/
|
|
24
|
+
readonly onMissedContent: (missed: boolean) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* How close to the bottom still counts as the bottom, in CSS pixels.
|
|
29
|
+
*
|
|
30
|
+
* Not zero: `scrollHeight - scrollTop - clientHeight` lands on fractional
|
|
31
|
+
* values under a zoom level or a fractional device pixel ratio, so an exact
|
|
32
|
+
* comparison reports "scrolled away" for a transcript that is visibly pinned.
|
|
33
|
+
*/
|
|
34
|
+
const BOTTOM_SLACK_PX = 4;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Follow the foot of a scrolling transcript, and stop when the reader scrolls
|
|
38
|
+
* away.
|
|
39
|
+
*
|
|
40
|
+
* Before this, eleven separate sites assigned `scrollTop = scrollHeight`
|
|
41
|
+
* unconditionally and nothing anywhere listened for a `scroll` event -- so
|
|
42
|
+
* nothing knew the reader had scrolled up, and scrolling back through a run was
|
|
43
|
+
* undone by the next token. Stick-to-bottom with a jump-to-latest affordance is
|
|
44
|
+
* a named primitive elsewhere for exactly this reason: shadcn ships it as
|
|
45
|
+
* `MessageScroller`, AI Elements as `ConversationScrollButton`.
|
|
46
|
+
*
|
|
47
|
+
* **Telling a reader's scroll from our own is the whole problem**, and the
|
|
48
|
+
* answer here is that it does not have to be told. A programmatic scroll only
|
|
49
|
+
* ever happens while already following, and it lands at the bottom, so the
|
|
50
|
+
* `scroll` event it provokes recomputes "at the bottom" as true and changes
|
|
51
|
+
* nothing. A reader's scroll is the only kind that can move the answer.
|
|
52
|
+
*
|
|
53
|
+
* A `ResizeObserver` covers the case scroll events cannot see: the *viewport*
|
|
54
|
+
* changing size. Resizing the panel, or the keyboard opening on a phone, moves
|
|
55
|
+
* the foot without anything scrolling and without any content arriving, so a
|
|
56
|
+
* pinned transcript would silently come unpinned.
|
|
57
|
+
*
|
|
58
|
+
* ⚠ It does **not** cover content that grows after insertion -- an image
|
|
59
|
+
* decoding, a chart laying out. A `ResizeObserver` on a scroll container does
|
|
60
|
+
* not fire when its `scrollHeight` changes, so catching that means observing
|
|
61
|
+
* every child, and the payoff is one late nudge in a case the reader can fix by
|
|
62
|
+
* scrolling. Insertion itself is covered: every site that adds to the
|
|
63
|
+
* transcript calls {@link StickToBottom.follow}.
|
|
64
|
+
*/
|
|
65
|
+
export function createStickToBottom({
|
|
66
|
+
viewport,
|
|
67
|
+
onMissedContent,
|
|
68
|
+
}: StickToBottomOptions): StickToBottom {
|
|
69
|
+
let isFollowing = true;
|
|
70
|
+
let missed = false;
|
|
71
|
+
|
|
72
|
+
const atBottom = (): boolean =>
|
|
73
|
+
viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <= BOTTOM_SLACK_PX;
|
|
74
|
+
|
|
75
|
+
const setMissed = (next: boolean): void => {
|
|
76
|
+
if (next === missed) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
missed = next;
|
|
80
|
+
onMissedContent(missed);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const toBottom = (): void => {
|
|
84
|
+
viewport.scrollTop = viewport.scrollHeight;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const onScroll = (): void => {
|
|
88
|
+
isFollowing = atBottom();
|
|
89
|
+
if (isFollowing) {
|
|
90
|
+
setMissed(false);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const follow = (): void => {
|
|
95
|
+
if (isFollowing) {
|
|
96
|
+
toBottom();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setMissed(true);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Passive: this listener never calls preventDefault, and saying so keeps it
|
|
103
|
+
// off the critical path of a scroll it has no intention of blocking.
|
|
104
|
+
viewport.addEventListener("scroll", onScroll, { passive: true });
|
|
105
|
+
|
|
106
|
+
const observer = new ResizeObserver(() => {
|
|
107
|
+
if (isFollowing) {
|
|
108
|
+
toBottom();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
observer.observe(viewport);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
follow,
|
|
115
|
+
jump: (): void => {
|
|
116
|
+
isFollowing = true;
|
|
117
|
+
setMissed(false);
|
|
118
|
+
toBottom();
|
|
119
|
+
},
|
|
120
|
+
following: (): boolean => isFollowing,
|
|
121
|
+
dispose: (): void => {
|
|
122
|
+
viewport.removeEventListener("scroll", onScroll);
|
|
123
|
+
observer.disconnect();
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|