@agent-native/core 0.108.0 → 0.109.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +25 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/client.ts +162 -17
  5. package/corpus/core/src/a2a/correlation.ts +50 -0
  6. package/corpus/core/src/a2a/handlers.ts +200 -14
  7. package/corpus/core/src/a2a/index.ts +7 -1
  8. package/corpus/core/src/a2a/invoke.ts +77 -1
  9. package/corpus/core/src/a2a/server.ts +13 -1
  10. package/corpus/core/src/a2a/task-store.ts +146 -6
  11. package/corpus/core/src/a2a/types.ts +32 -0
  12. package/corpus/core/src/action.ts +5 -2
  13. package/corpus/core/src/agent/production-agent.ts +33 -4
  14. package/corpus/core/src/client/AssistantChat.tsx +648 -603
  15. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -4
  16. package/corpus/core/src/client/agent-chat-adapter.ts +23 -37
  17. package/corpus/core/src/client/agent-sidebar-state.ts +4 -0
  18. package/corpus/core/src/client/analytics.ts +84 -0
  19. package/corpus/core/src/client/chat/message-components.tsx +94 -22
  20. package/corpus/core/src/client/chat/tool-call-display.tsx +170 -47
  21. package/corpus/core/src/client/chat/use-agent-chat-lifecycle-tracking.ts +74 -0
  22. package/corpus/core/src/client/chat-thread-url.ts +11 -0
  23. package/corpus/core/src/client/error-capture.ts +12 -0
  24. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +37 -1
  25. package/corpus/core/src/client/index.ts +2 -0
  26. package/corpus/core/src/client/route-chunk-recovery.ts +20 -8
  27. package/corpus/core/src/client/session-replay.ts +31 -0
  28. package/corpus/core/src/client/use-run-stuck-detection.ts +27 -1
  29. package/corpus/core/src/db/client.ts +55 -0
  30. package/corpus/core/src/extensions/actions.ts +2 -14
  31. package/corpus/core/src/extensions/store.ts +1 -1
  32. package/corpus/core/src/localization/default-messages.ts +3 -0
  33. package/corpus/core/src/mcp/build-server.ts +2 -2
  34. package/corpus/core/src/observability/traces.ts +172 -19
  35. package/corpus/core/src/progress/actions.ts +4 -2
  36. package/corpus/core/src/provider-api/index.ts +205 -105
  37. package/corpus/core/src/scripts/call-agent.ts +190 -19
  38. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +112 -25
  39. package/corpus/core/src/server/agent-chat-plugin.ts +136 -4
  40. package/corpus/core/src/styles/agent-conversation.css +7 -0
  41. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +20 -0
  42. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +20 -0
  43. package/corpus/core/src/templates/default/app/i18n/en-US.ts +20 -0
  44. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +20 -0
  45. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +21 -0
  46. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +19 -0
  47. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +20 -0
  48. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +19 -0
  49. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +20 -0
  50. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +19 -0
  51. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +19 -0
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  54. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  55. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  56. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  57. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -10
  58. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +54 -23
  59. package/corpus/templates/analytics/.builder/skills/apollo/SKILL.md +19 -41
  60. package/corpus/templates/analytics/.builder/skills/commonroom/SKILL.md +20 -35
  61. package/corpus/templates/analytics/.builder/skills/github/SKILL.md +23 -67
  62. package/corpus/templates/analytics/.builder/skills/pylon/SKILL.md +25 -43
  63. package/corpus/templates/analytics/AGENTS.md +22 -13
  64. package/corpus/templates/analytics/actions/account-deep-dive.ts +1 -0
  65. package/corpus/templates/analytics/actions/configure-gong-native-insights.ts +29 -0
  66. package/corpus/templates/analytics/actions/content-calendar-schema.ts +8 -4
  67. package/corpus/templates/analytics/actions/content-calendar.ts +12 -4
  68. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -1
  69. package/corpus/templates/analytics/actions/gong-calls.ts +113 -22
  70. package/corpus/templates/analytics/actions/gong-native-insights.ts +166 -0
  71. package/corpus/templates/analytics/actions/hubspot-deals.ts +190 -46
  72. package/corpus/templates/analytics/actions/pylon-issues.ts +123 -0
  73. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  74. package/corpus/templates/analytics/actions/slack-messages.ts +179 -27
  75. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +48 -152
  76. package/corpus/templates/analytics/app/components/ui/chart.tsx +1 -1
  77. package/corpus/templates/analytics/app/hooks/use-chart-tooltip-flip.ts +21 -6
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +13 -0
  79. package/corpus/templates/analytics/app/i18n-data.ts +134 -0
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +181 -30
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +6 -0
  82. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +4 -3
  83. package/corpus/templates/analytics/changelog/2026-07-17-analytics-now-includes-a-default-alert-for-spikes-in-stuck-agent-chats.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-editors-can-add-shared-extensions-or-opt-into-per-.md +6 -0
  85. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extensions-show-a-loading-skeleton.md +6 -0
  86. package/corpus/templates/analytics/changelog/2026-07-17-errors-now-group-repeat-failures-consistently-and-keep-priva.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-17-gong-transcript-reviews-now-batch-bounded-call-windows-for-f.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-17-hubspot-deal-filters-now-run-in-hubspot-before-paging-result.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-17-notion-content-calendars-now-discover-the-matching-database-.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-17-pylon-dashboard-reads-now-use-the-paginated-issue-search-api.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-17-slack-reads-no-longer-join-channels-and-report-pagination-coverage.md +6 -0
  92. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +23 -14
  93. package/corpus/templates/analytics/docs/schemas/tracked-events.md +5 -1
  94. package/corpus/templates/analytics/server/handlers/notion.ts +14 -3
  95. package/corpus/templates/analytics/server/handlers/slack.ts +182 -29
  96. package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +3 -3
  97. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +2 -6
  98. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +209 -87
  99. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +6 -2
  100. package/corpus/templates/analytics/server/lib/error-capture.ts +75 -8
  101. package/corpus/templates/analytics/server/lib/gong-native-policy.ts +72 -0
  102. package/corpus/templates/analytics/server/lib/gong.ts +54 -66
  103. package/corpus/templates/analytics/server/lib/hubspot.ts +40 -3
  104. package/corpus/templates/analytics/server/lib/notion.ts +83 -8
  105. package/corpus/templates/analytics/server/lib/real-data-actions.ts +4 -0
  106. package/corpus/templates/analytics/server/lib/slack.ts +242 -90
  107. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -3
  108. package/corpus/templates/analytics/server/routes/api/pylon/accounts.get.ts +42 -1
  109. package/corpus/templates/analytics/server/routes/api/pylon/issues.get.ts +71 -1
  110. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +44 -4
  111. package/corpus/templates/clips/actions/finalize-recording.ts +541 -62
  112. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +19 -1
  113. package/corpus/templates/clips/app/components/library/create-folder-dialog.tsx +123 -0
  114. package/corpus/templates/clips/app/components/library/library-grid.tsx +42 -4
  115. package/corpus/templates/clips/app/components/library/recording-card.tsx +30 -0
  116. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +17 -2
  117. package/corpus/templates/clips/app/components/player/video-player.tsx +14 -2
  118. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +2 -2
  119. package/corpus/templates/clips/app/entry.client.tsx +6 -1
  120. package/corpus/templates/clips/app/i18n/ar-SA.ts +12 -1
  121. package/corpus/templates/clips/app/i18n/de-DE.ts +12 -1
  122. package/corpus/templates/clips/app/i18n/en-US.ts +12 -1
  123. package/corpus/templates/clips/app/i18n/es-ES.ts +11 -1
  124. package/corpus/templates/clips/app/i18n/fr-FR.ts +11 -1
  125. package/corpus/templates/clips/app/i18n/hi-IN.ts +10 -1
  126. package/corpus/templates/clips/app/i18n/ja-JP.ts +12 -1
  127. package/corpus/templates/clips/app/i18n/ko-KR.ts +11 -1
  128. package/corpus/templates/clips/app/i18n/pt-BR.ts +11 -1
  129. package/corpus/templates/clips/app/i18n/zh-CN.ts +11 -1
  130. package/corpus/templates/clips/app/i18n/zh-TW.ts +11 -1
  131. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +72 -1
  132. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
  133. package/corpus/templates/clips/app/routes/record.tsx +3 -3
  134. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -3
  135. package/corpus/templates/clips/changelog/2026-07-17-choose-which-workspace-receives-new-clips-recordings-and-des.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-17-clips-now-retries-storage-verification-in-the-background-ins.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-17-create-folders-directly-from-the-move-menu.md +6 -0
  138. package/corpus/templates/clips/changelog/2026-07-17-failed-desktop-uploads-now-offer-a-direct-way-to-reopen-clip.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-07-17-fixed-broken-thumbnail-icons-appearing-over-playable-clip-em.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-07-17-playback-comments-stay-readable-at-faster-playback-speeds.md +6 -0
  141. package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +3 -0
  142. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +3 -3
  143. package/corpus/templates/clips/desktop/src/app.tsx +19 -7
  144. package/corpus/templates/clips/desktop/src/lib/recorder.ts +111 -13
  145. package/corpus/templates/clips/desktop/src/lib/upload-verification.ts +16 -7
  146. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -4
  147. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +32 -15
  148. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +45 -18
  149. package/corpus/templates/clips/server/jobs/media-verification.ts +130 -0
  150. package/corpus/templates/clips/server/lib/builder-media-compression.ts +15 -0
  151. package/corpus/templates/clips/server/lib/media-verification-state.ts +38 -0
  152. package/corpus/templates/clips/server/lib/player-thumbnail-url.ts +31 -0
  153. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +10 -3
  154. package/corpus/templates/clips/server/plugins/auth.ts +5 -5
  155. package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
  156. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +12 -2
  157. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +6 -1
  158. package/corpus/templates/clips/server/routes/api/thumbnail/[recordingId].get.ts +340 -0
  159. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +24 -7
  160. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +91 -7
  161. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +14 -0
  162. package/corpus/templates/clips/shared/finalize-recovery.ts +61 -2
  163. package/corpus/templates/clips/shared/share-meta.ts +1 -1
  164. package/corpus/templates/content/app/entry.client.tsx +6 -1
  165. package/corpus/templates/dispatch/AGENTS.md +5 -0
  166. package/corpus/templates/dispatch/changelog/2026-07-17-apps-page-links-to-other-available-apps.md +6 -0
  167. package/corpus/templates/dispatch/changelog/2026-07-17-curated-template-remixes.md +6 -0
  168. package/corpus/templates/mail/app/entry.client.tsx +6 -1
  169. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +11 -7
  170. package/corpus/templates/slides/.env.example +0 -1
  171. package/corpus/templates/slides/AGENTS.md +4 -0
  172. package/corpus/templates/slides/DEVELOPING.md +2 -2
  173. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
  174. package/corpus/templates/slides/actions/logo-config.ts +6 -7
  175. package/corpus/templates/slides/actions/search-images.ts +11 -39
  176. package/corpus/templates/slides/actions/search-logos.ts +5 -52
  177. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +1 -1
  178. package/corpus/templates/slides/app/components/editor/LogoSearchPanel.tsx +16 -26
  179. package/corpus/templates/slides/app/entry.client.tsx +6 -1
  180. package/corpus/templates/slides/server/lib/media-search-providers.ts +216 -0
  181. package/corpus/templates/slides/server/register-secrets.ts +30 -0
  182. package/dist/a2a/client.d.ts +47 -1
  183. package/dist/a2a/client.d.ts.map +1 -1
  184. package/dist/a2a/client.js +94 -12
  185. package/dist/a2a/client.js.map +1 -1
  186. package/dist/a2a/correlation.d.ts +10 -0
  187. package/dist/a2a/correlation.d.ts.map +1 -0
  188. package/dist/a2a/correlation.js +40 -0
  189. package/dist/a2a/correlation.js.map +1 -0
  190. package/dist/a2a/handlers.d.ts.map +1 -1
  191. package/dist/a2a/handlers.js +147 -15
  192. package/dist/a2a/handlers.js.map +1 -1
  193. package/dist/a2a/index.d.ts +4 -4
  194. package/dist/a2a/index.d.ts.map +1 -1
  195. package/dist/a2a/index.js +2 -2
  196. package/dist/a2a/index.js.map +1 -1
  197. package/dist/a2a/invoke.d.ts +29 -2
  198. package/dist/a2a/invoke.d.ts.map +1 -1
  199. package/dist/a2a/invoke.js +33 -1
  200. package/dist/a2a/invoke.js.map +1 -1
  201. package/dist/a2a/server.d.ts.map +1 -1
  202. package/dist/a2a/server.js +14 -1
  203. package/dist/a2a/server.js.map +1 -1
  204. package/dist/a2a/task-store.d.ts +12 -1
  205. package/dist/a2a/task-store.d.ts.map +1 -1
  206. package/dist/a2a/task-store.js +96 -6
  207. package/dist/a2a/task-store.js.map +1 -1
  208. package/dist/a2a/types.d.ts +27 -0
  209. package/dist/a2a/types.d.ts.map +1 -1
  210. package/dist/a2a/types.js.map +1 -1
  211. package/dist/action.d.ts +5 -2
  212. package/dist/action.d.ts.map +1 -1
  213. package/dist/action.js.map +1 -1
  214. package/dist/agent/production-agent.d.ts +14 -0
  215. package/dist/agent/production-agent.d.ts.map +1 -1
  216. package/dist/agent/production-agent.js +19 -3
  217. package/dist/agent/production-agent.js.map +1 -1
  218. package/dist/client/AssistantChat.d.ts +14 -1
  219. package/dist/client/AssistantChat.d.ts.map +1 -1
  220. package/dist/client/AssistantChat.js +158 -136
  221. package/dist/client/AssistantChat.js.map +1 -1
  222. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  223. package/dist/client/MultiTabAssistantChat.js +27 -4
  224. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  225. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  226. package/dist/client/agent-chat-adapter.js +21 -39
  227. package/dist/client/agent-chat-adapter.js.map +1 -1
  228. package/dist/client/agent-sidebar-state.d.ts +1 -0
  229. package/dist/client/agent-sidebar-state.d.ts.map +1 -1
  230. package/dist/client/agent-sidebar-state.js +4 -0
  231. package/dist/client/agent-sidebar-state.js.map +1 -1
  232. package/dist/client/analytics.d.ts +14 -0
  233. package/dist/client/analytics.d.ts.map +1 -1
  234. package/dist/client/analytics.js +67 -0
  235. package/dist/client/analytics.js.map +1 -1
  236. package/dist/client/chat/message-components.d.ts +8 -0
  237. package/dist/client/chat/message-components.d.ts.map +1 -1
  238. package/dist/client/chat/message-components.js +62 -19
  239. package/dist/client/chat/message-components.js.map +1 -1
  240. package/dist/client/chat/tool-call-display.d.ts +6 -0
  241. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  242. package/dist/client/chat/tool-call-display.js +83 -14
  243. package/dist/client/chat/tool-call-display.js.map +1 -1
  244. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts +8 -0
  245. package/dist/client/chat/use-agent-chat-lifecycle-tracking.d.ts.map +1 -0
  246. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js +51 -0
  247. package/dist/client/chat/use-agent-chat-lifecycle-tracking.js.map +1 -0
  248. package/dist/client/chat-thread-url.d.ts +2 -0
  249. package/dist/client/chat-thread-url.d.ts.map +1 -0
  250. package/dist/client/chat-thread-url.js +12 -0
  251. package/dist/client/chat-thread-url.js.map +1 -0
  252. package/dist/client/error-capture.d.ts.map +1 -1
  253. package/dist/client/error-capture.js +7 -0
  254. package/dist/client/error-capture.js.map +1 -1
  255. package/dist/client/extensions/ExtensionSlot.d.ts +3 -1
  256. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  257. package/dist/client/extensions/ExtensionSlot.js +28 -3
  258. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  259. package/dist/client/index.d.ts +1 -1
  260. package/dist/client/index.d.ts.map +1 -1
  261. package/dist/client/index.js +1 -1
  262. package/dist/client/index.js.map +1 -1
  263. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  264. package/dist/client/route-chunk-recovery.js +14 -9
  265. package/dist/client/route-chunk-recovery.js.map +1 -1
  266. package/dist/client/session-replay.d.ts +15 -0
  267. package/dist/client/session-replay.d.ts.map +1 -1
  268. package/dist/client/session-replay.js +20 -0
  269. package/dist/client/session-replay.js.map +1 -1
  270. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  271. package/dist/client/use-run-stuck-detection.js +25 -1
  272. package/dist/client/use-run-stuck-detection.js.map +1 -1
  273. package/dist/db/client.d.ts +7 -0
  274. package/dist/db/client.d.ts.map +1 -1
  275. package/dist/db/client.js +33 -0
  276. package/dist/db/client.js.map +1 -1
  277. package/dist/extensions/actions.d.ts.map +1 -1
  278. package/dist/extensions/actions.js +2 -10
  279. package/dist/extensions/actions.js.map +1 -1
  280. package/dist/extensions/store.js +1 -1
  281. package/dist/extensions/store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +3 -0
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +3 -0
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp/build-server.d.ts +2 -0
  287. package/dist/mcp/build-server.d.ts.map +1 -1
  288. package/dist/mcp/build-server.js +2 -2
  289. package/dist/mcp/build-server.js.map +1 -1
  290. package/dist/notifications/routes.d.ts +2 -2
  291. package/dist/observability/routes.d.ts +5 -5
  292. package/dist/observability/traces.d.ts +9 -0
  293. package/dist/observability/traces.d.ts.map +1 -1
  294. package/dist/observability/traces.js +137 -19
  295. package/dist/observability/traces.js.map +1 -1
  296. package/dist/progress/actions.d.ts.map +1 -1
  297. package/dist/progress/actions.js +3 -2
  298. package/dist/progress/actions.js.map +1 -1
  299. package/dist/progress/routes.d.ts +1 -1
  300. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  301. package/dist/provider-api/index.d.ts.map +1 -1
  302. package/dist/provider-api/index.js +91 -8
  303. package/dist/provider-api/index.js.map +1 -1
  304. package/dist/scripts/call-agent.d.ts.map +1 -1
  305. package/dist/scripts/call-agent.js +140 -17
  306. package/dist/scripts/call-agent.js.map +1 -1
  307. package/dist/secrets/routes.d.ts +9 -9
  308. package/dist/server/agent-chat/action-filters-a2a.d.ts +24 -2
  309. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  310. package/dist/server/agent-chat/action-filters-a2a.js +62 -7
  311. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  312. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  313. package/dist/server/agent-chat-plugin.js +118 -5
  314. package/dist/server/agent-chat-plugin.js.map +1 -1
  315. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  316. package/dist/server/transcribe-voice.d.ts +1 -1
  317. package/dist/styles/agent-conversation.css +7 -0
  318. package/dist/templates/default/app/i18n/ar-SA.ts +20 -0
  319. package/dist/templates/default/app/i18n/de-DE.ts +20 -0
  320. package/dist/templates/default/app/i18n/en-US.ts +20 -0
  321. package/dist/templates/default/app/i18n/es-ES.ts +20 -0
  322. package/dist/templates/default/app/i18n/fr-FR.ts +21 -0
  323. package/dist/templates/default/app/i18n/hi-IN.ts +19 -0
  324. package/dist/templates/default/app/i18n/ja-JP.ts +20 -0
  325. package/dist/templates/default/app/i18n/ko-KR.ts +19 -0
  326. package/dist/templates/default/app/i18n/pt-BR.ts +20 -0
  327. package/dist/templates/default/app/i18n/zh-CN.ts +19 -0
  328. package/dist/templates/default/app/i18n/zh-TW.ts +19 -0
  329. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  330. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  331. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  332. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  333. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  334. package/package.json +1 -1
  335. package/src/templates/default/app/i18n/ar-SA.ts +20 -0
  336. package/src/templates/default/app/i18n/de-DE.ts +20 -0
  337. package/src/templates/default/app/i18n/en-US.ts +20 -0
  338. package/src/templates/default/app/i18n/es-ES.ts +20 -0
  339. package/src/templates/default/app/i18n/fr-FR.ts +21 -0
  340. package/src/templates/default/app/i18n/hi-IN.ts +19 -0
  341. package/src/templates/default/app/i18n/ja-JP.ts +20 -0
  342. package/src/templates/default/app/i18n/ko-KR.ts +19 -0
  343. package/src/templates/default/app/i18n/pt-BR.ts +20 -0
  344. package/src/templates/default/app/i18n/zh-CN.ts +19 -0
  345. package/src/templates/default/app/i18n/zh-TW.ts +19 -0
  346. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +49 -0
  347. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +5 -0
  348. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +7 -1
  349. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +13 -0
  350. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -1
  351. package/corpus/templates/analytics/server/handlers/github.ts +0 -200
  352. package/corpus/templates/analytics/server/handlers/pylon.ts +0 -43
  353. package/corpus/templates/analytics/server/lib/apollo.ts +0 -167
  354. package/corpus/templates/analytics/server/lib/commonroom.ts +0 -149
  355. package/corpus/templates/analytics/server/lib/github.ts +0 -660
  356. package/corpus/templates/analytics/server/lib/mixpanel.ts +0 -156
  357. package/corpus/templates/analytics/server/lib/posthog.ts +0 -194
  358. package/corpus/templates/analytics/server/lib/pylon.ts +0 -109
  359. package/corpus/templates/analytics/server/routes/api/github/graphql.post.ts +0 -1
  360. package/corpus/templates/analytics/server/routes/api/github/issue.get.ts +0 -1
  361. package/corpus/templates/analytics/server/routes/api/github/org-prs.get.ts +0 -1
  362. package/corpus/templates/analytics/server/routes/api/github/pr.get.ts +0 -1
  363. package/corpus/templates/analytics/server/routes/api/github/prs.get.ts +0 -1
  364. package/corpus/templates/analytics/server/routes/api/github/search.get.ts +0 -1
  365. package/corpus/templates/slides/actions/fetch-logos.ts +0 -90
  366. package/corpus/templates/slides/actions/image-search.ts +0 -64
  367. package/corpus/templates/slides/actions/import-github.ts +0 -182
  368. package/corpus/templates/slides/actions/logo-lookup.ts +0 -113
