@agent-native/core 0.98.4 → 0.98.6

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 (314) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +28 -0
  3. package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
  4. package/corpus/core/docs/content/external-agents.mdx +62 -7
  5. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +38 -7
  6. package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
  7. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +39 -7
  8. package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
  9. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +39 -7
  10. package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
  11. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +39 -7
  12. package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
  13. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +38 -7
  14. package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
  15. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +38 -7
  16. package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
  17. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +38 -7
  18. package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
  19. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +39 -7
  20. package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
  21. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +37 -7
  22. package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +2 -0
  23. package/corpus/core/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
  24. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +37 -7
  25. package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +2 -0
  26. package/corpus/core/docs/content/tracking.mdx +2 -0
  27. package/corpus/core/package.json +1 -1
  28. package/corpus/core/src/a2a/handlers.ts +95 -21
  29. package/corpus/core/src/a2a/task-store.ts +65 -3
  30. package/corpus/core/src/agent/durable-background.ts +16 -16
  31. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +25 -8
  32. package/corpus/core/src/agent/engine/anthropic-engine.ts +17 -3
  33. package/corpus/core/src/agent/engine/output-tokens.ts +6 -6
  34. package/corpus/core/src/agent/production-agent.ts +200 -27
  35. package/corpus/core/src/agent/run-manager.ts +81 -1
  36. package/corpus/core/src/agent/run-store.ts +301 -41
  37. package/corpus/core/src/client/AgentPanel.tsx +6 -2
  38. package/corpus/core/src/client/AssistantChat.tsx +364 -69
  39. package/corpus/core/src/client/agent-chat-adapter.ts +169 -1
  40. package/corpus/core/src/client/chat/message-components.tsx +3 -0
  41. package/corpus/core/src/client/chat/tool-call-display.tsx +20 -36
  42. package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +7 -0
  43. package/corpus/core/src/client/extensions/AgentNativeExtensionFrame.tsx +2 -0
  44. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +2 -0
  45. package/corpus/core/src/client/extensions/ExtensionEditor.tsx +9 -2
  46. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +2 -0
  47. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +2 -0
  48. package/corpus/core/src/client/extensions/portable-extension.ts +2 -0
  49. package/corpus/core/src/client/session-replay.ts +361 -29
  50. package/corpus/core/src/client/sse-event-processor.ts +43 -1
  51. package/corpus/core/src/demo/actions/toggle-demo-mode.ts +1 -1
  52. package/corpus/core/src/demo/config.ts +6 -6
  53. package/corpus/core/src/demo/fetch-interceptor.ts +13 -4
  54. package/corpus/core/src/demo/redact.ts +13 -149
  55. package/corpus/core/src/extensions/html-shell.ts +3 -0
  56. package/corpus/core/src/extensions/session-replay-iframe.ts +131 -0
  57. package/corpus/core/src/integrations/adapters/slack.ts +123 -13
  58. package/corpus/core/src/integrations/identity-links-store.ts +210 -0
  59. package/corpus/core/src/integrations/identity.ts +132 -0
  60. package/corpus/core/src/integrations/index.ts +6 -0
  61. package/corpus/core/src/integrations/plugin.ts +58 -1
  62. package/corpus/core/src/integrations/types.ts +7 -0
  63. package/corpus/core/src/mcp/build-server.ts +127 -22
  64. package/corpus/core/src/mcp/external-agent-policy.ts +18 -0
  65. package/corpus/core/src/mcp/index.ts +1 -0
  66. package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
  67. package/corpus/core/src/server/agent-chat/plugin-options.ts +12 -1
  68. package/corpus/core/src/server/agent-chat/script-entries.ts +20 -3
  69. package/corpus/core/src/server/agent-chat-plugin.ts +3 -0
  70. package/corpus/core/src/session-replay-iframe-protocol.ts +58 -0
  71. package/corpus/core/src/shared/reasoning-effort.ts +35 -0
  72. package/corpus/core/src/styles/agent-conversation.css +26 -0
  73. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
  74. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  75. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +30 -21
  76. package/corpus/templates/analytics/AGENTS.md +27 -0
  77. package/corpus/templates/analytics/actions/create-session-replay-agent-link.ts +0 -1
  78. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
  79. package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
  80. package/corpus/templates/analytics/actions/get-session-replay-timeline.ts +40 -0
  81. package/corpus/templates/analytics/actions/list-error-issues.ts +13 -0
  82. package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
  83. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -0
  84. package/corpus/templates/analytics/app/global.css +2 -2
  85. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
  86. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +52 -203
  87. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +69 -16
  88. package/corpus/templates/analytics/changelog/2026-07-12-analytics-chat-retries-before-showing-a-generic-no-data-mess.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-12-analytics-sessions-search-no-longer-loses-fast-keystrokes-an.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-12-chart-selection-respects-chat-state.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-12-connected-external-agents-can-now-look-up-sessions-error-iss.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-anonymizes-error-reporting-emails.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-12-session-identities-stay-visible-when-demo-mode-is-off.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-12-session-replays-show-iframe-content.md +6 -0
  95. package/corpus/templates/analytics/netlify.toml +0 -3
  96. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +14 -0
  97. package/corpus/templates/analytics/server/lib/error-capture.ts +101 -2
  98. package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
  99. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +49 -17
  100. package/corpus/templates/analytics/server/lib/session-replay.ts +18 -16
  101. package/corpus/templates/analytics/server/plugins/agent-chat.ts +43 -6
  102. package/corpus/templates/analytics/server/plugins/db.ts +15 -0
  103. package/corpus/templates/assets/app/global.css +1 -1
  104. package/corpus/templates/brain/app/global.css +2 -2
  105. package/corpus/templates/brain/changelog/2026-07-12-fix-long-response-progress.md +6 -0
  106. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +1 -1
  107. package/corpus/templates/forms/app/components/ThemeToggle.tsx +22 -6
  108. package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +5 -5
  109. package/corpus/templates/forms/app/components/builder/FieldRenderer.tsx +3 -3
  110. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +16 -16
  111. package/corpus/templates/forms/app/global.css +164 -13
  112. package/corpus/templates/forms/app/pages/AskPage.tsx +35 -13
  113. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +143 -67
  114. package/corpus/templates/forms/app/pages/FormFillPage.tsx +44 -11
  115. package/corpus/templates/forms/app/pages/FormsListPage.tsx +42 -24
  116. package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +28 -15
  117. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +46 -20
  118. package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
  119. package/corpus/templates/forms/changelog/2026-07-12-ask-forms-suggestions-now-sit-beneath-the-composer-for-a-tig.md +6 -0
  120. package/corpus/templates/forms/changelog/2026-07-12-builder-response-tables-now-fill-the-view-without-a-redundan.md +6 -0
  121. package/corpus/templates/forms/changelog/2026-07-12-form-builder-surfaces-are-calmer-fields-stay-stable-on-hover.md +6 -0
  122. package/corpus/templates/forms/changelog/2026-07-12-response-tables-now-fill-the-available-pane-with-a-flexible-.md +6 -0
  123. package/corpus/templates/forms/changelog/2026-07-12-smoother-more-tactile-controls-throughout-animated-icon-and-.md +6 -0
  124. package/corpus/templates/mail/AGENTS.md +3 -1
  125. package/corpus/templates/mail/app/components/email/EmailThread.tsx +21 -13
  126. package/corpus/templates/mail/app/components/email/email-iframe-document.ts +18 -0
  127. package/corpus/templates/mail/server/lib/mail-integrations.ts +3 -0
  128. package/dist/a2a/handlers.d.ts.map +1 -1
  129. package/dist/a2a/handlers.js +84 -15
  130. package/dist/a2a/handlers.js.map +1 -1
  131. package/dist/a2a/task-store.d.ts +20 -1
  132. package/dist/a2a/task-store.d.ts.map +1 -1
  133. package/dist/a2a/task-store.js +57 -4
  134. package/dist/a2a/task-store.js.map +1 -1
  135. package/dist/agent/durable-background.d.ts +10 -10
  136. package/dist/agent/durable-background.d.ts.map +1 -1
  137. package/dist/agent/durable-background.js +16 -16
  138. package/dist/agent/durable-background.js.map +1 -1
  139. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  140. package/dist/agent/engine/ai-sdk-engine.js +19 -8
  141. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  142. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  143. package/dist/agent/engine/anthropic-engine.js +11 -3
  144. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  145. package/dist/agent/engine/output-tokens.js +6 -6
  146. package/dist/agent/engine/output-tokens.js.map +1 -1
  147. package/dist/agent/production-agent.d.ts +52 -0
  148. package/dist/agent/production-agent.d.ts.map +1 -1
  149. package/dist/agent/production-agent.js +154 -26
  150. package/dist/agent/production-agent.js.map +1 -1
  151. package/dist/agent/run-manager.d.ts +9 -0
  152. package/dist/agent/run-manager.d.ts.map +1 -1
  153. package/dist/agent/run-manager.js +71 -1
  154. package/dist/agent/run-manager.js.map +1 -1
  155. package/dist/agent/run-store.d.ts +9 -0
  156. package/dist/agent/run-store.d.ts.map +1 -1
  157. package/dist/agent/run-store.js +243 -48
  158. package/dist/agent/run-store.js.map +1 -1
  159. package/dist/client/AgentPanel.d.ts.map +1 -1
  160. package/dist/client/AgentPanel.js +6 -2
  161. package/dist/client/AgentPanel.js.map +1 -1
  162. package/dist/client/AssistantChat.d.ts +21 -0
  163. package/dist/client/AssistantChat.d.ts.map +1 -1
  164. package/dist/client/AssistantChat.js +298 -67
  165. package/dist/client/AssistantChat.js.map +1 -1
  166. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  167. package/dist/client/agent-chat-adapter.js +146 -1
  168. package/dist/client/agent-chat-adapter.js.map +1 -1
  169. package/dist/client/chat/message-components.d.ts.map +1 -1
  170. package/dist/client/chat/message-components.js +2 -1
  171. package/dist/client/chat/message-components.js.map +1 -1
  172. package/dist/client/chat/tool-call-display.d.ts +3 -1
  173. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  174. package/dist/client/chat/tool-call-display.js +13 -37
  175. package/dist/client/chat/tool-call-display.js.map +1 -1
  176. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -0
  177. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
  178. package/dist/client/conversation/use-near-bottom-autoscroll.js +6 -0
  179. package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
  180. package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
  181. package/dist/client/extensions/AgentNativeExtensionFrame.js +2 -1
  182. package/dist/client/extensions/AgentNativeExtensionFrame.js.map +1 -1
  183. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  184. package/dist/client/extensions/EmbeddedExtension.js +2 -1
  185. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  186. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  187. package/dist/client/extensions/ExtensionEditor.js +5 -2
  188. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  189. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  190. package/dist/client/extensions/ExtensionViewer.js +2 -1
  191. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  192. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
  193. package/dist/client/extensions/InlineExtensionFrame.js +2 -1
  194. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
  195. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  196. package/dist/client/extensions/portable-extension.js +2 -0
  197. package/dist/client/extensions/portable-extension.js.map +1 -1
  198. package/dist/client/session-replay.d.ts.map +1 -1
  199. package/dist/client/session-replay.js +308 -29
  200. package/dist/client/session-replay.js.map +1 -1
  201. package/dist/client/sse-event-processor.d.ts +5 -0
  202. package/dist/client/sse-event-processor.d.ts.map +1 -1
  203. package/dist/client/sse-event-processor.js +37 -1
  204. package/dist/client/sse-event-processor.js.map +1 -1
  205. package/dist/collab/routes.d.ts +1 -1
  206. package/dist/demo/actions/toggle-demo-mode.js +1 -1
  207. package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
  208. package/dist/demo/config.js +6 -6
  209. package/dist/demo/config.js.map +1 -1
  210. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  211. package/dist/demo/fetch-interceptor.js +13 -4
  212. package/dist/demo/fetch-interceptor.js.map +1 -1
  213. package/dist/demo/redact.d.ts +7 -7
  214. package/dist/demo/redact.d.ts.map +1 -1
  215. package/dist/demo/redact.js +8 -145
  216. package/dist/demo/redact.js.map +1 -1
  217. package/dist/extensions/html-shell.d.ts.map +1 -1
  218. package/dist/extensions/html-shell.js +2 -0
  219. package/dist/extensions/html-shell.js.map +1 -1
  220. package/dist/extensions/session-replay-iframe.d.ts +10 -0
  221. package/dist/extensions/session-replay-iframe.d.ts.map +1 -0
  222. package/dist/extensions/session-replay-iframe.js +121 -0
  223. package/dist/extensions/session-replay-iframe.js.map +1 -0
  224. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  225. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  226. package/dist/integrations/adapters/slack.js +98 -13
  227. package/dist/integrations/adapters/slack.js.map +1 -1
  228. package/dist/integrations/identity-links-store.d.ts +23 -0
  229. package/dist/integrations/identity-links-store.d.ts.map +1 -0
  230. package/dist/integrations/identity-links-store.js +158 -0
  231. package/dist/integrations/identity-links-store.js.map +1 -0
  232. package/dist/integrations/identity.d.ts +11 -0
  233. package/dist/integrations/identity.d.ts.map +1 -0
  234. package/dist/integrations/identity.js +100 -0
  235. package/dist/integrations/identity.js.map +1 -0
  236. package/dist/integrations/index.d.ts +2 -0
  237. package/dist/integrations/index.d.ts.map +1 -1
  238. package/dist/integrations/index.js +2 -0
  239. package/dist/integrations/index.js.map +1 -1
  240. package/dist/integrations/plugin.d.ts.map +1 -1
  241. package/dist/integrations/plugin.js +43 -1
  242. package/dist/integrations/plugin.js.map +1 -1
  243. package/dist/integrations/types.d.ts +6 -0
  244. package/dist/integrations/types.d.ts.map +1 -1
  245. package/dist/integrations/types.js.map +1 -1
  246. package/dist/mcp/build-server.d.ts +9 -2
  247. package/dist/mcp/build-server.d.ts.map +1 -1
  248. package/dist/mcp/build-server.js +97 -20
  249. package/dist/mcp/build-server.js.map +1 -1
  250. package/dist/mcp/external-agent-policy.d.ts +19 -0
  251. package/dist/mcp/external-agent-policy.d.ts.map +1 -0
  252. package/dist/mcp/external-agent-policy.js +2 -0
  253. package/dist/mcp/external-agent-policy.js.map +1 -0
  254. package/dist/mcp/index.d.ts +1 -0
  255. package/dist/mcp/index.d.ts.map +1 -1
  256. package/dist/mcp/index.js.map +1 -1
  257. package/dist/notifications/routes.d.ts +1 -1
  258. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  259. package/dist/scripts/agent-engines/list-agent-engines.js +1 -19
  260. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  261. package/dist/server/agent-chat/plugin-options.d.ts +11 -1
  262. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  263. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  264. package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
  265. package/dist/server/agent-chat/script-entries.js +16 -2
  266. package/dist/server/agent-chat/script-entries.js.map +1 -1
  267. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  268. package/dist/server/agent-chat-plugin.js +3 -0
  269. package/dist/server/agent-chat-plugin.js.map +1 -1
  270. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  271. package/dist/server/transcribe-voice.d.ts +1 -1
  272. package/dist/session-replay-iframe-protocol.d.ts +36 -0
  273. package/dist/session-replay-iframe-protocol.d.ts.map +1 -0
  274. package/dist/session-replay-iframe-protocol.js +24 -0
  275. package/dist/session-replay-iframe-protocol.js.map +1 -0
  276. package/dist/shared/reasoning-effort.d.ts +11 -0
  277. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  278. package/dist/shared/reasoning-effort.js +36 -0
  279. package/dist/shared/reasoning-effort.js.map +1 -1
  280. package/dist/styles/agent-conversation.css +26 -0
  281. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
  282. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  283. package/docs/content/durable-background-runs.mdx +37 -0
  284. package/docs/content/external-agents.mdx +62 -7
  285. package/docs/content/locales/ar-SA/external-agents.mdx +38 -7
  286. package/docs/content/locales/ar-SA/tracking.mdx +2 -0
  287. package/docs/content/locales/de-DE/external-agents.mdx +39 -7
  288. package/docs/content/locales/de-DE/tracking.mdx +2 -0
  289. package/docs/content/locales/es-ES/external-agents.mdx +39 -7
  290. package/docs/content/locales/es-ES/tracking.mdx +2 -0
  291. package/docs/content/locales/fr-FR/external-agents.mdx +39 -7
  292. package/docs/content/locales/fr-FR/tracking.mdx +4 -2
  293. package/docs/content/locales/hi-IN/external-agents.mdx +38 -7
  294. package/docs/content/locales/hi-IN/tracking.mdx +2 -0
  295. package/docs/content/locales/ja-JP/external-agents.mdx +38 -7
  296. package/docs/content/locales/ja-JP/tracking.mdx +2 -0
  297. package/docs/content/locales/ko-KR/external-agents.mdx +38 -7
  298. package/docs/content/locales/ko-KR/tracking.mdx +2 -0
  299. package/docs/content/locales/pt-BR/external-agents.mdx +39 -7
  300. package/docs/content/locales/pt-BR/tracking.mdx +2 -0
  301. package/docs/content/locales/zh-CN/external-agents.mdx +37 -7
  302. package/docs/content/locales/zh-CN/tracking.mdx +2 -0
  303. package/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
  304. package/docs/content/locales/zh-TW/external-agents.mdx +37 -7
  305. package/docs/content/locales/zh-TW/tracking.mdx +2 -0
  306. package/docs/content/tracking.mdx +2 -0
  307. package/package.json +2 -2
  308. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +34 -5
  309. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
  310. package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
  311. package/dist/observability/hosted-model-experiment.d.ts +0 -39
  312. package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
  313. package/dist/observability/hosted-model-experiment.js +0 -90
  314. package/dist/observability/hosted-model-experiment.js.map +0 -1
