@agent-native/core 0.90.11 → 0.91.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +22 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/run-ownership.ts +29 -1
- package/corpus/core/src/changelog/parse.ts +78 -0
- package/corpus/core/src/chat-threads/schema.ts +43 -0
- package/corpus/core/src/chat-threads/store.ts +144 -12
- package/corpus/core/src/cli/workspace-dev.ts +25 -5
- package/corpus/core/src/client/AgentPanel.tsx +79 -14
- package/corpus/core/src/client/AssistantChat.tsx +359 -425
- package/corpus/core/src/client/analytics-session.ts +70 -0
- package/corpus/core/src/client/analytics.ts +175 -49
- package/corpus/core/src/client/chat/message-components.tsx +22 -2
- package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
- package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
- package/corpus/core/src/client/error-capture.ts +616 -0
- package/corpus/core/src/client/index.ts +12 -0
- package/corpus/core/src/client/session-replay.ts +57 -7
- package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
- package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
- package/corpus/core/src/client/settings/index.ts +1 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
- package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
- package/corpus/core/src/mcp/builtin-tools.ts +29 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
- package/corpus/core/src/server/onboarding-html.ts +28 -16
- package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
- package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/corpus/core/src/vite/client.ts +217 -35
- package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
- package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
- package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
- package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
- package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
- package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
- package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
- package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
- package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
- package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
- package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
- package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
- package/corpus/templates/analytics/AGENTS.md +47 -2
- package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
- package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
- package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
- package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
- package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
- package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
- package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
- package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
- package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
- package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
- package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
- package/corpus/templates/analytics/actions/navigate.ts +58 -4
- package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
- package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
- package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
- package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
- package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
- package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
- package/corpus/templates/analytics/actions/view-screen.ts +212 -0
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
- package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
- package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
- package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
- package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
- package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
- package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
- package/corpus/templates/analytics/app/i18n-data.ts +33 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
- package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
- package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
- package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
- package/corpus/templates/analytics/app/root.tsx +33 -1
- package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
- package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
- package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
- package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
- package/corpus/templates/analytics/docs/error-capture.md +172 -0
- package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
- package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
- package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
- package/corpus/templates/analytics/server/db/schema.ts +6 -0
- package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
- package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
- package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
- package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
- package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
- package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
- package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
- package/corpus/templates/analytics/server/plugins/db.ts +408 -0
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
- package/corpus/templates/assets/app/routes/_index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.tsx +22 -1
- package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/brain/app/routes/settings.tsx +43 -5
- package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
- package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/chat/app/routes/settings.tsx +16 -1
- package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
- package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
- package/corpus/templates/clips/app/routes/record.tsx +18 -1
- package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
- package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
- package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
- package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
- package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
- package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
- package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
- package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
- package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/content/shared/api.ts +3 -0
- package/corpus/templates/content/shared/properties.ts +42 -0
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-system.ts +147 -1
- package/corpus/templates/design/app/routes/settings.tsx +16 -1
- package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
- package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
- package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
- package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/macros/app/routes/settings.tsx +16 -1
- package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
- package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
- package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
- package/corpus/templates/plan/app/routes/settings.tsx +23 -2
- package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/slides/actions/add-slide.ts +1 -0
- package/corpus/templates/slides/actions/get-design-system.ts +147 -1
- package/corpus/templates/slides/app/pages/Index.tsx +46 -1
- package/corpus/templates/slides/app/routes/settings.tsx +16 -1
- package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/dist/agent/run-ownership.d.ts +6 -0
- package/dist/agent/run-ownership.d.ts.map +1 -1
- package/dist/agent/run-ownership.js +11 -1
- package/dist/agent/run-ownership.js.map +1 -1
- package/dist/changelog/parse.d.ts +7 -0
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +64 -0
- package/dist/changelog/parse.js.map +1 -1
- package/dist/chat-threads/schema.d.ts +445 -0
- package/dist/chat-threads/schema.d.ts.map +1 -0
- package/dist/chat-threads/schema.js +39 -0
- package/dist/chat-threads/schema.js.map +1 -0
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +99 -10
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +20 -5
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +35 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +105 -183
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics-session.d.ts +3 -0
- package/dist/client/analytics-session.d.ts.map +1 -0
- package/dist/client/analytics-session.js +66 -0
- package/dist/client/analytics-session.js.map +1 -0
- package/dist/client/analytics.d.ts +32 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +116 -46
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +2 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +16 -6
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/components/ui/message-scroller.d.ts +16 -0
- package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/client/components/ui/message-scroller.js +25 -0
- package/dist/client/components/ui/message-scroller.js.map +1 -0
- package/dist/client/conversation/AgentConversation.d.ts +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +3 -8
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/error-capture.d.ts +99 -0
- package/dist/client/error-capture.d.ts.map +1 -0
- package/dist/client/error-capture.js +437 -0
- package/dist/client/error-capture.js.map +1 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +22 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +45 -4
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +100 -5
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
- package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
- package/dist/client/settings/SettingsTabsPage.js +131 -19
- package/dist/client/settings/SettingsTabsPage.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +13 -8
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
- package/dist/client/sharing/ShareDialog.js +12 -7
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +21 -2
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/schema.d.ts +15 -15
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +109 -73
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +28 -16
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.js +30 -1
- package/dist/sharing/actions/list-resource-shares.js.map +1 -1
- package/dist/sharing/actions/share-resource.js +6 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +192 -30
- package/dist/vite/client.js.map +1 -1
- package/docs/content/toolkit-settings.mdx +56 -3
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const ANONYMOUS_ID_STORAGE_KEY = "agent-native.anonymous_id";
|
|
2
|
+
const SESSION_ID_STORAGE_KEY = "agent-native.session_id";
|
|
3
|
+
const SESSION_LAST_ACTIVITY_STORAGE_KEY = "agent-native.session_last_activity";
|
|
4
|
+
// 30-minute idle timeout matches GA4 / Mixpanel defaults: a tab left open
|
|
5
|
+
// overnight starts a new session in the morning instead of stretching one visit.
|
|
6
|
+
const SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
7
|
+
|
|
8
|
+
function generateVisitorId(): string {
|
|
9
|
+
try {
|
|
10
|
+
if (
|
|
11
|
+
typeof crypto !== "undefined" &&
|
|
12
|
+
typeof crypto.randomUUID === "function"
|
|
13
|
+
) {
|
|
14
|
+
return crypto.randomUUID();
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
// fall through to Math.random
|
|
18
|
+
}
|
|
19
|
+
return (
|
|
20
|
+
Date.now().toString(36) +
|
|
21
|
+
Math.random().toString(36).slice(2) +
|
|
22
|
+
Math.random().toString(36).slice(2)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function safeStorageGet(key: string): string | null {
|
|
27
|
+
try {
|
|
28
|
+
return window.localStorage.getItem(key);
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function safeStorageSet(key: string, value: string): void {
|
|
35
|
+
try {
|
|
36
|
+
window.localStorage.setItem(key, value);
|
|
37
|
+
} catch {
|
|
38
|
+
// private browsing / storage disabled -- best-effort
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getOrCreateAnalyticsAnonymousId(): string | undefined {
|
|
43
|
+
if (typeof window === "undefined") return undefined;
|
|
44
|
+
let id = safeStorageGet(ANONYMOUS_ID_STORAGE_KEY);
|
|
45
|
+
if (!id) {
|
|
46
|
+
id = generateVisitorId();
|
|
47
|
+
safeStorageSet(ANONYMOUS_ID_STORAGE_KEY, id);
|
|
48
|
+
}
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function getOrCreateAnalyticsSessionId(): string | undefined {
|
|
53
|
+
if (typeof window === "undefined") return undefined;
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const lastActivityRaw = safeStorageGet(SESSION_LAST_ACTIVITY_STORAGE_KEY);
|
|
56
|
+
const lastActivity = lastActivityRaw
|
|
57
|
+
? Number.parseInt(lastActivityRaw, 10)
|
|
58
|
+
: 0;
|
|
59
|
+
let id = safeStorageGet(SESSION_ID_STORAGE_KEY);
|
|
60
|
+
const expired =
|
|
61
|
+
!lastActivity ||
|
|
62
|
+
Number.isNaN(lastActivity) ||
|
|
63
|
+
now - lastActivity > SESSION_IDLE_TIMEOUT_MS;
|
|
64
|
+
if (!id || expired) {
|
|
65
|
+
id = generateVisitorId();
|
|
66
|
+
safeStorageSet(SESSION_ID_STORAGE_KEY, id);
|
|
67
|
+
}
|
|
68
|
+
safeStorageSet(SESSION_LAST_ACTIVITY_STORAGE_KEY, String(now));
|
|
69
|
+
return id;
|
|
70
|
+
}
|
|
@@ -5,13 +5,31 @@ import {
|
|
|
5
5
|
llmConnectionTrackingProperties,
|
|
6
6
|
type LlmConnectionStatus,
|
|
7
7
|
} from "../shared/llm-connection.js";
|
|
8
|
+
import {
|
|
9
|
+
getOrCreateAnalyticsAnonymousId,
|
|
10
|
+
getOrCreateAnalyticsSessionId,
|
|
11
|
+
} from "./analytics-session.js";
|
|
8
12
|
import { agentNativePath } from "./api-path.js";
|
|
13
|
+
import {
|
|
14
|
+
installErrorCapture,
|
|
15
|
+
type CapturedExceptionEvent,
|
|
16
|
+
} from "./error-capture.js";
|
|
9
17
|
import type {
|
|
10
18
|
SessionReplayOptions,
|
|
11
19
|
SessionReplayStartResult,
|
|
12
20
|
} from "./session-replay.js";
|
|
13
21
|
import { scrubUrl } from "./url-scrub.js";
|
|
14
22
|
export { scrubUrl } from "./url-scrub.js";
|
|
23
|
+
export {
|
|
24
|
+
addErrorBreadcrumb,
|
|
25
|
+
captureException,
|
|
26
|
+
captureMessage,
|
|
27
|
+
isErrorCaptureInstalled,
|
|
28
|
+
type CaptureExceptionContext,
|
|
29
|
+
type CapturedExceptionEvent,
|
|
30
|
+
type ExceptionBreadcrumb,
|
|
31
|
+
type ExceptionLevel,
|
|
32
|
+
} from "./error-capture.js";
|
|
15
33
|
export type {
|
|
16
34
|
SessionReplayConsoleOptions,
|
|
17
35
|
SessionReplayNetworkOptions,
|
|
@@ -40,6 +58,25 @@ type PageviewTrackingState = {
|
|
|
40
58
|
lastPageviewKey: string | null;
|
|
41
59
|
};
|
|
42
60
|
|
|
61
|
+
/**
|
|
62
|
+
* First-party, Sentry-style error capture configuration. Pass `true`/`false`
|
|
63
|
+
* to force on/off, or an options object to tune it. When omitted, error
|
|
64
|
+
* capture auto-enables whenever a first-party analytics public key is
|
|
65
|
+
* configured (mirroring pageview + session-replay auto-enable).
|
|
66
|
+
*/
|
|
67
|
+
export type ErrorCaptureConfigOptions = {
|
|
68
|
+
/** Build/release identifier attached to every captured exception. */
|
|
69
|
+
release?: string;
|
|
70
|
+
/** Deployment environment (e.g. "production"). Defaults to Vite MODE. */
|
|
71
|
+
environment?: string;
|
|
72
|
+
/** Auto-capture `window.onerror`. Defaults to true. */
|
|
73
|
+
captureGlobalErrors?: boolean;
|
|
74
|
+
/** Auto-capture `unhandledrejection`. Defaults to true. */
|
|
75
|
+
captureUnhandledRejections?: boolean;
|
|
76
|
+
/** Breadcrumb ring-buffer size. Defaults to 20. */
|
|
77
|
+
maxBreadcrumbs?: number;
|
|
78
|
+
};
|
|
79
|
+
|
|
43
80
|
export type ConfigureTrackingOptions = {
|
|
44
81
|
/**
|
|
45
82
|
* Agent Native first-party analytics public key. This mirrors hosted
|
|
@@ -53,6 +90,12 @@ export type ConfigureTrackingOptions = {
|
|
|
53
90
|
endpoint?: string;
|
|
54
91
|
getDefaultProps?: GetDefaultProps;
|
|
55
92
|
sessionReplay?: boolean | SessionReplayOptions;
|
|
93
|
+
/**
|
|
94
|
+
* First-party, Sentry-style error capture. Auto-captures uncaught errors
|
|
95
|
+
* and unhandled rejections and exposes `captureException`/`captureMessage`.
|
|
96
|
+
* Auto-enables when a public key is present; pass `false` to disable.
|
|
97
|
+
*/
|
|
98
|
+
errorCapture?: boolean | ErrorCaptureConfigOptions;
|
|
56
99
|
};
|
|
57
100
|
|
|
58
101
|
type SentryUser = {
|
|
@@ -84,6 +127,11 @@ let _sessionReplayOptions: SessionReplayOptions | null = null;
|
|
|
84
127
|
let _sessionReplayIdentitySnapshot: TrackingIdentity | null = null;
|
|
85
128
|
let _sessionReplayStartPromise: Promise<SessionReplayStartResult | null> | null =
|
|
86
129
|
null;
|
|
130
|
+
let _errorCaptureInstalled = false;
|
|
131
|
+
let _errorCaptureDisposer: (() => void) | null = null;
|
|
132
|
+
let _sessionReplayModuleForCapture:
|
|
133
|
+
| typeof import("./session-replay.js")
|
|
134
|
+
| null = null;
|
|
87
135
|
// Buffer for setSentryUser calls made before Sentry has initialized.
|
|
88
136
|
// `undefined` means "no pending update"; `null` means "pending clear".
|
|
89
137
|
let _pendingSentryUser: SentryUser | null | undefined = undefined;
|
|
@@ -91,19 +139,19 @@ let _pendingSentryOrgId: string | null | undefined = undefined;
|
|
|
91
139
|
|
|
92
140
|
const AGENT_NATIVE_ANALYTICS_DEFAULT_ENDPOINT =
|
|
93
141
|
"https://analytics.agent-native.com/track";
|
|
142
|
+
/**
|
|
143
|
+
* Dedicated first-party analytics event name for captured exceptions. The
|
|
144
|
+
* analytics server ingest forks events with this name into the error-capture
|
|
145
|
+
* tables (error_issues / error_events) while still recording them in
|
|
146
|
+
* analytics_events for alerting. Keep in sync with the template server ingest.
|
|
147
|
+
*/
|
|
148
|
+
export const AGENT_NATIVE_EXCEPTION_EVENT_NAME = "$exception";
|
|
94
149
|
const PAGEVIEW_TRACKING_STATE_KEY = Symbol.for(
|
|
95
150
|
"agent-native.client.pageviewTracking",
|
|
96
151
|
);
|
|
97
152
|
|
|
98
|
-
const ANONYMOUS_ID_STORAGE_KEY = "agent-native.anonymous_id";
|
|
99
|
-
const SESSION_ID_STORAGE_KEY = "agent-native.session_id";
|
|
100
|
-
const SESSION_LAST_ACTIVITY_STORAGE_KEY = "agent-native.session_last_activity";
|
|
101
153
|
const LLM_CONNECTION_STORAGE_KEY = "agent-native.llm_connection_status";
|
|
102
154
|
const LLM_CONNECTION_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
103
|
-
// 30-minute idle timeout matches GA4 / Mixpanel defaults — a tab left open
|
|
104
|
-
// overnight starts a new session in the morning rather than stretching one
|
|
105
|
-
// session over multiple visits.
|
|
106
|
-
const SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
107
155
|
|
|
108
156
|
// First-touch referral attribution (viral attribution). Captured once on the
|
|
109
157
|
// visitor's first page load and persisted across the signup boundary so the
|
|
@@ -143,24 +191,6 @@ export interface FirstTouchAttribution {
|
|
|
143
191
|
landed_at?: string;
|
|
144
192
|
}
|
|
145
193
|
|
|
146
|
-
function generateVisitorId(): string {
|
|
147
|
-
try {
|
|
148
|
-
if (
|
|
149
|
-
typeof crypto !== "undefined" &&
|
|
150
|
-
typeof crypto.randomUUID === "function"
|
|
151
|
-
) {
|
|
152
|
-
return crypto.randomUUID();
|
|
153
|
-
}
|
|
154
|
-
} catch {
|
|
155
|
-
// fall through to Math.random
|
|
156
|
-
}
|
|
157
|
-
return (
|
|
158
|
-
Date.now().toString(36) +
|
|
159
|
-
Math.random().toString(36).slice(2) +
|
|
160
|
-
Math.random().toString(36).slice(2)
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
194
|
function safeStorageGet(key: string): string | null {
|
|
165
195
|
try {
|
|
166
196
|
return window.localStorage.getItem(key);
|
|
@@ -371,13 +401,7 @@ function applyTrackingIdentity(
|
|
|
371
401
|
}
|
|
372
402
|
|
|
373
403
|
function getOrCreateAnonymousId(): string | undefined {
|
|
374
|
-
|
|
375
|
-
let id = safeStorageGet(ANONYMOUS_ID_STORAGE_KEY);
|
|
376
|
-
if (!id) {
|
|
377
|
-
id = generateVisitorId();
|
|
378
|
-
safeStorageSet(ANONYMOUS_ID_STORAGE_KEY, id);
|
|
379
|
-
}
|
|
380
|
-
return id;
|
|
404
|
+
return getOrCreateAnalyticsAnonymousId();
|
|
381
405
|
}
|
|
382
406
|
|
|
383
407
|
export function getAnalyticsAnonymousId(): string | undefined {
|
|
@@ -385,23 +409,7 @@ export function getAnalyticsAnonymousId(): string | undefined {
|
|
|
385
409
|
}
|
|
386
410
|
|
|
387
411
|
function getOrCreateSessionId(): string | undefined {
|
|
388
|
-
|
|
389
|
-
const now = Date.now();
|
|
390
|
-
const lastActivityRaw = safeStorageGet(SESSION_LAST_ACTIVITY_STORAGE_KEY);
|
|
391
|
-
const lastActivity = lastActivityRaw
|
|
392
|
-
? Number.parseInt(lastActivityRaw, 10)
|
|
393
|
-
: 0;
|
|
394
|
-
let id = safeStorageGet(SESSION_ID_STORAGE_KEY);
|
|
395
|
-
const expired =
|
|
396
|
-
!lastActivity ||
|
|
397
|
-
Number.isNaN(lastActivity) ||
|
|
398
|
-
now - lastActivity > SESSION_IDLE_TIMEOUT_MS;
|
|
399
|
-
if (!id || expired) {
|
|
400
|
-
id = generateVisitorId();
|
|
401
|
-
safeStorageSet(SESSION_ID_STORAGE_KEY, id);
|
|
402
|
-
}
|
|
403
|
-
safeStorageSet(SESSION_LAST_ACTIVITY_STORAGE_KEY, String(now));
|
|
404
|
-
return id;
|
|
412
|
+
return getOrCreateAnalyticsSessionId();
|
|
405
413
|
}
|
|
406
414
|
|
|
407
415
|
export function getAnalyticsSessionId(): string | undefined {
|
|
@@ -978,7 +986,125 @@ export function configureTracking(options: ConfigureTrackingOptions): void {
|
|
|
978
986
|
endpoint: options.endpoint,
|
|
979
987
|
publicKey,
|
|
980
988
|
});
|
|
989
|
+
maybeInstallErrorCapture(options.errorCapture);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Lazily load the session-replay module so error capture can read the active
|
|
995
|
+
* replay id and surface manual captures on the replay timeline without a
|
|
996
|
+
* static import (which would create an analytics <-> session-replay import
|
|
997
|
+
* cycle and pull the replay module into the analytics chunk eagerly).
|
|
998
|
+
*/
|
|
999
|
+
function loadSessionReplayModuleForCapture(): void {
|
|
1000
|
+
if (_sessionReplayModuleForCapture) return;
|
|
1001
|
+
import("./session-replay.js")
|
|
1002
|
+
.then((mod) => {
|
|
1003
|
+
_sessionReplayModuleForCapture = mod;
|
|
1004
|
+
})
|
|
1005
|
+
.catch(() => {
|
|
1006
|
+
// Session linkage is best-effort; capture still works without it.
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function errorCaptureSessionContext(): {
|
|
1011
|
+
sessionId?: string;
|
|
1012
|
+
anonymousId?: string;
|
|
1013
|
+
replayId?: string;
|
|
1014
|
+
} {
|
|
1015
|
+
return {
|
|
1016
|
+
sessionId: getOrCreateSessionId(),
|
|
1017
|
+
anonymousId: getOrCreateAnonymousId(),
|
|
1018
|
+
replayId:
|
|
1019
|
+
_sessionReplayModuleForCapture?.getSessionReplayId?.() ?? undefined,
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
function exceptionEventProperties(
|
|
1024
|
+
event: CapturedExceptionEvent,
|
|
1025
|
+
): Record<string, unknown> {
|
|
1026
|
+
return {
|
|
1027
|
+
exceptionType: event.type,
|
|
1028
|
+
exceptionMessage: event.message,
|
|
1029
|
+
...(event.stack ? { exceptionStack: event.stack } : {}),
|
|
1030
|
+
handled: event.handled,
|
|
1031
|
+
level: event.level,
|
|
1032
|
+
occurredAt: event.occurredAt,
|
|
1033
|
+
...(event.url ? { errorUrl: event.url } : {}),
|
|
1034
|
+
...(event.release ? { release: event.release } : {}),
|
|
1035
|
+
...(event.environment ? { environment: event.environment } : {}),
|
|
1036
|
+
...(event.sessionReplayId
|
|
1037
|
+
? { sessionReplayId: event.sessionReplayId }
|
|
1038
|
+
: {}),
|
|
1039
|
+
...(event.breadcrumbs?.length ? { breadcrumbs: event.breadcrumbs } : {}),
|
|
1040
|
+
...(event.tags ? { exceptionTags: event.tags } : {}),
|
|
1041
|
+
...(event.extra ? { exceptionExtra: event.extra } : {}),
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
function sendExceptionEvent(event: CapturedExceptionEvent): void {
|
|
1046
|
+
// Route through the existing first-party analytics ingest as a dedicated
|
|
1047
|
+
// `$exception` event. This reuses the public-key auth + sendBeacon/keepalive
|
|
1048
|
+
// transport; the server forks it into error_issues/error_events and still
|
|
1049
|
+
// records it in analytics_events for alerting.
|
|
1050
|
+
trackEvent(
|
|
1051
|
+
AGENT_NATIVE_EXCEPTION_EVENT_NAME,
|
|
1052
|
+
exceptionEventProperties(event),
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function emitExceptionToReplay(event: CapturedExceptionEvent): void {
|
|
1057
|
+
_sessionReplayModuleForCapture?.emitSessionReplayException?.({
|
|
1058
|
+
type: event.type,
|
|
1059
|
+
message: event.message,
|
|
1060
|
+
level: event.level,
|
|
1061
|
+
...(event.stack ? { stack: event.stack } : {}),
|
|
1062
|
+
...(event.url ? { url: event.url } : {}),
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
function errorCaptureAutoEnabled(): boolean {
|
|
1067
|
+
const publicKey =
|
|
1068
|
+
_agentNativeAnalyticsPublicKey ||
|
|
1069
|
+
(import.meta.env as Record<string, string | undefined>)
|
|
1070
|
+
?.VITE_AGENT_NATIVE_ANALYTICS_PUBLIC_KEY;
|
|
1071
|
+
return !!publicKey;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function maybeInstallErrorCapture(
|
|
1075
|
+
config: boolean | ErrorCaptureConfigOptions | undefined,
|
|
1076
|
+
): void {
|
|
1077
|
+
if (typeof window === "undefined") return;
|
|
1078
|
+
if (config === false) {
|
|
1079
|
+
_errorCaptureDisposer?.();
|
|
1080
|
+
_errorCaptureDisposer = null;
|
|
1081
|
+
_errorCaptureInstalled = false;
|
|
1082
|
+
return;
|
|
981
1083
|
}
|
|
1084
|
+
if (_errorCaptureInstalled && config === undefined) return;
|
|
1085
|
+
const enabled = config === undefined ? errorCaptureAutoEnabled() : true;
|
|
1086
|
+
if (!enabled) return;
|
|
1087
|
+
const options = typeof config === "object" ? config : {};
|
|
1088
|
+
loadSessionReplayModuleForCapture();
|
|
1089
|
+
_errorCaptureDisposer = installErrorCapture({
|
|
1090
|
+
send: sendExceptionEvent,
|
|
1091
|
+
getSessionContext: errorCaptureSessionContext,
|
|
1092
|
+
emitReplayEvent: emitExceptionToReplay,
|
|
1093
|
+
environment:
|
|
1094
|
+
options.environment ||
|
|
1095
|
+
(import.meta.env as Record<string, string | undefined>)?.MODE,
|
|
1096
|
+
...(options.release ? { release: options.release } : {}),
|
|
1097
|
+
...(options.captureGlobalErrors !== undefined
|
|
1098
|
+
? { captureGlobalErrors: options.captureGlobalErrors }
|
|
1099
|
+
: {}),
|
|
1100
|
+
...(options.captureUnhandledRejections !== undefined
|
|
1101
|
+
? { captureUnhandledRejections: options.captureUnhandledRejections }
|
|
1102
|
+
: {}),
|
|
1103
|
+
...(options.maxBreadcrumbs !== undefined
|
|
1104
|
+
? { maxBreadcrumbs: options.maxBreadcrumbs }
|
|
1105
|
+
: {}),
|
|
1106
|
+
});
|
|
1107
|
+
_errorCaptureInstalled = true;
|
|
982
1108
|
}
|
|
983
1109
|
|
|
984
1110
|
function sessionReplayEnabledFromEnv(): boolean {
|
|
@@ -82,6 +82,22 @@ export function displayableUserMessageText(text: string): string {
|
|
|
82
82
|
.trim();
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export function isHiddenUserMessage(message: unknown): boolean {
|
|
86
|
+
const meta = (message as { metadata?: unknown })?.metadata as
|
|
87
|
+
| {
|
|
88
|
+
custom?: {
|
|
89
|
+
agentNativeHiddenUserMessage?: unknown;
|
|
90
|
+
agentNativeRecoveryAction?: unknown;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
| undefined;
|
|
94
|
+
return (
|
|
95
|
+
meta?.custom?.agentNativeHiddenUserMessage === true ||
|
|
96
|
+
meta?.custom?.agentNativeRecoveryAction === "continue" ||
|
|
97
|
+
meta?.custom?.agentNativeRecoveryAction === "retry"
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
85
101
|
// ─── Message timestamp helpers ────────────────────────────────────────────────
|
|
86
102
|
|
|
87
103
|
interface FormattedMessageTimestamp {
|
|
@@ -634,13 +650,15 @@ export function UserMessage() {
|
|
|
634
650
|
const timestamp = formatMessageTimestamp(message.createdAt);
|
|
635
651
|
const isEditing = useComposer((state) => state.isEditing);
|
|
636
652
|
const chatRunning = React.useContext(ChatRunningContext);
|
|
653
|
+
const hidden = isHiddenUserMessage(message);
|
|
637
654
|
const hasDisplayableText =
|
|
638
|
-
|
|
655
|
+
!hidden &&
|
|
656
|
+
(message.content
|
|
639
657
|
?.filter((part): part is { type: "text"; text: string } => {
|
|
640
658
|
return part.type === "text" && typeof part.text === "string";
|
|
641
659
|
})
|
|
642
660
|
.some((part) => displayableUserMessageText(part.text).length > 0) ??
|
|
643
|
-
|
|
661
|
+
false);
|
|
644
662
|
|
|
645
663
|
useEffect(() => {
|
|
646
664
|
const el = contentRef.current;
|
|
@@ -656,6 +674,8 @@ export function UserMessage() {
|
|
|
656
674
|
return () => observer.disconnect();
|
|
657
675
|
}, [hasDisplayableText]);
|
|
658
676
|
|
|
677
|
+
if (hidden) return null;
|
|
678
|
+
|
|
659
679
|
// When in edit mode, show the inline edit composer instead of the message bubble.
|
|
660
680
|
if (isEditing) {
|
|
661
681
|
return (
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MessageScroller as ShadcnMessageScroller,
|
|
3
|
+
useMessageScroller,
|
|
4
|
+
useMessageScrollerScrollable,
|
|
5
|
+
useMessageScrollerVisibility,
|
|
6
|
+
type MessageScrollerDefaultScrollPosition,
|
|
7
|
+
type MessageScrollerScrollAlign,
|
|
8
|
+
type MessageScrollerScrollOptions,
|
|
9
|
+
type MessageScrollerScrollable,
|
|
10
|
+
type MessageScrollerVisibilityState,
|
|
11
|
+
} from "@shadcn/react/message-scroller";
|
|
12
|
+
import { IconChevronDown } from "@tabler/icons-react";
|
|
13
|
+
import * as React from "react";
|
|
14
|
+
|
|
15
|
+
import { cn } from "../../utils.js";
|
|
16
|
+
|
|
17
|
+
type MessageScrollerProviderProps = React.ComponentProps<
|
|
18
|
+
typeof ShadcnMessageScroller.Provider
|
|
19
|
+
>;
|
|
20
|
+
type MessageScrollerRootProps = React.ComponentProps<
|
|
21
|
+
typeof ShadcnMessageScroller.Root
|
|
22
|
+
>;
|
|
23
|
+
type MessageScrollerViewportProps = React.ComponentProps<
|
|
24
|
+
typeof ShadcnMessageScroller.Viewport
|
|
25
|
+
>;
|
|
26
|
+
type MessageScrollerContentProps = React.ComponentProps<
|
|
27
|
+
typeof ShadcnMessageScroller.Content
|
|
28
|
+
>;
|
|
29
|
+
type MessageScrollerItemProps = React.ComponentProps<
|
|
30
|
+
typeof ShadcnMessageScroller.Item
|
|
31
|
+
>;
|
|
32
|
+
type MessageScrollerButtonProps = React.ComponentProps<
|
|
33
|
+
typeof ShadcnMessageScroller.Button
|
|
34
|
+
>;
|
|
35
|
+
|
|
36
|
+
function MessageScrollerProvider(props: MessageScrollerProviderProps) {
|
|
37
|
+
return <ShadcnMessageScroller.Provider {...props} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function MessageScroller({ className, ...props }: MessageScrollerRootProps) {
|
|
41
|
+
return (
|
|
42
|
+
<ShadcnMessageScroller.Root
|
|
43
|
+
className={cn("relative flex min-h-0 flex-1 flex-col", className)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function MessageScrollerViewport({
|
|
50
|
+
className,
|
|
51
|
+
...props
|
|
52
|
+
}: MessageScrollerViewportProps) {
|
|
53
|
+
return (
|
|
54
|
+
<ShadcnMessageScroller.Viewport
|
|
55
|
+
className={cn(
|
|
56
|
+
"min-h-0 flex-1 overflow-y-auto overflow-x-hidden",
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function MessageScrollerContent({
|
|
65
|
+
className,
|
|
66
|
+
spacerClassName,
|
|
67
|
+
...props
|
|
68
|
+
}: MessageScrollerContentProps) {
|
|
69
|
+
return (
|
|
70
|
+
<ShadcnMessageScroller.Content
|
|
71
|
+
className={cn("flex flex-col", className)}
|
|
72
|
+
spacerClassName={cn("shrink-0", spacerClassName)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function MessageScrollerItem(props: MessageScrollerItemProps) {
|
|
79
|
+
return <ShadcnMessageScroller.Item {...props} />;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function MessageScrollerButton({
|
|
83
|
+
className,
|
|
84
|
+
children,
|
|
85
|
+
render,
|
|
86
|
+
...props
|
|
87
|
+
}: MessageScrollerButtonProps) {
|
|
88
|
+
return (
|
|
89
|
+
<ShadcnMessageScroller.Button
|
|
90
|
+
render={
|
|
91
|
+
render ??
|
|
92
|
+
((buttonProps) => (
|
|
93
|
+
<div className="shrink-0 flex justify-center -mb-1">
|
|
94
|
+
<button
|
|
95
|
+
{...buttonProps}
|
|
96
|
+
className={cn(
|
|
97
|
+
"flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent",
|
|
98
|
+
"data-[active=false]:hidden",
|
|
99
|
+
className,
|
|
100
|
+
buttonProps.className as string | undefined,
|
|
101
|
+
)}
|
|
102
|
+
aria-label="Scroll to bottom"
|
|
103
|
+
>
|
|
104
|
+
{children ?? (
|
|
105
|
+
<IconChevronDown className="h-3.5 w-3.5 text-muted-foreground" />
|
|
106
|
+
)}
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
))
|
|
110
|
+
}
|
|
111
|
+
{...props}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
MessageScroller,
|
|
118
|
+
MessageScrollerButton,
|
|
119
|
+
MessageScrollerContent,
|
|
120
|
+
MessageScrollerItem,
|
|
121
|
+
MessageScrollerProvider,
|
|
122
|
+
MessageScrollerViewport,
|
|
123
|
+
useMessageScroller,
|
|
124
|
+
useMessageScrollerScrollable,
|
|
125
|
+
useMessageScrollerVisibility,
|
|
126
|
+
type MessageScrollerDefaultScrollPosition,
|
|
127
|
+
type MessageScrollerScrollAlign,
|
|
128
|
+
type MessageScrollerScrollOptions,
|
|
129
|
+
type MessageScrollerScrollable,
|
|
130
|
+
type MessageScrollerVisibilityState,
|
|
131
|
+
};
|
|
@@ -18,6 +18,14 @@ import {
|
|
|
18
18
|
resolveBuiltinActionChatRenderer,
|
|
19
19
|
resolveBuiltinFallbackToolRenderer,
|
|
20
20
|
} from "../chat/widgets/builtin-tool-renderers.js";
|
|
21
|
+
import {
|
|
22
|
+
MessageScroller,
|
|
23
|
+
MessageScrollerButton,
|
|
24
|
+
MessageScrollerContent,
|
|
25
|
+
MessageScrollerItem,
|
|
26
|
+
MessageScrollerProvider,
|
|
27
|
+
MessageScrollerViewport,
|
|
28
|
+
} from "../components/ui/message-scroller.js";
|
|
21
29
|
import { HighlightedCodeBlock as SharedHighlightedCodeBlock } from "../HighlightedCodeBlock.js";
|
|
22
30
|
import { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
23
31
|
import { humanizeToolName } from "../tool-display.js";
|
|
@@ -30,7 +38,6 @@ import type {
|
|
|
30
38
|
AgentConversationNotice,
|
|
31
39
|
AgentConversationToolCall,
|
|
32
40
|
} from "./types.js";
|
|
33
|
-
import { useNearBottomAutoscroll } from "./use-near-bottom-autoscroll.js";
|
|
34
41
|
|
|
35
42
|
export interface AgentConversationProps {
|
|
36
43
|
messages: AgentConversationMessage[];
|
|
@@ -48,22 +55,12 @@ export function AgentConversation({
|
|
|
48
55
|
messages,
|
|
49
56
|
loading = false,
|
|
50
57
|
error,
|
|
51
|
-
streaming = false,
|
|
52
58
|
className,
|
|
53
59
|
timelineClassName,
|
|
54
60
|
emptyTitle = "No messages yet",
|
|
55
61
|
emptyDescription,
|
|
56
62
|
composer,
|
|
57
63
|
}: AgentConversationProps) {
|
|
58
|
-
const followKey = `${messages.length}:${
|
|
59
|
-
messages[messages.length - 1]?.text?.length ?? 0
|
|
60
|
-
}`;
|
|
61
|
-
const { scrollRef, showScrollToBottom, scrollToBottom } =
|
|
62
|
-
useNearBottomAutoscroll<HTMLDivElement>({
|
|
63
|
-
followKey,
|
|
64
|
-
streaming,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
64
|
return (
|
|
68
65
|
<section className={cn("agent-conversation", className)}>
|
|
69
66
|
{error && (
|
|
@@ -72,37 +69,62 @@ export function AgentConversation({
|
|
|
72
69
|
<span>{error}</span>
|
|
73
70
|
</div>
|
|
74
71
|
)}
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
<MessageScrollerProvider autoScroll>
|
|
73
|
+
<MessageScroller className="agent-conversation__scroller">
|
|
74
|
+
<MessageScrollerViewport
|
|
75
|
+
className={cn("agent-conversation__timeline", timelineClassName)}
|
|
76
|
+
>
|
|
77
|
+
<MessageScrollerContent>
|
|
78
|
+
{loading && messages.length === 0 ? (
|
|
79
|
+
<MessageScrollerItem>
|
|
80
|
+
<ConversationEmpty
|
|
81
|
+
icon={
|
|
82
|
+
<IconLoader2
|
|
83
|
+
size={17}
|
|
84
|
+
className="agent-conversation-spin"
|
|
85
|
+
/>
|
|
86
|
+
}
|
|
87
|
+
title="Loading session..."
|
|
88
|
+
/>
|
|
89
|
+
</MessageScrollerItem>
|
|
90
|
+
) : messages.length === 0 ? (
|
|
91
|
+
<MessageScrollerItem>
|
|
92
|
+
<ConversationEmpty
|
|
93
|
+
icon={<IconClock size={18} />}
|
|
94
|
+
title={emptyTitle}
|
|
95
|
+
description={emptyDescription}
|
|
96
|
+
/>
|
|
97
|
+
</MessageScrollerItem>
|
|
98
|
+
) : (
|
|
99
|
+
messages.map((message) => (
|
|
100
|
+
<MessageScrollerItem
|
|
101
|
+
key={message.id}
|
|
102
|
+
messageId={message.id}
|
|
103
|
+
scrollAnchor={message.role === "user"}
|
|
104
|
+
>
|
|
105
|
+
<AgentConversationMessageView message={message} />
|
|
106
|
+
</MessageScrollerItem>
|
|
107
|
+
))
|
|
108
|
+
)}
|
|
109
|
+
</MessageScrollerContent>
|
|
110
|
+
</MessageScrollerViewport>
|
|
111
|
+
<MessageScrollerButton
|
|
112
|
+
render={(buttonProps) => (
|
|
113
|
+
<button
|
|
114
|
+
{...buttonProps}
|
|
115
|
+
className={cn(
|
|
116
|
+
"agent-conversation__scroll-bottom",
|
|
117
|
+
"data-[active=false]:hidden",
|
|
118
|
+
buttonProps.className as string | undefined,
|
|
119
|
+
)}
|
|
120
|
+
aria-label="Scroll to bottom"
|
|
121
|
+
>
|
|
122
|
+
<IconArrowDown size={15} strokeWidth={1.9} />
|
|
123
|
+
</button>
|
|
124
|
+
)}
|
|
89
125
|
/>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<AgentConversationMessageView key={message.id} message={message} />
|
|
93
|
-
))
|
|
94
|
-
)}
|
|
95
|
-
</div>
|
|
96
|
-
{showScrollToBottom && (
|
|
97
|
-
<button
|
|
98
|
-
type="button"
|
|
99
|
-
className="agent-conversation__scroll-bottom"
|
|
100
|
-
onClick={scrollToBottom}
|
|
101
|
-
aria-label="Scroll to bottom"
|
|
102
|
-
>
|
|
103
|
-
<IconArrowDown size={15} strokeWidth={1.9} />
|
|
104
|
-
</button>
|
|
105
|
-
)}
|
|
126
|
+
</MessageScroller>
|
|
127
|
+
</MessageScrollerProvider>
|
|
106
128
|
{composer}
|
|
107
129
|
</section>
|
|
108
130
|
);
|