@@ -63,6 +63,8 @@ import {
63
63
 
64
64
  // Exported so AssistantChatInner can provide a context value.
65
65
  export const ChatRunningContext = React.createContext(false);
66
+ export const ChatRunDurationContext = React.createContext<number | null>(null);
67
+ export const ASSISTANT_VISIBLE_TOOL_CALL_LIMIT = 3;
66
68
 
67
69
  /**
68
70
  * Human-in-the-loop approval bridge. `AssistantChatInner` provides a value that
@@ -898,6 +900,7 @@ export function ReconnectStreamMessage({
898
900
  content: ContentPart[];
899
901
  }) {
900
902
  const chatRunning = React.useContext(ChatRunningContext);
903
+ const toolSummary = getReconnectToolSummaryInfo(content);
901
904
  const latestReasoningPartIndex = content.reduce(
902
905
  (latestIndex, part, index) =>
903
906
  part.type === "reasoning" ? index : latestIndex,
@@ -908,61 +911,148 @@ export function ReconnectStreamMessage({
908
911
  const streamingReasoningPartIndex =
909
912
  content.at(-1)?.type === "reasoning" ? content.length - 1 : -1;
910
913
 
914
+ const renderPart = (part: ContentPart, i: number) => {
915
+ if (part.type === "text") {
916
+ const partStreaming = chatRunning && i === streamingTextPartIndex;
917
+ return (
918
+ <SmoothMarkdownText
919
+ key={`reconnect-text-${i}`}
920
+ text={part.text}
921
+ streaming={partStreaming}
922
+ resetKey={`reconnect-text-${i}`}
923
+ statusType={partStreaming ? "running" : "complete"}
924
+ />
925
+ );
926
+ }
927
+ if (part.type === "reasoning") {
928
+ return (
929
+ <ReasoningCell
930
+ key={`reconnect-reasoning-${i}`}
931
+ text={part.text}
932
+ isStreaming={chatRunning && i === streamingReasoningPartIndex}
933
+ resetKey={`reconnect-reasoning-${i}`}
934
+ defaultOpen={i === latestReasoningPartIndex}
935
+ collapseWhenReplaced={i < latestReasoningPartIndex}
936
+ />
937
+ );
938
+ }
939
+ return (
940
+ <ToolCallDisplay
941
+ key={`reconnect-tool-${i}`}
942
+ toolName={part.toolName}
943
+ argsText={part.argsText}
944
+ args={part.args}
945
+ result={part.result}
946
+ mcpApp={part.mcpApp}
947
+ chatUI={part.chatUI}
948
+ structuredMeta={part.structuredMeta}
949
+ isRunning={
950
+ part.result === undefined && (chatRunning || part.activity === true)
951
+ }
952
+ approval={part.approval}
953
+ repeatCount={part.repeatCount}
954
+ />
955
+ );
956
+ };
957
+
958
+ const renderedParts: React.ReactNode[] = [];
959
+ let summaryStartIndex = -1;
960
+ let summaryToolCount = 0;
961
+ const flushSummary = (endIndex: number) => {
962
+ if (summaryStartIndex < 0) return;
963
+ renderedParts.push(
964
+ <RanToolsSummary
965
+ key={`reconnect-tool-summary-${summaryStartIndex}`}
966
+ toolCount={summaryToolCount}
967
+ >
968
+ {content
969
+ .slice(summaryStartIndex, endIndex)
970
+ .map((part, offset) => renderPart(part, summaryStartIndex + offset))}
971
+ </RanToolsSummary>,
972
+ );
973
+ summaryStartIndex = -1;
974
+ summaryToolCount = 0;
975
+ };
976
+
977
+ for (let i = 0; i < content.length; i++) {
978
+ const part = content[i]!;
979
+ const isOlderToolWork =
980
+ toolSummary.startIndex >= 0 &&
981
+ i < toolSummary.startIndex &&
982
+ isReconnectToolSummaryPart(content, i, toolSummary.startIndex);
983
+ if (isOlderToolWork) {
984
+ summaryStartIndex = summaryStartIndex < 0 ? i : summaryStartIndex;
985
+ if (part.type === "tool-call") summaryToolCount++;
986
+ continue;
987
+ }
988
+ flushSummary(i);
989
+ renderedParts.push(renderPart(part, i));
990
+ }
991
+ flushSummary(content.length);
992
+
911
993
  return (
912
994
  <div className="flex justify-start">
913
995
  <div className="w-full max-w-[95%] text-sm leading-relaxed text-foreground space-y-1">
914
- {content.map((part, i) => {
915
- if (part.type === "text") {
916
- const partStreaming = chatRunning && i === streamingTextPartIndex;
917
- return (
918
- <SmoothMarkdownText
919
- key={`reconnect-text-${i}`}
920
- text={part.text}
921
- streaming={partStreaming}
922
- resetKey={`reconnect-text-${i}`}
923
- statusType={partStreaming ? "running" : "complete"}
924
- />
925
- );
926
- }
927
- if (part.type === "reasoning") {
928
- return (
929
- <ReasoningCell
930
- key={`reconnect-reasoning-${i}`}
931
- text={part.text}
932
- isStreaming={chatRunning && i === streamingReasoningPartIndex}
933
- resetKey={`reconnect-reasoning-${i}`}
934
- defaultOpen={i === latestReasoningPartIndex}
935
- collapseWhenReplaced={i < latestReasoningPartIndex}
936
- />
937
- );
938
- }
939
- if (part.type === "tool-call") {
940
- return (
941
- <ToolCallDisplay
942
- key={`reconnect-tool-${i}`}
943
- toolName={part.toolName}
944
- argsText={part.argsText}
945
- args={part.args}
946
- result={part.result}
947
- mcpApp={part.mcpApp}
948
- chatUI={part.chatUI}
949
- structuredMeta={part.structuredMeta}
950
- isRunning={
951
- part.result === undefined &&
952
- (chatRunning || part.activity === true)
953
- }
954
- approval={part.approval}
955
- repeatCount={part.repeatCount}
956
- />
957
- );
958
- }
959
- return null;
960
- })}
996
+ {renderedParts}
961
997
  </div>
962
998
  </div>
963
999
  );
964
1000
  }
965
1001
 
1002
+ function getReconnectToolSummaryInfo(content: readonly ContentPart[]) {
1003
+ const toolCallIndices = content.reduce<number[]>((indices, part, index) => {
1004
+ if (part.type === "tool-call" && isReconnectSummarizablePart(part)) {
1005
+ indices.push(index);
1006
+ }
1007
+ return indices;
1008
+ }, []);
1009
+ if (toolCallIndices.length <= ASSISTANT_VISIBLE_TOOL_CALL_LIMIT) {
1010
+ return { startIndex: -1 };
1011
+ }
1012
+ return {
1013
+ startIndex:
1014
+ toolCallIndices[
1015
+ toolCallIndices.length - ASSISTANT_VISIBLE_TOOL_CALL_LIMIT
1016
+ ]!,
1017
+ };
1018
+ }
1019
+
1020
+ function isReconnectSummarizablePart(part: ContentPart): boolean {
1021
+ return (
1022
+ part.type === "reasoning" ||
1023
+ (part.type === "tool-call" && part.toolName !== "connect-builder")
1024
+ );
1025
+ }
1026
+
1027
+ function isReconnectToolSummaryPart(
1028
+ content: readonly ContentPart[],
1029
+ index: number,
1030
+ startIndex: number,
1031
+ ): boolean {
1032
+ if (startIndex < 0 || index >= startIndex) return false;
1033
+ if (!isReconnectSummarizablePart(content[index]!)) return false;
1034
+
1035
+ let segmentStart = index;
1036
+ while (
1037
+ segmentStart > 0 &&
1038
+ isReconnectSummarizablePart(content[segmentStart - 1]!)
1039
+ ) {
1040
+ segmentStart--;
1041
+ }
1042
+
1043
+ let segmentEnd = index + 1;
1044
+ while (
1045
+ segmentEnd < startIndex &&
1046
+ isReconnectSummarizablePart(content[segmentEnd]!)
1047
+ ) {
1048
+ segmentEnd++;
1049
+ }
1050
+
1051
+ return content
1052
+ .slice(segmentStart, segmentEnd)
1053
+ .some((candidate) => candidate.type === "tool-call");
1054
+ }
1055
+
966
1056
  // ─── Reasoning / Thinking cell ────────────────────────────────────────────────
967
1057
 
968
1058
  /**
@@ -1141,6 +1231,39 @@ export function WorkedForSummary({
1141
1231
  );
1142
1232
  }
1143
1233
 
1234
+ export function RanToolsSummary({
1235
+ toolCount,
1236
+ children,
1237
+ }: {
1238
+ toolCount: number;
1239
+ children: React.ReactNode;
1240
+ }) {
1241
+ const [open, setOpen] = useState(false);
1242
+ const label = `Ran ${toolCount} ${toolCount === 1 ? "tool" : "tools"}`;
1243
+
1244
+ return (
1245
+ <div className="my-1 w-full">
1246
+ <button
1247
+ type="button"
1248
+ onClick={() => setOpen((v) => !v)}
1249
+ aria-expanded={open}
1250
+ className="flex items-center gap-1.5 py-0.5 text-[13px] text-muted-foreground transition-colors hover:text-foreground"
1251
+ >
1252
+ <span>{label}</span>
1253
+ <IconChevronRight
1254
+ className={cn(
1255
+ "size-3.5 shrink-0 transition-transform",
1256
+ open && "rotate-90",
1257
+ )}
1258
+ />
1259
+ </button>
1260
+ <AnimatedCollapse open={open}>
1261
+ <div className="pt-1">{children}</div>
1262
+ </AnimatedCollapse>
1263
+ </div>
1264
+ );
1265
+ }
1266
+
1144
1267
  // ─── Re-export for AssistantMessage ───────────────────────────────────────────
1145
1268
  // AssistantMessage in AssistantChat.tsx uses FilesChangedSummary directly, so
1146
1269
  // re-export it so AssistantChat.tsx can import from one place.
@@ -0,0 +1,74 @@
1
+ import { useCallback, useEffect } from "react";
2
+
3
+ import {
4
+ ACTIVE_RUN_STATE_EVENT,
5
+ getActiveRun,
6
+ type ActiveRunState,
7
+ } from "../active-run-state.js";
8
+ import { trackAgentChatLifecycle } from "../analytics.js";
9
+
10
+ export interface AgentChatLifecycleTrackingOptions {
11
+ surface: string;
12
+ threadId?: string;
13
+ tabId?: string;
14
+ onActiveRunChange?: (active: boolean) => void;
15
+ }
16
+
17
+ export function useAgentChatLifecycleTracking({
18
+ surface,
19
+ threadId,
20
+ tabId,
21
+ onActiveRunChange,
22
+ }: AgentChatLifecycleTrackingOptions): (runId?: string) => void {
23
+ useEffect(() => {
24
+ trackAgentChatLifecycle({
25
+ phase: "surface-mounted",
26
+ surface,
27
+ ...(threadId ? { threadId } : {}),
28
+ ...(tabId ? { tabId } : {}),
29
+ });
30
+ }, [surface, tabId, threadId]);
31
+
32
+ useEffect(() => {
33
+ const sync = (state = getActiveRun()) => {
34
+ const active = Boolean(
35
+ threadId && state?.threadId === threadId && state.runId,
36
+ );
37
+ onActiveRunChange?.(active);
38
+ if (!active || !state) return;
39
+ trackAgentChatLifecycle({
40
+ phase: "run-observed",
41
+ surface,
42
+ threadId: state.threadId,
43
+ runId: state.runId,
44
+ ...(tabId ? { tabId } : {}),
45
+ });
46
+ };
47
+ sync();
48
+ const activeRunHandler = (event: Event) => {
49
+ const state = (event as CustomEvent<{ state?: ActiveRunState | null }>)
50
+ .detail?.state;
51
+ sync(state ?? null);
52
+ };
53
+ const storageHandler = () => sync();
54
+ window.addEventListener(ACTIVE_RUN_STATE_EVENT, activeRunHandler);
55
+ window.addEventListener("storage", storageHandler);
56
+ return () => {
57
+ window.removeEventListener(ACTIVE_RUN_STATE_EVENT, activeRunHandler);
58
+ window.removeEventListener("storage", storageHandler);
59
+ };
60
+ }, [onActiveRunChange, surface, tabId, threadId]);
61
+
62
+ return useCallback(
63
+ (runId?: string) => {
64
+ trackAgentChatLifecycle({
65
+ phase: "run-stopped",
66
+ surface,
67
+ ...(threadId ? { threadId } : {}),
68
+ ...(runId ? { runId } : {}),
69
+ ...(tabId ? { tabId } : {}),
70
+ });
71
+ },
72
+ [surface, tabId, threadId],
73
+ );
74
+ }
@@ -0,0 +1,11 @@
1
+ export function hasChatThreadDeepLink(): boolean {
2
+ if (typeof window === "undefined") return false;
3
+ try {
4
+ const params = new URLSearchParams(window.location.search);
5
+ return Boolean(
6
+ params.get("thread")?.trim() || params.get("threadId")?.trim(),
7
+ );
8
+ } catch {
9
+ return false;
10
+ }
11
+ }
@@ -355,6 +355,18 @@ function shouldIgnoreAutoCapturedError(normalized: {
355
355
  return true;
356
356
  }
357
357
 
358
+ // Route-chunk recovery reloads the current page after stale lazy chunks or
359
+ // module scripts fail. Browser-level failures have no useful stack, so do
360
+ // not retain the transient loader noise as an application issue.
361
+ if (
362
+ !stack &&
363
+ /^(?:Importing a module script failed\.?|(?:Failed to fetch|error loading) dynamically imported module(?::.*)?)$/i.test(
364
+ message,
365
+ )
366
+ ) {
367
+ return true;
368
+ }
369
+
358
370
  if (
359
371
  normalized.type === "InvalidStateError" &&
360
372
  /^Transition was aborted because of invalid state$/i.test(message)
@@ -1,6 +1,6 @@
1
1
  import { IconPlus } from "@tabler/icons-react";
2
2
  import { useQuery, useQueryClient } from "@tanstack/react-query";
3
- import { useState } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
 
5
5
  import { sendToAgentChat } from "../agent-chat.js";
6
6
  import { agentNativePath } from "../api-path.js";
@@ -49,6 +49,8 @@ export interface ExtensionSlotProps {
49
49
  className?: string;
50
50
  /** Optional className applied to each EmbeddedExtension. */
51
51
  toolClassName?: string;
52
+ /** Fires once when the slot query and all installed extensions are ready. */
53
+ onReady?: () => void;
52
54
  }