@@ -178,6 +178,16 @@ const BACKGROUND_FOLLOW_POLL_INTERVAL_MS = 1_000;
178
178
  // accurate if any of the four numbers change.
179
179
  export const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 150_000;
180
180
 
181
+ // A re-observed terminal run whose outcome would be an ERROR (never a
182
+ // genuine "done" success) gets a short extra grace window before the follow
183
+ // loop surfaces it: the server's dead-run recovery can reap a lost
184
+ // background run and insert a claimable successor a beat after the client
185
+ // first sees the stale terminal row. Deliberately much shorter than
186
+ // BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS — this exists to absorb that narrow
187
+ // insert-latency race, not to mask a genuinely lost run behind a long hang
188
+ // before the user sees an error.
189
+ const BACKGROUND_TERMINAL_ERROR_GRACE_POLLS = 5;
190
+
181
191
  /**
182
192
  * User-facing copy for the server's background terminal reasons
183
193
  * (`agent_runs.terminal_reason`, surfaced by /runs/active). These runs died in
@@ -200,6 +210,50 @@ const BACKGROUND_TERMINAL_REASON_MESSAGES: Record<string, string> = {
200
210
  "This request needed more automatic continuations than allowed and was stopped. Try breaking it into smaller steps.",
201
211
  };
202
212
 
213
+ /**
214
+ * `agent_runs.terminal_reason` values that mark a CHUNK boundary, not the end
215
+ * of the turn — `markBackgroundContinuationChunkTerminal` (production-agent.ts)
216
+ * writes status "completed" with one of these bare reasons whenever a
217
+ * background chunk ends at a continuation boundary (mirrors
218
+ * `AgentLoopContinuationReason` there). A run in this state is expected to be
219
+ * replaced by a server-chained successor row; it must never be read as "the
220
+ * turn is done" just because its own row says `status: "completed"`.
221
+ */
222
+ const BACKGROUND_CONTINUATION_TERMINAL_REASONS = new Set<string>([
223
+ "run_timeout",
224
+ "loop_limit",
225
+ "max_tokens",
226
+ "stream_ended",
227
+ "gateway_timeout",
228
+ "network_interrupted",
229
+ "no_progress",
230
+ ]);
231
+
232
+ /**
233
+ * True when the given `/runs/active` snapshot, if surfaced as a background
234
+ * terminal outcome right now, would render as an error rather than a
235
+ * successful completion. Mirrors `emitBackgroundTerminalOutcome`'s own
236
+ * mappedMessage/hasErrorTerminalReason/status branching (kept in sync with
237
+ * it) so callers can decide whether an error-surfacing grace window applies
238
+ * BEFORE actually emitting anything.
239
+ */
240
+ function isBackgroundTerminalErrorOutcome(
241
+ lastKnown: Record<string, unknown> | null,
242
+ ): boolean {
243
+ const status = typeof lastKnown?.status === "string" ? lastKnown.status : "";
244
+ const rawTerminalReason =
245
+ typeof lastKnown?.terminalReason === "string"
246
+ ? lastKnown.terminalReason
247
+ : "";
248
+ const hasErrorTerminalReason = rawTerminalReason.startsWith("error:");
249
+ const terminalReason = rawTerminalReason.replace(/^error:/, "");
250
+ const mappedMessage = terminalReason
251
+ ? BACKGROUND_TERMINAL_REASON_MESSAGES[terminalReason]
252
+ : undefined;
253
+ if (mappedMessage || hasErrorTerminalReason) return true;
254
+ return status !== "completed";
255
+ }
256
+
203
257
  function normalizeMentions(text: string): string {
204
258
  return text.replace(/@\[([^\]|]+)\|[^\]]+\]/g, "@$1");
