@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.
Files changed (315) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +22 -0
  3. package/corpus/core/docs/content/toolkit-settings.mdx +56 -3
  4. package/corpus/core/package.json +2 -1
  5. package/corpus/core/src/agent/run-ownership.ts +29 -1
  6. package/corpus/core/src/changelog/parse.ts +78 -0
  7. package/corpus/core/src/chat-threads/schema.ts +43 -0
  8. package/corpus/core/src/chat-threads/store.ts +144 -12
  9. package/corpus/core/src/cli/workspace-dev.ts +25 -5
  10. package/corpus/core/src/client/AgentPanel.tsx +79 -14
  11. package/corpus/core/src/client/AssistantChat.tsx +359 -425
  12. package/corpus/core/src/client/analytics-session.ts +70 -0
  13. package/corpus/core/src/client/analytics.ts +175 -49
  14. package/corpus/core/src/client/chat/message-components.tsx +22 -2
  15. package/corpus/core/src/client/components/ui/message-scroller.tsx +131 -0
  16. package/corpus/core/src/client/conversation/AgentConversation.tsx +63 -41
  17. package/corpus/core/src/client/error-capture.ts +616 -0
  18. package/corpus/core/src/client/index.ts +12 -0
  19. package/corpus/core/src/client/session-replay.ts +57 -7
  20. package/corpus/core/src/client/settings/SettingsPanel.tsx +123 -1
  21. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +292 -45
  22. package/corpus/core/src/client/settings/index.ts +1 -0
  23. package/corpus/core/src/client/sharing/ShareButton.tsx +14 -11
  24. package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -10
  25. package/corpus/core/src/mcp/builtin-tools.ts +29 -2
  26. package/corpus/core/src/server/agent-chat-plugin.ts +174 -79
  27. package/corpus/core/src/server/onboarding-html.ts +28 -16
  28. package/corpus/core/src/sharing/actions/list-resource-shares.ts +45 -1
  29. package/corpus/core/src/sharing/actions/share-resource.ts +9 -0
  30. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  31. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  32. package/corpus/core/src/vite/client.ts +217 -35
  33. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +8 -7
  34. package/corpus/templates/analytics/.agents/skills/analysis-workspace/SKILL.md +14 -10
  35. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +15 -15
  36. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +1 -0
  37. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -22
  38. package/corpus/templates/analytics/.agents/skills/data-programs/SKILL.md +114 -61
  39. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +1 -0
  40. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +7 -7
  41. package/corpus/templates/analytics/.agents/skills/hubspot/SKILL.md +1 -0
  42. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +1 -1
  43. package/corpus/templates/analytics/.builder/skills/bigquery/SKILL.md +17 -17
  44. package/corpus/templates/analytics/.builder/skills/gcloud/SKILL.md +5 -5
  45. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +7 -7
  46. package/corpus/templates/analytics/.builder/skills/gong/SKILL.md +12 -12
  47. package/corpus/templates/analytics/.builder/skills/grafana/SKILL.md +7 -7
  48. package/corpus/templates/analytics/.builder/skills/sentry/SKILL.md +7 -7
  49. package/corpus/templates/analytics/.builder/skills/slack/SKILL.md +6 -6
  50. package/corpus/templates/analytics/.builder/skills/stripe/SKILL.md +7 -7
  51. package/corpus/templates/analytics/AGENTS.md +47 -2
  52. package/corpus/templates/analytics/actions/add-status-page-monitor.ts +36 -0
  53. package/corpus/templates/analytics/actions/capture-test-error.ts +33 -0
  54. package/corpus/templates/analytics/actions/delete-monitor.ts +24 -0
  55. package/corpus/templates/analytics/actions/delete-status-page.ts +23 -0
  56. package/corpus/templates/analytics/actions/get-error-issue.ts +36 -0
  57. package/corpus/templates/analytics/actions/get-monitor-stats.ts +55 -0
  58. package/corpus/templates/analytics/actions/get-monitor.ts +27 -0
  59. package/corpus/templates/analytics/actions/get-public-status-page.ts +41 -0
  60. package/corpus/templates/analytics/actions/get-status-page.ts +29 -0
  61. package/corpus/templates/analytics/actions/list-error-issues.ts +40 -0
  62. package/corpus/templates/analytics/actions/list-monitors.ts +21 -0
  63. package/corpus/templates/analytics/actions/list-status-pages.ts +21 -0
  64. package/corpus/templates/analytics/actions/match-error-issues.ts +51 -0
  65. package/corpus/templates/analytics/actions/navigate.ts +58 -4
  66. package/corpus/templates/analytics/actions/remove-status-page-monitor.ts +22 -0
  67. package/corpus/templates/analytics/actions/reorder-status-page-monitors.ts +25 -0
  68. package/corpus/templates/analytics/actions/resolve-error-issue.ts +38 -0
  69. package/corpus/templates/analytics/actions/run-monitor-check.ts +23 -0
  70. package/corpus/templates/analytics/actions/save-analysis.ts +1 -0
  71. package/corpus/templates/analytics/actions/save-monitor.ts +145 -0
  72. package/corpus/templates/analytics/actions/save-status-page.ts +47 -0
  73. package/corpus/templates/analytics/actions/view-screen.ts +212 -0
  74. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  75. package/corpus/templates/analytics/app/components/layout/Layout.tsx +10 -1
  76. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +134 -39
  77. package/corpus/templates/analytics/app/components/monitoring/PublicStatusView.tsx +351 -0
  78. package/corpus/templates/analytics/app/components/monitoring/ResponseTimeChart.tsx +174 -0
  79. package/corpus/templates/analytics/app/components/monitoring/UptimeStatCards.tsx +85 -0
  80. package/corpus/templates/analytics/app/components/monitoring/UptimeTimelineBars.tsx +106 -0
  81. package/corpus/templates/analytics/app/components/monitoring/chart-utils.ts +101 -0
  82. package/corpus/templates/analytics/app/components/monitoring/index.ts +28 -0
  83. package/corpus/templates/analytics/app/components/monitoring/types.ts +42 -0
  84. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +34 -0
  85. package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -0
  86. package/corpus/templates/analytics/app/i18n-data.ts +33 -0
  87. package/corpus/templates/analytics/app/pages/DataSources.tsx +28 -0
  88. package/corpus/templates/analytics/app/pages/Settings.tsx +77 -9
  89. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -3
  90. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +7 -0
  91. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +205 -0
  92. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +100 -0
  93. package/corpus/templates/analytics/app/pages/monitoring/UptimePanel.tsx +475 -0
  94. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +372 -0
  95. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +360 -0
  96. package/corpus/templates/analytics/app/pages/monitoring/errors/Sparkline.tsx +55 -0
  97. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +106 -0
  98. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +75 -0
  99. package/corpus/templates/analytics/app/pages/monitoring/errors/utils.ts +132 -0
  100. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorDetail.tsx +535 -0
  101. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +1026 -0
  102. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorList.tsx +311 -0
  103. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +235 -0
  104. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPageEditor.tsx +661 -0
  105. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/StatusPagesView.tsx +355 -0
  106. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/i18n.ts +106 -0
  107. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/slug.ts +24 -0
  108. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-pages/types.ts +20 -0
  109. package/corpus/templates/analytics/app/pages/monitoring/uptime/status-summary.ts +87 -0
  110. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +161 -0
  111. package/corpus/templates/analytics/app/pages/monitoring/uptime/utils.ts +210 -0
  112. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +76 -1
  113. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +74 -9
  114. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +197 -20
  115. package/corpus/templates/analytics/app/root.tsx +33 -1
  116. package/corpus/templates/analytics/app/routes/monitoring._index.tsx +10 -0
  117. package/corpus/templates/analytics/app/routes/status.$slug.tsx +118 -0
  118. package/corpus/templates/analytics/changelog/2026-07-08-add-uptime-monitors-that-ping-your-urls-and-alert-you-when-t.md +6 -0
  119. package/corpus/templates/analytics/changelog/2026-07-08-analytics-chats-keep-large-data-dictionaries-compact-so-prov.md +6 -0
  120. package/corpus/templates/analytics/changelog/2026-07-08-create-public-status-pages-that-share-the-live-health-of-cho.md +6 -0
  121. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-extension-panels-use-clearer-open-copy.md +6 -0
  122. package/corpus/templates/analytics/changelog/2026-07-08-error-capture.md +6 -0
  123. package/corpus/templates/analytics/changelog/2026-07-08-fixed-single-panel-dashboard-drags-so-they-no-longer-rewrite.md +6 -0
  124. package/corpus/templates/analytics/changelog/2026-07-08-jump-straight-from-an-error-in-a-session-recording-to-its-fu.md +6 -0
  125. package/corpus/templates/analytics/changelog/2026-07-08-monitor-detail-and-list-now-show-colorful-uptime-timelines-r.md +6 -0
  126. package/corpus/templates/analytics/changelog/2026-07-08-pinned-ask-chats-now-show-a-pin-icon-in-the-sidebar.md +6 -0
  127. package/corpus/templates/analytics/changelog/2026-07-08-publish-a-public-uptime-status-page-with-colorful-uptime-tim.md +6 -0
  128. package/corpus/templates/analytics/changelog/2026-07-08-sessions-now-hide-visitor-emails-in-demo-mode-and-show-clean.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +5 -0
  130. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +5 -0
  131. package/corpus/templates/analytics/changelog/2026-07-08-the-uptime-monitor-list-now-has-a-current-status-overview-wi.md +6 -0
  132. package/corpus/templates/analytics/docs/error-capture.md +172 -0
  133. package/corpus/templates/analytics/docs/uptime-monitoring.md +150 -0
  134. package/corpus/templates/analytics/server/db/schema-errors.ts +150 -0
  135. package/corpus/templates/analytics/server/db/schema-monitoring.ts +177 -0
  136. package/corpus/templates/analytics/server/db/schema.ts +6 -0
  137. package/corpus/templates/analytics/server/jobs/uptime-monitors.ts +123 -0
  138. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +41 -0
  139. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +55 -12
  140. package/corpus/templates/analytics/server/lib/error-capture.ts +1331 -0
  141. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +47 -1
  142. package/corpus/templates/analytics/server/lib/monitor-stats.ts +494 -0
  143. package/corpus/templates/analytics/server/lib/status-pages.ts +798 -0
  144. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +1665 -0
  145. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -37
  146. package/corpus/templates/analytics/server/plugins/auth.ts +11 -1
  147. package/corpus/templates/analytics/server/plugins/db.ts +408 -0
  148. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +63 -0
  149. package/corpus/templates/assets/app/routes/_index.tsx +1 -1
  150. package/corpus/templates/assets/app/routes/settings.tsx +22 -1
  151. package/corpus/templates/assets/changelog/2026-07-08-recent-drafts-keep-comfortable-side-padding.md +6 -0
  152. package/corpus/templates/assets/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  153. package/corpus/templates/brain/app/routes/settings.tsx +43 -5
  154. package/corpus/templates/brain/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  155. package/corpus/templates/calendar/app/pages/Settings.tsx +44 -6
  156. package/corpus/templates/calendar/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  157. package/corpus/templates/chat/app/routes/settings.tsx +16 -1
  158. package/corpus/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  159. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +79 -37
  160. package/corpus/templates/clips/app/components/player/player-controls.tsx +35 -0
  161. package/corpus/templates/clips/app/components/player/video-player.tsx +162 -18
  162. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +63 -6
  163. package/corpus/templates/clips/app/routes/record.tsx +18 -1
  164. package/corpus/templates/clips/changelog/2026-07-07-shared-clips-start-playback-reliably-from-the-first-play-click.md +6 -0
  165. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-camera-and-microphone-menus-now-show-which-.md +6 -0
  166. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-copies-new-clip-links-after-saving.md +6 -0
  167. package/corpus/templates/clips/changelog/2026-07-08-chrome-extension-recordings-now-continue-after-granting-came.md +6 -0
  168. package/corpus/templates/clips/changelog/2026-07-08-mobile-shared-clips-now-have-loom-style-tap-and-skip-controls.md +6 -0
  169. package/corpus/templates/clips/changelog/2026-07-08-recordings-and-uploads-copy-links-after-saving.md +6 -0
  170. package/corpus/templates/clips/changelog/2026-07-08-settings-are-cleaner-searchable-and-collapse-s3-with-builder.md +5 -0
  171. package/corpus/templates/clips/changelog/2026-07-08-transcripts-are-more-reliable-for-longer-desktop-recordings-.md +6 -0
  172. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -0
  173. package/corpus/templates/clips/chrome-extension/src/background.ts +162 -13
  174. package/corpus/templates/clips/chrome-extension/src/content-script.ts +14 -0
  175. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +36 -0
  176. package/corpus/templates/clips/chrome-extension/src/overlay.ts +99 -25
  177. package/corpus/templates/clips/chrome-extension/src/permission.ts +63 -14
  178. package/corpus/templates/clips/chrome-extension/src/popup.ts +123 -23
  179. package/corpus/templates/content/actions/_builder-cms-read-client.ts +47 -0
  180. package/corpus/templates/content/actions/_database-source-utils.ts +33 -4
  181. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +214 -29
  182. package/corpus/templates/content/actions/attach-content-database-source.ts +3 -0
  183. package/corpus/templates/content/actions/change-content-database-source-role.ts +1 -0
  184. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +42 -32
  185. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +352 -81
  186. package/corpus/templates/content/app/components/editor/database/settings.tsx +49 -24
  187. package/corpus/templates/content/app/routes/_app.settings.tsx +19 -1
  188. package/corpus/templates/content/changelog/2026-07-07-builder-source-tag-fields-now-import-as-multi-select.md +6 -0
  189. package/corpus/templates/content/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  190. package/corpus/templates/content/shared/api.ts +3 -0
  191. package/corpus/templates/content/shared/properties.ts +42 -0
  192. package/corpus/templates/design/actions/generate-design.ts +3 -0
  193. package/corpus/templates/design/actions/get-design-system.ts +147 -1
  194. package/corpus/templates/design/app/routes/settings.tsx +16 -1
  195. package/corpus/templates/design/changelog/2026-07-08-design-generation-now-follows-hydrated-builder-design-system.md +6 -0
  196. package/corpus/templates/design/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  197. package/corpus/templates/dispatch/app/routes/settings.tsx +23 -2
  198. package/corpus/templates/dispatch/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  199. package/corpus/templates/forms/app/routes/_app.settings.tsx +16 -1
  200. package/corpus/templates/forms/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  201. package/corpus/templates/macros/app/routes/settings.tsx +16 -1
  202. package/corpus/templates/macros/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  203. package/corpus/templates/mail/app/components/settings/GmailFiltersSection.tsx +1 -1
  204. package/corpus/templates/mail/app/components/settings/SnippetsSection.tsx +1 -1
  205. package/corpus/templates/mail/app/pages/SettingsPage.tsx +123 -105
  206. package/corpus/templates/mail/changelog/2026-07-08-settings-redesigned-with-a-consistent-searchable-layout.md +5 -0
  207. package/corpus/templates/plan/app/routes/settings.tsx +23 -2
  208. package/corpus/templates/plan/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  209. package/corpus/templates/slides/actions/add-slide.ts +1 -0
  210. package/corpus/templates/slides/actions/get-design-system.ts +147 -1
  211. package/corpus/templates/slides/app/pages/Index.tsx +46 -1
  212. package/corpus/templates/slides/app/routes/settings.tsx +16 -1
  213. package/corpus/templates/slides/changelog/2026-07-08-deck-generation-now-follows-hydrated-builder-design-system-g.md +6 -0
  214. package/corpus/templates/slides/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  215. package/dist/agent/run-ownership.d.ts +6 -0
  216. package/dist/agent/run-ownership.d.ts.map +1 -1
  217. package/dist/agent/run-ownership.js +11 -1
  218. package/dist/agent/run-ownership.js.map +1 -1
  219. package/dist/changelog/parse.d.ts +7 -0
  220. package/dist/changelog/parse.d.ts.map +1 -1
  221. package/dist/changelog/parse.js +64 -0
  222. package/dist/changelog/parse.js.map +1 -1
  223. package/dist/chat-threads/schema.d.ts +445 -0
  224. package/dist/chat-threads/schema.d.ts.map +1 -0
  225. package/dist/chat-threads/schema.js +39 -0
  226. package/dist/chat-threads/schema.js.map +1 -0
  227. package/dist/chat-threads/store.d.ts +12 -0
  228. package/dist/chat-threads/store.d.ts.map +1 -1
  229. package/dist/chat-threads/store.js +99 -10
  230. package/dist/chat-threads/store.js.map +1 -1
  231. package/dist/cli/workspace-dev.d.ts.map +1 -1
  232. package/dist/cli/workspace-dev.js +20 -5
  233. package/dist/cli/workspace-dev.js.map +1 -1
  234. package/dist/client/AgentPanel.d.ts.map +1 -1
  235. package/dist/client/AgentPanel.js +35 -7
  236. package/dist/client/AgentPanel.js.map +1 -1
  237. package/dist/client/AssistantChat.d.ts.map +1 -1
  238. package/dist/client/AssistantChat.js +105 -183
  239. package/dist/client/AssistantChat.js.map +1 -1
  240. package/dist/client/analytics-session.d.ts +3 -0
  241. package/dist/client/analytics-session.d.ts.map +1 -0
  242. package/dist/client/analytics-session.js +66 -0
  243. package/dist/client/analytics-session.js.map +1 -0
  244. package/dist/client/analytics.d.ts +32 -0
  245. package/dist/client/analytics.d.ts.map +1 -1
  246. package/dist/client/analytics.js +116 -46
  247. package/dist/client/analytics.js.map +1 -1
  248. package/dist/client/chat/message-components.d.ts +2 -1
  249. package/dist/client/chat/message-components.d.ts.map +1 -1
  250. package/dist/client/chat/message-components.js +16 -6
  251. package/dist/client/chat/message-components.js.map +1 -1
  252. package/dist/client/components/ui/message-scroller.d.ts +16 -0
  253. package/dist/client/components/ui/message-scroller.d.ts.map +1 -0
  254. package/dist/client/components/ui/message-scroller.js +25 -0
  255. package/dist/client/components/ui/message-scroller.js.map +1 -0
  256. package/dist/client/conversation/AgentConversation.d.ts +1 -1
  257. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  258. package/dist/client/conversation/AgentConversation.js +3 -8
  259. package/dist/client/conversation/AgentConversation.js.map +1 -1
  260. package/dist/client/error-capture.d.ts +99 -0
  261. package/dist/client/error-capture.d.ts.map +1 -0
  262. package/dist/client/error-capture.js +437 -0
  263. package/dist/client/error-capture.js.map +1 -0
  264. package/dist/client/index.d.ts +2 -2
  265. package/dist/client/index.d.ts.map +1 -1
  266. package/dist/client/index.js +3 -1
  267. package/dist/client/index.js.map +1 -1
  268. package/dist/client/session-replay.d.ts +22 -0
  269. package/dist/client/session-replay.d.ts.map +1 -1
  270. package/dist/client/session-replay.js +45 -4
  271. package/dist/client/session-replay.js.map +1 -1
  272. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  273. package/dist/client/settings/SettingsPanel.js +100 -5
  274. package/dist/client/settings/SettingsPanel.js.map +1 -1
  275. package/dist/client/settings/SettingsTabsPage.d.ts +49 -1
  276. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  277. package/dist/client/settings/SettingsTabsPage.js +131 -19
  278. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  279. package/dist/client/settings/index.d.ts +1 -1
  280. package/dist/client/settings/index.d.ts.map +1 -1
  281. package/dist/client/settings/index.js.map +1 -1
  282. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  283. package/dist/client/sharing/ShareButton.js +13 -8
  284. package/dist/client/sharing/ShareButton.js.map +1 -1
  285. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  286. package/dist/client/sharing/ShareDialog.js +12 -7
  287. package/dist/client/sharing/ShareDialog.js.map +1 -1
  288. package/dist/collab/struct-routes.d.ts +1 -1
  289. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  290. package/dist/mcp/builtin-tools.js +21 -2
  291. package/dist/mcp/builtin-tools.js.map +1 -1
  292. package/dist/notifications/routes.d.ts +1 -1
  293. package/dist/org/schema.d.ts +15 -15
  294. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  295. package/dist/resources/handlers.d.ts +3 -3
  296. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  297. package/dist/server/agent-chat-plugin.js +109 -73
  298. package/dist/server/agent-chat-plugin.js.map +1 -1
  299. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  300. package/dist/server/onboarding-html.d.ts.map +1 -1
  301. package/dist/server/onboarding-html.js +28 -16
  302. package/dist/server/onboarding-html.js.map +1 -1
  303. package/dist/sharing/actions/list-resource-shares.js +30 -1
  304. package/dist/sharing/actions/list-resource-shares.js.map +1 -1
  305. package/dist/sharing/actions/share-resource.js +6 -0
  306. package/dist/sharing/actions/share-resource.js.map +1 -1
  307. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  308. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +9 -6
  309. package/dist/vite/client.d.ts.map +1 -1
  310. package/dist/vite/client.js +192 -30
  311. package/dist/vite/client.js.map +1 -1
  312. package/docs/content/toolkit-settings.mdx +56 -3
  313. package/package.json +2 -1
  314. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -2
  315. 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
- if (typeof window === "undefined") return undefined;
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
- if (typeof window === "undefined") return undefined;
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
- message.content
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
- false;
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
- <div
76
- ref={scrollRef}
77
- className={cn("agent-conversation__timeline", timelineClassName)}
78
- >
79
- {loading && messages.length === 0 ? (
80
- <ConversationEmpty
81
- icon={<IconLoader2 size={17} className="agent-conversation-spin" />}
82
- title="Loading session..."
83
- />
84
- ) : messages.length === 0 ? (
85
- <ConversationEmpty
86
- icon={<IconClock size={18} />}
87
- title={emptyTitle}
88
- description={emptyDescription}
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
- messages.map((message) => (
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
  );