53
55
 
54
56
  /**
@@ -70,8 +72,11 @@ export function ExtensionSlot({
70
72
  showEmptyAffordance,
71
73
  className,
72
74
  toolClassName,
75
+ onReady,
73
76
  }: ExtensionSlotProps) {
74
77
  const t = useT();
78
+ const readyInstallIds = useRef(new Set<string>());
79
+ const readyNotified = useRef(false);
75
80
  const installsQuery = useQuery<SlotInstall[]>({
76
81
  queryKey: ["slot-installs", id],
77
82
  queryFn: async () => {
@@ -87,6 +92,35 @@ export function ExtensionSlot({
87
92
  });
88
93
  const installs = installsQuery.data ?? [];
89
94
 
95
+ useEffect(() => {
96
+ readyInstallIds.current.clear();
97
+ readyNotified.current = false;
98
+ }, [id]);
99
+
100
+ useEffect(() => {
101
+ if (readyNotified.current || installsQuery.isLoading) return;
102
+ if (
103
+ installsQuery.isError ||
104
+ installs.length === 0 ||
105
+ readyInstallIds.current.size >= installs.length
106
+ ) {
107
+ readyNotified.current = true;
108
+ onReady?.();
109
+ }
110
+ }, [installs, installsQuery.isError, installsQuery.isLoading, onReady]);
111
+
112
+ const markInstallReady = (installId: string) => {
113
+ readyInstallIds.current.add(installId);
114
+ if (
115
+ !readyNotified.current &&
116
+ !installsQuery.isLoading &&
117
+ readyInstallIds.current.size >= installs.length
118
+ ) {
119
+ readyNotified.current = true;
120
+ onReady?.();
121
+ }
122
+ };
123
+
90
124
  if (installsQuery.isLoading) {
91
125
  return null;
92
126
  }
@@ -121,6 +155,8 @@ export function ExtensionSlot({
121
155
  slotId={id}
122
156
  context={context}
123
157
  className={toolClassName}
158
+ onReady={() => markInstallReady(install.installId)}
159
+ onUnavailable={() => markInstallReady(install.installId)}
124
160
  />
125
161
  ))}
126
162
  </div>
@@ -787,6 +787,7 @@ export {
787
787
  export { AgentTerminal, type AgentTerminalProps } from "./terminal/index.js";
788
788
  export {
789
789
  trackEvent,
790
+ trackAgentChatLifecycle,
790
791
  trackSessionStatus,
791
792
  configureTracking,
792
793
  setTrackingContentCaptureEnabled,
@@ -811,6 +812,7 @@ export {
811
812
  type CaptureExceptionContext,
812
813
  type CapturedExceptionEvent,
813
814
  type ClientCaptureContext,
815
+ type AgentChatLifecycleEvent,
814
816
  type ConfigureTrackingOptions,
815
817
  type ErrorCaptureConfigOptions,
816
818
  type ExceptionBreadcrumb,
@@ -201,6 +201,17 @@ function recoverToIntendedNavigation(
201
201
  return true;
202
202
  }
203
203
 
204
+ function recoverFromDynamicImportFailure(
205
+ win: Window,
206
+ state: RouteChunkRecoveryState,
207
+ message: string,
208
+ ): boolean {
209
+ if (!isDynamicImportFailureMessage(message)) return false;
210
+ state.routeModuleFailureAt = Date.now();
211
+ if (recoverToIntendedNavigation(win, state)) return true;
212
+ return reloadForStaleChunk(win);
213
+ }
214
+
204
215
  function patchHistoryMethod(
205
216
  win: Window,
206
217
  state: RouteChunkRecoveryState,
@@ -290,16 +301,17 @@ export function installRouteChunkRecovery(
290
301
  win.addEventListener("unhandledrejection", (event) => {
291
302
  const reason = (event as PromiseRejectionEvent).reason;
292
303
  const message = String(reason?.message || reason || "");
293
- if (!isDynamicImportFailureMessage(message)) return;
294
- state.routeModuleFailureAt = Date.now();
295
- if (recoverToIntendedNavigation(win, state)) {
304
+ if (recoverFromDynamicImportFailure(win, state, message)) {
296
305
  event.preventDefault();
297
- return;
298
306
  }
299
- // No fresh cross-route target — the current route's own chunk went stale.
300
- // Reload once (guarded) to fetch fresh assets instead of leaving the user
301
- // on a broken view.
302
- if (reloadForStaleChunk(win)) {
307
+ });
308
+
309
+ win.addEventListener("error", (event) => {
310
+ const errorEvent = event as ErrorEvent;
311
+ const message = String(
312
+ errorEvent.error?.message || errorEvent.message || "",
313
+ );
314
+ if (recoverFromDynamicImportFailure(win, state, message)) {
303
315
  event.preventDefault();
304
316
  }
305
317
  });
@@ -390,6 +390,8 @@ const SESSION_REPLAY_CLAIM_TIMEOUT_MS = 150;
390
390
  export const SESSION_REPLAY_CONSOLE_EVENT_TAG = "agent-native.console";
391
391
  /** rrweb custom-event tag for captured fetch/XHR request summaries. */