205
259
  }
@@ -2387,6 +2441,52 @@ export function createAgentChatAdapter(
2387
2441
  };
2388
2442
  dispatchResumingUiEvent();
2389
2443
 
2444
+ // Before surfacing a background terminal ERROR (never called for a
2445
+ // genuine "done" success — see call site), give the server's
2446
+ // reap-and-recover path a short extra window to insert a claimable
2447
+ // successor row for this turn. Returns as soon as `/runs/active`
2448
+ // reports a DIFFERENT runId than the stale one, so the caller can
2449
+ // hand back to the main loop and follow it seamlessly instead of
2450
+ // erroring out from under it.
2451
+ const awaitBackgroundErrorRecoverySuccessor = async (
2452
+ staleRunId: string,
2453
+ ): Promise<"successor" | "timeout" | "aborted"> => {
2454
+ for (
2455
+ let attempt = 0;
2456
+ attempt < BACKGROUND_TERMINAL_ERROR_GRACE_POLLS;
2457
+ attempt++
2458
+ ) {
2459
+ if (abortSignal.aborted) return "aborted";
2460
+ dispatchResumingUiEvent();
2461
+ await delay(BACKGROUND_FOLLOW_POLL_INTERVAL_MS, abortSignal);
2462
+ if (abortSignal.aborted) return "aborted";
2463
+ let recheck: Record<string, unknown> | null = null;
2464
+ try {
2465
+ const activeRes = await fetch(
2466
+ `${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId!)}`,
2467
+ { signal: abortSignal },
2468
+ );
2469
+ if (activeRes.ok) {
2470
+ recheck = await activeRes.json().catch(() => null);
2471
+ }
2472
+ } catch (pollErr: unknown) {
2473
+ if (pollErr instanceof Error && pollErr.name === "AbortError") {
2474
+ return "aborted";
2475
+ }
2476
+ // Transient poll failure — this attempt counts as "no
2477
+ // successor yet", not a hard failure of the grace window.
2478
+ }
2479
+ const recheckRunId =
2480
+ recheck?.active === true && recheck.runId
2481
+ ? String(recheck.runId)
2482
+ : null;
2483
+ if (recheckRunId && recheckRunId !== staleRunId) {
2484
+ return "successor";
2485
+ }
2486
+ }
2487
+ return "timeout";
2488
+ };
2489
+
2390
2490
  let idleSince: number | null = null;
2391
2491
  let lastSeenActive: Record<string, unknown> | null = null;
2392
2492
  // Terminal runs already replayed once. A recoverable terminal error
@@ -2394,7 +2494,10 @@ export function createAgentChatAdapter(
2394
2494
  // which used to re-drive a POST in foreground mode. In follow mode
2395
2495
  // the server owns recovery, so a SECOND visit to the same terminal
2396
2496
  // run means the turn is over — surface the outcome instead of
2397
- // re-replaying it every poll for the whole reconnect window.
2497
+ // re-replaying it every poll for the whole reconnect window. (A
2498
+ // CONTINUATION-class terminal_reason is the one exception: see the
2499
+ // isContinuationChunkBoundary check below, which keeps polling
2500
+ // instead of surfacing anything.)
2398
2501
  const replayedTerminalRunIds = new Set<string>();
2399
2502
 
2400
2503
  while (true) {
@@ -2458,6 +2561,64 @@ export function createAgentChatAdapter(
2458
2561
  return "client_continue";
2459
2562
  }
2460
2563
  }
2564
+ const rawTerminalReason =
2565
+ typeof active?.terminalReason === "string"
2566
+ ? active.terminalReason
2567
+ : "";
2568
+ const bareTerminalReason = rawTerminalReason.replace(
2569
+ /^error:/,
2570
+ "",
2571
+ );
2572
+ // A re-observed "completed" row with a CONTINUATION-class
2573
+ // reason (run_timeout/no_progress/loop_limit/…) is a MID-TURN
2574
+ // chunk boundary, not the end of the turn — a warm instance
2575
+ // can keep serving this stale row for a beat before the
2576
+ // pre-inserted successor becomes visible. Emitting a terminal
2577
+ // outcome here is exactly the bug this branch exists to
2578
+ // avoid: it would flip the message to "done" while the
2579
+ // successor's content is still coming. Keep polling on the
2580
+ // shared idle budget instead; a truly stuck handoff still
2581
+ // fails loud (never a silent stop) once it expires.
2582
+ const isContinuationChunkBoundary =
2583
+ activeStatus === "completed" &&
2584
+ !rawTerminalReason.startsWith("error:") &&
2585
+ !BACKGROUND_TERMINAL_REASON_MESSAGES[bareTerminalReason] &&
2586
+ BACKGROUND_CONTINUATION_TERMINAL_REASONS.has(
2587
+ bareTerminalReason,
2588
+ );
2589
+ if (isContinuationChunkBoundary) {
2590
+ if (idleSince === null) idleSince = Date.now();
2591
+ if (
2592
+ Date.now() - idleSince >=
2593
+ BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS
2594
+ ) {
2595
+ yield* emitBackgroundTerminalError({
2596
+ message:
2597
+ "The agent's background run stopped between chunks and no continuation appeared. You can retry from the preserved chat context.",
2598
+ errorCode: "background_run_lost",
2599
+ details: `terminal_reason: ${rawTerminalReason}`,
2600
+ });
2601
+ return "completed";
2602
+ }
2603
+ dispatchResumingUiEvent();
2604
+ await delay(BACKGROUND_FOLLOW_POLL_INTERVAL_MS, abortSignal);
2605
+ continue;
2606
+ }
2607
+ if (isBackgroundTerminalErrorOutcome(active)) {
2608
+ const graceOutcome =
2609
+ await awaitBackgroundErrorRecoverySuccessor(activeRunId);
2610
+ if (graceOutcome === "aborted") {
2611
+ clearActiveRun();
2612
+ return "completed";
2613
+ }
2614
+ if (graceOutcome === "successor") {
2615
+ // A successor claimed the turn while we waited — hand
2616
+ // back to the top of the loop so it attaches and follows
2617
+ // it exactly like any other newly-discovered run instead
2618
+ // of duplicating that bookkeeping here.
2619
+ continue;
2620
+ }
2621
+ }
2461
2622
  yield* emitBackgroundTerminalOutcome(active);
2462
2623
  return "completed";
2463
2624
  }