392
392
  export const SESSION_REPLAY_NETWORK_EVENT_TAG = "agent-native.network";
393
+ /** Content-free agent-chat lifecycle markers for replay incident forensics. */
394
+ export const SESSION_REPLAY_AGENT_CHAT_EVENT_TAG = "agent-native.chat";
393
395
 
394
396
  const DEFAULT_MAX_CONSOLE_EVENTS = 1000;
395
397
  const DEFAULT_MAX_NETWORK_EVENTS = 2000;
@@ -3384,3 +3386,32 @@ export function emitSessionReplayException(input: {
3384
3386
  ...(input.url ? { url: input.url } : {}),
3385
3387
  });
3386
3388
  }
3389
+
3390
+ export type SessionReplayAgentChatEvent = {
3391
+ phase: "surface-mounted" | "run-observed" | "run-stopped";
3392
+ surface: string;
3393
+ threadId?: string;
3394
+ runId?: string;
3395
+ tabId?: string;
3396
+ };
3397
+
3398
+ /**
3399
+ * Add a content-free chat lifecycle marker to the active replay. The payload
3400
+ * deliberately accepts only ids and low-cardinality state; prompt/response
3401
+ * content must never enter replay diagnostics through this path.
3402
+ */
3403
+ export function emitSessionReplayAgentChatEvent(
3404
+ input: SessionReplayAgentChatEvent,
3405
+ ): void {
3406
+ const state = getState();
3407
+ if (!state.active || !state.addCustomEvent) return;
3408
+ const bounded = (value: string | undefined, max = 160) =>
3409
+ value?.trim().slice(0, max) || undefined;
3410
+ emitReplayCustomEvent(state, SESSION_REPLAY_AGENT_CHAT_EVENT_TAG, {
3411
+ phase: input.phase,
3412
+ surface: bounded(input.surface, 80) ?? "app",
3413
+ ...(bounded(input.threadId) ? { threadId: bounded(input.threadId) } : {}),
3414
+ ...(bounded(input.runId) ? { runId: bounded(input.runId) } : {}),
3415
+ ...(bounded(input.tabId) ? { tabId: bounded(input.tabId) } : {}),
3416
+ });
3417
+ }
@@ -80,6 +80,7 @@ export const DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS = 180_000;
80
80
  export const DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS = 13 * 60_000;
81
81
  const DEFAULT_POLL_INTERVAL_MS = 5_000;
82
82
  const IDLE_BACKOFF_INTERVAL_MS = 15_000;
83
+ const MAX_POLL_ERROR_BACKOFF_MS = 30_000;
83
84
  const FRESH_BACKGROUND_HEARTBEAT_MS = 30_000;
84
85
 
85
86
  interface ActiveRunResponse {
@@ -129,6 +130,22 @@ export function useRunStuckDetection({
129
130
  let timer: ReturnType<typeof setTimeout> | null = null;
130
131
  let snapshotTransitionTimer: ReturnType<typeof setTimeout> | null = null;
131
132
  let snapshotVersion = 0;
133
+ let consecutivePollFailures = 0;
134
+
135
+ const pollFailureDelay = () => {
136
+ consecutivePollFailures += 1;
137
+ return Math.min(
138
+ Math.max(pollIntervalMs, 1) * 2 ** consecutivePollFailures,
139
+ MAX_POLL_ERROR_BACKOFF_MS,
140
+ );
141
+ };
142
+
143
+ const clearObservedRun = () => {
144
+ snapshotVersion += 1;
145
+ if (snapshotTransitionTimer) clearTimeout(snapshotTransitionTimer);
146
+ snapshotTransitionTimer = null;
147
+ setState(EMPTY_STATE);
148
+ };
132
149
 
133
150
  type RunHealthSnapshot = {
134
151
  active: boolean;
@@ -269,6 +286,7 @@ export function useRunStuckDetection({
269
286
  );
270
287
  if (cancelled) return;
271
288
  if (res.ok) {
289
+ consecutivePollFailures = 0;
272
290
  const data = (await res.json()) as ActiveRunResponse;
273
291
  const lastProgressAt = data.lastProgressAt ?? null;
274
292
  // Measure elapsed against the SERVER clock (serverNow) rather than the
@@ -336,9 +354,17 @@ export function useRunStuckDetection({
336
354
  if (!data.active || data.status !== "running") {
337
355
  nextDelay = IDLE_BACKOFF_INTERVAL_MS;
338
356
  }
357
+ } else if (res.status === 429 || res.status >= 500) {
358
+ nextDelay = pollFailureDelay();
359
+ } else {
360
+ consecutivePollFailures = 0;
361
+ clearObservedRun();
362
+ nextDelay = MAX_POLL_ERROR_BACKOFF_MS;
339
363
  }
340
364
  } catch {
341
- // Network blip — leave previous state. Next tick will retry.
365
+ // Network/503 blip — leave previous state and ease polling pressure
366
+ // while the server or database recovers.
367
+ nextDelay = pollFailureDelay();
342
368
  }
343
369
  if (!cancelled) {
344
370
  timer = setTimeout(poll, nextDelay);
@@ -669,6 +669,61 @@ export function isConnectionError(err: any): boolean {
669
669
  );
670
670
  }
671
671
 
672
+ /**
673
+ * Classify database failures that should temporarily shed request load.
674
+ * Statement timeouts are not included in isConnectionError() because retrying
675
+ * every timed-out mutation would not be safe, but request handlers can still
676
+ * return a retryable service-unavailable response for them.
677
+ */
678
+ export function isTransientDatabaseError(err: unknown): boolean {
679
+ const error = err as {
680
+ code?: unknown;
681
+ name?: unknown;
682
+ message?: unknown;
683
+ stack?: unknown;
684
+ cause?: {
685
+ code?: unknown;
686
+ name?: unknown;
687
+ message?: unknown;
688
+ stack?: unknown;
689
+ };
690
+ };
691
+ const code = String(error?.code ?? error?.cause?.code ?? "");
692
+ if (
693
+ code === "ECHECKOUTTIMEOUT" ||
694
+ code === "53300" ||
695
+ code === "57014" ||
696
+ /^08/.test(code) ||
697
+ /^57P0[123]$/.test(code)
698
+ ) {
699
+ return true;
700
+ }
701
+
702
+ const message = [error?.message, error?.cause?.message]
703
+ .filter((value): value is string => typeof value === "string")
704
+ .join(" ");
705
+ if (
706
+ /\bstatement timeout\b|\bdb (?:query|connect) timed out\b/i.test(message)
707
+ ) {
708
+ return true;
709
+ }
710
+
711
+ const databaseSurface = [
712
+ error?.name,
713
+ error?.cause?.name,
714
+ error?.stack,
715
+ error?.cause?.stack,
716
+ ]
717
+ .filter((value): value is string => typeof value === "string")
718
+ .join(" ");
719
+ return (
720
+ isConnectionError(error) &&
721
+ /@neondatabase|@libsql|\bpostgres(?:ql)?\b|\bpg-pool\b|drizzle-orm|\/db\/client\.[cm]?[jt]s/i.test(
722
+ databaseSurface,
723
+ )
724
+ );
725
+ }
726
+
672
727
  export async function retryOnConnectionError<T>(
673
728
  fn: () => Promise<T>,
674
729
  maxAttempts = 3,
@@ -727,20 +727,8 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
727
727
  !coerceBoolean(args?.allowFullReplacement)
728
728
  ) {
729
729
  const message =
730
- "Full extension-body replacement was blocked to preserve the existing visual design. Read the current extension and use focused patches/edits for a data-only repair. Only retry with allowFullReplacement=true when the user explicitly requested a broad visual rewrite or supplied a complete replacement body.";
731
- throw new AgentActionStopError(message, {
732
- errorCode: "extension_full_replacement_requires_explicit_intent",
733
- toolResult: JSON.stringify(
734
- {
735
- error: "extension_full_replacement_requires_explicit_intent",
736
- message,
737
- recoverable: false,
738
- next: "Call get-extension once, then update-extension with patches or edits that change only the data-loading code. Use allowFullReplacement=true only for an explicitly requested visual rewrite.",
739
- },
740
- null,
741
- 2,
742
- ),
743
- });
730
+ "Full extension-body replacement requires allowFullReplacement=true. No changes were applied. If the user's request includes a broad visual rewrite such as changing layout, compactness, visible sections, naming, or padding, retry once with allowFullReplacement=true; otherwise read the current extension and use focused patches/edits for a data-only repair. Do not retry unchanged arguments.";
731
+ throw new ExtensionContentEditError(message);
744
732
  }
745
733
 
746
734
  // Full-replacement content can come inline (`content`) or by reference
@@ -1192,7 +1192,7 @@ export async function updateExtensionContent(
1192
1192
 
1193
1193
  if (opts.content !== undefined && opts.allowFullReplacement !== true) {
1194
1194
  throw new ExtensionContentEditError(
1195
- "Full extension-body replacement requires explicit allowFullReplacement=true. Use patches or edits for a targeted data-only repair so the existing design is preserved.",
1195
+ "Full extension-body replacement requires allowFullReplacement=true. No changes were applied. Use patches or edits for a targeted data-only repair, or set allowFullReplacement=true for a user-requested broad visual rewrite.",
1196
1196
  );
1197
1197
  }
1198
1198