@@ -2513,6 +2674,13 @@ export function createAgentChatAdapter(
2513
2674
  }
2514
2675
  dispatchResumingUiEvent();
2515
2676
  } else {
2677
+ // No active run visible for this turn yet (the gap between a
2678
+ // chunk ending and the successor becoming pollable). Refresh
2679
+ // the "Resuming…" bridge on every tick here too — not just
2680
+ // when an active run IS visible — so the client's own
2681
+ // isAutoResuming window can't lapse into a false-idle UI while
2682
+ // this loop is still confidently waiting out its own budget.
2683
+ dispatchResumingUiEvent();
2516
2684
  if (idleSince === null) idleSince = Date.now();
2517
2685
  if (Date.now() - idleSince >= BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS) {
2518
2686
  captureChatClientError(
@@ -842,6 +842,7 @@ export function shouldShowAssistantMessageFooter({
842
842
 
843
843
  function ReasoningMessagePart() {
844
844
  const part = useMessagePartReasoning();
845
+ const chatRunning = React.useContext(ChatRunningContext);
845
846
  const isStreaming = part.status?.type === "running";
846
847
  // Time thinking client-side: record the moment streaming first starts and
847
848
  // the moment it stops so the cell can show "Thought for Xs". Historical
@@ -864,6 +865,8 @@ function ReasoningMessagePart() {
864
865
  text={part.text}
865
866
  isStreaming={isStreaming}
866
867
  durationMs={durationMs}
868
+ defaultOpen={isStreaming || !chatRunning}
869
+ autoCollapse={chatRunning}
867
870
  />
868
871
  );
869
872
  }
@@ -404,45 +404,16 @@ export function AnimatedCollapse({
404
404
  open: boolean;
405
405
  children: React.ReactNode;
406
406
  }) {
407
- const ref = useRef<HTMLDivElement>(null);
408
- const [height, setHeight] = useState<number | "auto">(open ? "auto" : 0);
409
407
  const [mounted, setMounted] = useState(open);
410
- const reduceMotionRef = useRef(false);
411
-
412
- useEffect(() => {
413
- reduceMotionRef.current =
414
- typeof window !== "undefined" &&
415
- !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
416
- }, []);
417
408
 
418
409
  useLayoutEffect(() => {
419
410
  if (open) setMounted(true);
420
411
  }, [open]);
421
412
 
422
- useLayoutEffect(() => {
423
- const el = ref.current;
424
- if (!el || !mounted) return;
425
- if (reduceMotionRef.current) {
426
- setHeight(open ? "auto" : 0);
427
- if (!open) setMounted(false);
428
- return;
429
- }
430
- if (open) {
431
- const full = el.scrollHeight;
432
- setHeight(0);
433
- const frame = requestAnimationFrame(() => setHeight(full));
434
- return () => cancelAnimationFrame(frame);
435
- }
436
- setHeight(el.scrollHeight);
437
- const frame = requestAnimationFrame(() => setHeight(0));
438
- return () => cancelAnimationFrame(frame);
439
- }, [open, mounted]);
440
-
441
413
  const onTransitionEnd = useCallback(
442
414
  (event: React.TransitionEvent<HTMLDivElement>) => {
443
- if (event.propertyName !== "height") return;
444
- if (open) setHeight("auto");
445
- else setMounted(false);
415
+ if (event.propertyName !== "grid-template-rows" || open) return;
416
+ setMounted(false);
446
417
  },
447
418
  [open],
448
419
  );
@@ -451,12 +422,12 @@ export function AnimatedCollapse({
451
422
 
452
423
  return (
453
424
  <div
454
- ref={ref}
455
- className="overflow-hidden transition-[height] duration-200 ease-[var(--ease-collapse)]"
456
- style={{ height: height === "auto" ? "auto" : `${height}px` }}
425
+ className="agent-chat-collapse"
426
+ data-state={open ? "open" : "closed"}
427
+ aria-hidden={!open}
457
428
  onTransitionEnd={onTransitionEnd}
458
429
  >
459
- {children}
430
+ <div className="agent-chat-collapse__content">{children}</div>
460
431
  </div>
461
432
  );
462
433
  }
@@ -953,6 +924,7 @@ export function ReconnectStreamMessage({
953
924
  key={`reconnect-reasoning-${i}`}
954
925
  text={part.text}
955
926
  isStreaming={chatRunning && i === streamingReasoningPartIndex}
927
+ defaultOpen={chatRunning && i === streamingReasoningPartIndex}
956
928
  />
957
929
  );
958
930
  }
@@ -996,11 +968,14 @@ export function ReasoningCell({
996
968
  text,
997
969
  isStreaming = false,
998
970
  defaultOpen,
971
+ autoCollapse = false,
999
972
  durationMs,
1000
973
  }: {
1001
974
  text: string;
1002
975
  isStreaming?: boolean;
1003
976
  defaultOpen?: boolean;
977
+ /** Animate closed when a live reasoning segment finishes during a run. */
978
+ autoCollapse?: boolean;
1004
979
  /**
1005
980
  * Elapsed thinking time in ms, once known. Only meaningful once streaming
1006
981
  * has finished — callers that track live timing (see ReasoningMessagePart)
@@ -1011,7 +986,16 @@ export function ReasoningCell({
1011
986
  }) {
1012
987
  const embeddedInWorkSummary = React.useContext(WorkSummaryContentContext);
1013
988
  const [open, setOpen] = useState(defaultOpen ?? true);
989
+ const wasStreamingRef = useRef(isStreaming);
1014
990
  const trimmed = text.trim();
991
+
992
+ useEffect(() => {
993
+ if (autoCollapse && wasStreamingRef.current && !isStreaming) {
994
+ setOpen(false);
995
+ }
996
+ wasStreamingRef.current = isStreaming;
997
+ }, [autoCollapse, isStreaming]);
998
+
1015
999
  if (!trimmed && !isStreaming) return null;
1016
1000
 
1017
1001
  if (embeddedInWorkSummary) {
@@ -1024,7 +1008,7 @@ export function ReasoningCell({
1024
1008
 
1025
1009
  const label = isStreaming
1026
1010
  ? "Thinking"
1027
- : durationMs != null && durationMs >= 1000
1011
+ : durationMs != null
1028
1012
  ? `Thought for ${formatWorkedDuration(durationMs)}`
1029
1013
  : "Thought";
1030
1014
  // Only clamp to a scroll-free "tail" view while actively streaming and
@@ -243,6 +243,12 @@ export function useNearBottomAutoscroll<TElement extends HTMLElement>({
243
243
  window.setTimeout(() => scrollToBottomIfFollowing(generation), 80);
244
244
  }, [scrollToBottomIfFollowing]);
245
245
 
246
+ const resumeFollowing = useCallback(() => {
247
+ const el = scrollRef.current;
248
+ setFollowingBottom(true, true, el ?? undefined);
249
+ scrollToBottomAfterPaint();
250
+ }, [scrollToBottomAfterPaint, setFollowingBottom]);
251
+
246
252
  const markNearBottom = useCallback(() => {
247
253
  setFollowingBottom(true, true, scrollRef.current ?? undefined);
248
254
  }, [setFollowingBottom]);
@@ -267,5 +273,6 @@ export function useNearBottomAutoscroll<TElement extends HTMLElement>({
267
273
  markNearBottom,
268
274
  scrollToBottom,
269
275
  scrollToBottomAfterPaint,
276
+ resumeFollowing,
270
277
  };
271
278
  }
@@ -9,6 +9,7 @@ import React, {
9
9
  type IframeHTMLAttributes,
10
10
  } from "react";
11
11
 
12
+ import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "../../session-replay-iframe-protocol.js";
12
13
  import {
13
14
  createAgentNativeHostBridge,
14
15
  type AgentNativeClientAction,
@@ -604,6 +605,7 @@ export const AgentNativeExtensionFrame = forwardRef<
604
605
  return (
605
606
  <iframe
606
607
  {...iframeProps}
608
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
607
609
  key={`${extension.id}:${extension.updatedAt ?? ""}`}
608
610
  ref={(node) => {
609
611
  iframeRef.current = node;
@@ -10,6 +10,7 @@ import { useNavigate } from "react-router";
10
10
 
11
11
  import { extensionPath } from "../../extensions/path.js";
12
12
  import { THEME_VAR_NAMES } from "../../extensions/theme.js";
13
+ import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "../../session-replay-iframe-protocol.js";
13
14
  import { sendToAgentChat } from "../agent-chat.js";
14
15
  import { agentNativePath } from "../api-path.js";
15
16
  import { useAppearance } from "../appearance.js";
@@ -425,6 +426,7 @@ export function EmbeddedExtension({
425
426
  return (
426
427
  <div className={`relative group/embedded-extension ${className ?? ""}`}>
427
428
  <iframe
429
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
428
430
  ref={iframeRef}
429
431
  key={`${extensionId}-${extension.updatedAt ?? ""}`}
430
432
  src={iframeSrc}
@@ -6,10 +6,12 @@ import {
6
6
  IconX,
7
7
  } from "@tabler/icons-react";
8
8
  import { useQuery, useQueryClient } from "@tanstack/react-query";
9
- import { useState, useEffect } from "react";
9
+ import { useEffect, useMemo, useState } from "react";
10
10
  import { Link, useNavigate } from "react-router";
11
11
 
12
12
  import { extensionPath } from "../../extensions/path.js";
13
+ import { injectSessionReplayIframeBootstrap } from "../../extensions/session-replay-iframe.js";
14
+ import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "../../session-replay-iframe-protocol.js";
13
15
  import { agentNativePath } from "../api-path.js";
14
16
  import {
15
17
  Popover,
@@ -61,6 +63,10 @@ export function ExtensionEditor({ extensionId }: ExtensionEditorProps) {
61
63
  const [deleting, setDeleting] = useState(false);
62
64
  const [menuOpen, setMenuOpen] = useState(false);
63
65
  const [confirmingDelete, setConfirmingDelete] = useState(false);
66
+ const previewHtml = useMemo(
67
+ () => injectSessionReplayIframeBootstrap(content),
68
+ [content],
69
+ );
64
70
 
65
71
  const slotsQuery = useQuery<SlotDeclaration[]>({
66
72
  queryKey: ["extension-slots", extensionId],
@@ -425,7 +431,8 @@ export function ExtensionEditor({ extensionId }: ExtensionEditorProps) {
425
431
  <div className="w-1/2">
426
432
  {content ? (
427
433
  <iframe
428
- srcDoc={content}
434
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
435
+ srcDoc={previewHtml}
429
436
  className="h-full w-full border-0"
430
437
  sandbox="allow-scripts allow-forms"
431
438
  title={t("extensions.previewTitle")}
@@ -17,6 +17,7 @@ import { Link, useLocation, useNavigate } from "react-router";
17
17
  import { buildExtensionHtml } from "../../extensions/html-shell.js";
18
18
  import { extensionPath, isExtensionPathname } from "../../extensions/path.js";
19
19
  import { getThemeVars } from "../../extensions/theme.js";
20
+ import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "../../session-replay-iframe-protocol.js";
20
21
  import { sendToAgentChat } from "../agent-chat.js";
21
22
  import { AgentToggleButton } from "../AgentPanel.js";
22
23
  import { agentNativePath, appPath } from "../api-path.js";
@@ -1400,6 +1401,7 @@ export function ExtensionViewer({ extensionId }: ExtensionViewerProps) {
1400
1401
  </div>
1401
1402
  )}
1402
1403
  <iframe
1404
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
1403
1405
  ref={iframeRef}
1404
1406
  key={`${extension.updatedAt}-${refreshKey}`}
1405
1407
  src={iframeSrcDoc ? undefined : iframeSrc}
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
2
2
 
3
3
  import { buildExtensionHtml } from "../../extensions/html-shell.js";
4
4
  import { getThemeVars } from "../../extensions/theme.js";
5
+ import { SESSION_REPLAY_IFRAME_ATTRIBUTE } from "../../session-replay-iframe-protocol.js";
5
6
  import { sendToAgentChat } from "../agent-chat.js";
6
7
  import { agentNativePath } from "../api-path.js";
7
8
  import {
@@ -641,6 +642,7 @@ export function InlineExtensionFrame({
641
642
  return (
642
643
  <div className={`relative ${className ?? ""}`}>
643
644
  <iframe
645
+ {...{ [SESSION_REPLAY_IFRAME_ATTRIBUTE]: "" }}
644
646
  ref={iframeRef}
645
647
  key={`${resolvedId}-${extension.updatedAt ?? "inline"}-${isTransient ? "transient" : "persisted"}`}
646
648
  src={iframeSrc}
@@ -1,4 +1,5 @@
1
1
  import { EXTENSION_IFRAME_META_CSP } from "../../extensions/html-shell.js";
2
+ import { buildSessionReplayIframeBootstrap } from "../../extensions/session-replay-iframe.js";
2
3
  import { AGENT_NATIVE_HOST_MESSAGE_TYPES } from "../host-bridge.js";
3
4
 
4
5
  export const AGENT_NATIVE_EXTENSION_MESSAGE_TYPES = {
@@ -702,6 +703,7 @@ export function buildAgentNativeExtensionHtml({
702
703
  }, '*');
703
704
  })();
704
705
  </script>
706
+ ${buildSessionReplayIframeBootstrap()}
705
707
  </head>
706
708
  <body>
707
709
  ${content}