@agent-native/core 0.131.5 → 0.131.7

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 (350) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +70 -0
  3. package/corpus/core/docs/content/agent-native-toolkit.mdx +13 -6
  4. package/corpus/core/docs/content/cloneable-saas.mdx +5 -5
  5. package/corpus/core/docs/content/creating-templates.mdx +9 -0
  6. package/corpus/core/docs/content/deployment.mdx +18 -12
  7. package/corpus/core/docs/content/doctor.mdx +8 -1
  8. package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
  9. package/corpus/core/docs/content/extensions.mdx +18 -18
  10. package/corpus/core/docs/content/faq.mdx +4 -4
  11. package/corpus/core/docs/content/key-concepts.mdx +30 -21
  12. package/corpus/core/docs/content/security.mdx +2 -2
  13. package/corpus/core/docs/content/template-brain-developers.mdx +4 -1
  14. package/corpus/core/docs/content/template-mail-developers.mdx +4 -1
  15. package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/a2a/client.ts +449 -66
  18. package/corpus/core/src/a2a/correlation.ts +31 -0
  19. package/corpus/core/src/a2a/invoke.ts +4 -2
  20. package/corpus/core/src/a2a/types.ts +4 -0
  21. package/corpus/core/src/action.ts +3 -0
  22. package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
  23. package/corpus/core/src/agent/engine/registry.ts +98 -6
  24. package/corpus/core/src/agent/production-agent.ts +151 -18
  25. package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
  26. package/corpus/core/src/agent/run-manager.ts +117 -41
  27. package/corpus/core/src/agent/thread-debug-history.ts +86 -0
  28. package/corpus/core/src/agent/types.ts +3 -1
  29. package/corpus/core/src/cli/create.ts +11 -1
  30. package/corpus/core/src/cli/templates-meta.ts +2 -2
  31. package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
  32. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
  33. package/corpus/core/src/client/sse-event-processor.ts +17 -3
  34. package/corpus/core/src/db/client.ts +57 -17
  35. package/corpus/core/src/guards/no-env-credentials.ts +2 -0
  36. package/corpus/core/src/integrations/adapters/slack.ts +8 -3
  37. package/corpus/core/src/localization/default-messages.ts +44 -0
  38. package/corpus/core/src/observability/traces.ts +78 -5
  39. package/corpus/core/src/scripts/call-agent.ts +294 -11
  40. package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
  41. package/corpus/core/src/secrets/crypto.ts +156 -35
  42. package/corpus/core/src/secrets/storage.ts +64 -26
  43. package/corpus/core/src/server/agent-capabilities.ts +1 -1
  44. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +113 -7
  45. package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
  46. package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
  47. package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
  48. package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
  49. package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  50. package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  51. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  53. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  54. package/corpus/core/src/vite/client.ts +1 -0
  55. package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
  56. package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
  57. package/corpus/templates/analytics/AGENTS.md +7 -4
  58. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
  59. package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
  60. package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
  61. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
  62. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
  63. package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
  64. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
  65. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
  66. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
  67. package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
  68. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
  69. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
  70. package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
  71. package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
  72. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
  73. package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
  74. package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
  75. package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
  76. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
  77. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
  78. package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
  79. package/corpus/templates/brain/AGENTS.md +3 -1
  80. package/corpus/templates/brain/README.md +4 -1
  81. package/corpus/templates/brain/actions/_schemas.ts +30 -8
  82. package/corpus/templates/brain/actions/ask-brain.ts +124 -14
  83. package/corpus/templates/brain/actions/create-source.ts +18 -2
  84. package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
  85. package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
  86. package/corpus/templates/brain/actions/import-capture.ts +17 -5
  87. package/corpus/templates/brain/actions/import-transcript.ts +17 -5
  88. package/corpus/templates/brain/actions/update-source.ts +25 -5
  89. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
  90. package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
  91. package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
  92. package/corpus/templates/brain/server/lib/brain.ts +49 -19
  93. package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
  94. package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
  95. package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
  96. package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
  97. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
  98. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  99. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
  100. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
  101. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
  102. package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
  103. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
  104. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
  105. package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
  106. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
  107. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
  108. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
  109. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
  110. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
  111. package/corpus/templates/design/package.json +0 -1
  112. package/corpus/templates/dispatch/AGENTS.md +8 -0
  113. package/corpus/templates/dispatch/DEVELOPING.md +29 -0
  114. package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
  115. package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
  116. package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
  117. package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
  118. package/corpus/templates/dispatch/netlify.toml +3 -0
  119. package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
  120. package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
  121. package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
  122. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  123. package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
  124. package/corpus/templates/plan/shared/plan-content.ts +35 -0
  125. package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
  126. package/corpus/templates/slides/AGENTS.md +4 -4
  127. package/corpus/templates/slides/actions/create-deck.ts +1 -1
  128. package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
  129. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
  130. package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
  131. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
  132. package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
  133. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
  134. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
  135. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
  136. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
  137. package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
  138. package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
  139. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
  140. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
  141. package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
  142. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
  143. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
  144. package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
  145. package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
  146. package/corpus/templates/slides/app/global.css +105 -0
  147. package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
  148. package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
  149. package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
  150. package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
  151. package/corpus/templates/slides/app/pages/Index.tsx +98 -41
  152. package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
  153. package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
  154. package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
  155. package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
  156. package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
  157. package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
  158. package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
  159. package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
  160. package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
  161. package/corpus/templates/slides/netlify.toml +3 -1
  162. package/corpus/templates/slides/package.json +0 -1
  163. package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
  164. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  165. package/corpus/templates/slides/vite.config.ts +0 -1
  166. package/corpus/toolkit/CHANGELOG.md +13 -0
  167. package/corpus/toolkit/README.md +19 -0
  168. package/corpus/toolkit/agent-native.eject.json +38 -0
  169. package/corpus/toolkit/package.json +29 -1
  170. package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
  171. package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
  172. package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
  173. package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
  174. package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
  175. package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
  176. package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
  177. package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
  178. package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
  179. package/corpus/toolkit/src/index.ts +1 -0
  180. package/dist/a2a/client.d.ts +23 -0
  181. package/dist/a2a/client.d.ts.map +1 -1
  182. package/dist/a2a/client.js +309 -44
  183. package/dist/a2a/client.js.map +1 -1
  184. package/dist/a2a/correlation.d.ts +1 -0
  185. package/dist/a2a/correlation.d.ts.map +1 -1
  186. package/dist/a2a/correlation.js +27 -0
  187. package/dist/a2a/correlation.js.map +1 -1
  188. package/dist/a2a/invoke.d.ts.map +1 -1
  189. package/dist/a2a/invoke.js +4 -2
  190. package/dist/a2a/invoke.js.map +1 -1
  191. package/dist/a2a/types.d.ts +4 -0
  192. package/dist/a2a/types.d.ts.map +1 -1
  193. package/dist/a2a/types.js.map +1 -1
  194. package/dist/action.d.ts +3 -0
  195. package/dist/action.d.ts.map +1 -1
  196. package/dist/action.js.map +1 -1
  197. package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
  198. package/dist/agent/action-continuation-guidance.js +2 -1
  199. package/dist/agent/action-continuation-guidance.js.map +1 -1
  200. package/dist/agent/engine/registry.d.ts.map +1 -1
  201. package/dist/agent/engine/registry.js +82 -8
  202. package/dist/agent/engine/registry.js.map +1 -1
  203. package/dist/agent/production-agent.d.ts +40 -1
  204. package/dist/agent/production-agent.d.ts.map +1 -1
  205. package/dist/agent/production-agent.js +113 -15
  206. package/dist/agent/production-agent.js.map +1 -1
  207. package/dist/agent/run-loop-with-resume.d.ts +21 -0
  208. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  209. package/dist/agent/run-loop-with-resume.js +163 -4
  210. package/dist/agent/run-loop-with-resume.js.map +1 -1
  211. package/dist/agent/run-manager.d.ts +16 -9
  212. package/dist/agent/run-manager.d.ts.map +1 -1
  213. package/dist/agent/run-manager.js +93 -42
  214. package/dist/agent/run-manager.js.map +1 -1
  215. package/dist/agent/thread-debug-history.d.ts +10 -0
  216. package/dist/agent/thread-debug-history.d.ts.map +1 -0
  217. package/dist/agent/thread-debug-history.js +68 -0
  218. package/dist/agent/thread-debug-history.js.map +1 -0
  219. package/dist/agent/types.d.ts +3 -1
  220. package/dist/agent/types.d.ts.map +1 -1
  221. package/dist/agent/types.js.map +1 -1
  222. package/dist/cli/create.d.ts.map +1 -1
  223. package/dist/cli/create.js +6 -1
  224. package/dist/cli/create.js.map +1 -1
  225. package/dist/cli/templates-meta.js +2 -2
  226. package/dist/cli/templates-meta.js.map +1 -1
  227. package/dist/client/agent-chat-adapter.d.ts +1 -1
  228. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  229. package/dist/client/agent-chat-adapter.js +76 -13
  230. package/dist/client/agent-chat-adapter.js.map +1 -1
  231. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  232. package/dist/client/resources/McpIntegrationDialog.js +1 -1
  233. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  234. package/dist/client/sse-event-processor.d.ts.map +1 -1
  235. package/dist/client/sse-event-processor.js +12 -3
  236. package/dist/client/sse-event-processor.js.map +1 -1
  237. package/dist/collab/routes.d.ts +1 -1
  238. package/dist/db/client.d.ts.map +1 -1
  239. package/dist/db/client.js +48 -17
  240. package/dist/db/client.js.map +1 -1
  241. package/dist/guards/no-env-credentials.d.ts.map +1 -1
  242. package/dist/guards/no-env-credentials.js +2 -0
  243. package/dist/guards/no-env-credentials.js.map +1 -1
  244. package/dist/integrations/adapters/slack.js +7 -3
  245. package/dist/integrations/adapters/slack.js.map +1 -1
  246. package/dist/localization/default-messages.d.ts +43 -0
  247. package/dist/localization/default-messages.d.ts.map +1 -1
  248. package/dist/localization/default-messages.js +43 -0
  249. package/dist/localization/default-messages.js.map +1 -1
  250. package/dist/observability/traces.d.ts +3 -1
  251. package/dist/observability/traces.d.ts.map +1 -1
  252. package/dist/observability/traces.js +73 -4
  253. package/dist/observability/traces.js.map +1 -1
  254. package/dist/progress/routes.d.ts +1 -1
  255. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  256. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  257. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  258. package/dist/scripts/call-agent.d.ts.map +1 -1
  259. package/dist/scripts/call-agent.js +237 -12
  260. package/dist/scripts/call-agent.js.map +1 -1
  261. package/dist/scripts/describe-workspace-apps.js +2 -2
  262. package/dist/scripts/describe-workspace-apps.js.map +1 -1
  263. package/dist/secrets/crypto.d.ts +36 -21
  264. package/dist/secrets/crypto.d.ts.map +1 -1
  265. package/dist/secrets/crypto.js +134 -33
  266. package/dist/secrets/crypto.js.map +1 -1
  267. package/dist/secrets/storage.d.ts +6 -6
  268. package/dist/secrets/storage.d.ts.map +1 -1
  269. package/dist/secrets/storage.js +43 -26
  270. package/dist/secrets/storage.js.map +1 -1
  271. package/dist/server/agent-capabilities.js +1 -1
  272. package/dist/server/agent-capabilities.js.map +1 -1
  273. package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
  274. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  275. package/dist/server/agent-chat/action-filters-a2a.js +94 -3
  276. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  277. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  278. package/dist/server/agent-chat/context-tools.js +2 -0
  279. package/dist/server/agent-chat/context-tools.js.map +1 -1
  280. package/dist/server/agent-chat/plugin-options.d.ts +23 -0
  281. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
  282. package/dist/server/agent-chat/plugin-options.js +4 -1
  283. package/dist/server/agent-chat/plugin-options.js.map +1 -1
  284. package/dist/server/agent-chat/prompt-resources.js +1 -1
  285. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  286. package/dist/server/agent-chat-plugin.d.ts +2 -1
  287. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  288. package/dist/server/agent-chat-plugin.js +79 -56
  289. package/dist/server/agent-chat-plugin.js.map +1 -1
  290. package/dist/server/realtime-token.d.ts +1 -1
  291. package/dist/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  292. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  293. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  294. package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  295. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  296. package/dist/vite/client.d.ts.map +1 -1
  297. package/dist/vite/client.js +1 -0
  298. package/dist/vite/client.js.map +1 -1
  299. package/docs/content/agent-native-toolkit.mdx +13 -6
  300. package/docs/content/cloneable-saas.mdx +5 -5
  301. package/docs/content/creating-templates.mdx +9 -0
  302. package/docs/content/deployment.mdx +18 -12
  303. package/docs/content/doctor.mdx +8 -1
  304. package/docs/content/drop-in-agent.mdx +1 -1
  305. package/docs/content/extensions.mdx +18 -18
  306. package/docs/content/faq.mdx +4 -4
  307. package/docs/content/key-concepts.mdx +30 -21
  308. package/docs/content/security.mdx +2 -2
  309. package/docs/content/template-brain-developers.mdx +4 -1
  310. package/docs/content/template-mail-developers.mdx +4 -1
  311. package/docs/content/what-is-agent-native.mdx +6 -6
  312. package/package.json +3 -3
  313. package/src/a2a/client.ts +449 -66
  314. package/src/a2a/correlation.ts +31 -0
  315. package/src/a2a/invoke.ts +4 -2
  316. package/src/a2a/types.ts +4 -0
  317. package/src/action.ts +3 -0
  318. package/src/agent/action-continuation-guidance.ts +2 -1
  319. package/src/agent/engine/registry.ts +98 -6
  320. package/src/agent/production-agent.ts +151 -18
  321. package/src/agent/run-loop-with-resume.ts +190 -3
  322. package/src/agent/run-manager.ts +117 -41
  323. package/src/agent/thread-debug-history.ts +86 -0
  324. package/src/agent/types.ts +3 -1
  325. package/src/cli/create.ts +11 -1
  326. package/src/cli/templates-meta.ts +2 -2
  327. package/src/client/agent-chat-adapter.ts +91 -13
  328. package/src/client/resources/McpIntegrationDialog.tsx +11 -9
  329. package/src/client/sse-event-processor.ts +17 -3
  330. package/src/db/client.ts +57 -17
  331. package/src/guards/no-env-credentials.ts +2 -0
  332. package/src/integrations/adapters/slack.ts +8 -3
  333. package/src/localization/default-messages.ts +44 -0
  334. package/src/observability/traces.ts +78 -5
  335. package/src/scripts/call-agent.ts +294 -11
  336. package/src/scripts/describe-workspace-apps.ts +2 -2
  337. package/src/secrets/crypto.ts +156 -35
  338. package/src/secrets/storage.ts +64 -26
  339. package/src/server/agent-capabilities.ts +1 -1
  340. package/src/server/agent-chat/action-filters-a2a.ts +113 -7
  341. package/src/server/agent-chat/context-tools.ts +2 -0
  342. package/src/server/agent-chat/plugin-options.ts +34 -1
  343. package/src/server/agent-chat/prompt-resources.ts +1 -1
  344. package/src/server/agent-chat-plugin.ts +91 -59
  345. package/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
  346. package/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
  347. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
  348. package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
  349. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
  350. package/src/vite/client.ts +1 -0
@@ -174,7 +174,8 @@ const BACKGROUND_FOLLOW_POLL_INTERVAL_MS = 1_000;
174
174
  // UNCLAIMED_BACKGROUND_RUN_GRACE_MS (25s)
175
175
  // + UNCLAIMED_BACKGROUND_RUN_FAST_SWEEP_MS (20s)
176
176
  // = ~45-65s worst-case time-to-first-redispatch-attempt
177
- // < BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS (150s, this constant)
177
+ // < RUN_NO_PROGRESS_HARD_TIMEOUT_MS (150s, run-manager.ts)
178
+ // < BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS (210s, this constant)
178
179
  // < UNCLAIMED_BACKGROUND_RUN_REDISPATCH_BOUND_MS (300s, run-store.ts)
179
180
  // On top of that margin, the follow loop below never counts a tick against
180
181
  // this timeout at all while `/runs/active` reports `awaitingRedispatch:
@@ -184,7 +185,7 @@ const BACKGROUND_FOLLOW_POLL_INTERVAL_MS = 1_000;
184
185
  // paper over a slow sweep; fix the sweep timing (run-store.ts /
185
186
  // agent-chat-plugin.ts) instead, and keep this comment's inequality chain
186
187
  // accurate if any of the four numbers change.
187
- export const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 150_000;
188
+ export const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 210_000;
188
189
 
189
190
  // Per-TURN follow budgets. BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS above is a
190
191
  // per-idle-WINDOW bound and resets every time a successor run appears, so a
@@ -1773,6 +1774,11 @@ export function createAgentChatAdapter(
1773
1774
  let lastAutoContinueReason: string | null = null;
1774
1775
  let lastRecoverableRunError: AgentAutoContinueErrorInfo | null = null;
1775
1776
  let lastActivityTrail: AgentActivityTrailEntry[] = [];
1777
+ let backgroundFollowNoProgressDetaches = 0;
1778
+ let backgroundFollowConsecutiveNoProgressDetaches = 0;
1779
+ let backgroundFollowLastDetachReason: string | null = null;
1780
+ let backgroundFollowLastDetachWasClientWatchdog: boolean | null = null;
1781
+ let backgroundFollowLastServerProgressAt: number | null = null;
1776
1782
  const attemptedRunIds: string[] = [];
1777
1783
  let authRecoveryAttempted = false;
1778
1784
  let continuationToolCallCounter = 0;
@@ -1828,6 +1834,21 @@ export function createAgentChatAdapter(
1828
1834
  ? `activity_trail: ${formatActivityTrail(lastActivityTrail)}`
1829
1835
  : "",
1830
1836
  `total_transient_continuations: ${totalTransientContinuationAttempts}`,
1837
+ `background_follow_no_progress_detaches: ${backgroundFollowNoProgressDetaches}`,
1838
+ `background_follow_consecutive_no_progress_detaches: ${backgroundFollowConsecutiveNoProgressDetaches}`,
1839
+ backgroundFollowLastDetachReason
1840
+ ? `background_follow_last_detach_reason: ${backgroundFollowLastDetachReason}`
1841
+ : "",
1842
+ backgroundFollowLastDetachWasClientWatchdog !== null
1843
+ ? `background_follow_last_detach_source: ${
1844
+ backgroundFollowLastDetachWasClientWatchdog
1845
+ ? "client_watchdog"
1846
+ : "server"
1847
+ }`
1848
+ : "",
1849
+ backgroundFollowLastServerProgressAt !== null
1850
+ ? `background_follow_last_server_progress_at: ${backgroundFollowLastServerProgressAt}`
1851
+ : "",
1831
1852
  ]
1832
1853
  .filter(Boolean)
1833
1854
  .join("\n");
@@ -2451,6 +2472,8 @@ export function createAgentChatAdapter(
2451
2472
  > {
2452
2473
  if (!runId) return "gone";
2453
2474
  let attached = false;
2475
+ backgroundFollowLastDetachReason = null;
2476
+ backgroundFollowLastDetachWasClientWatchdog = null;
2454
2477
  try {
2455
2478
  const eventsRes = await fetch(
2456
2479
  `${apiUrl}/runs/${encodeURIComponent(runId)}/events?after=${lastSeq + 1}`,
@@ -2488,6 +2511,9 @@ export function createAgentChatAdapter(
2488
2511
  }
2489
2512
  if (attachErr instanceof AgentAutoContinueSignal) {
2490
2513
  lastAutoContinueReason = attachErr.reason;
2514
+ backgroundFollowLastDetachReason = attachErr.reason;
2515
+ backgroundFollowLastDetachWasClientWatchdog =
2516
+ attachErr.clientWatchdog;
2491
2517
  if (attachErr.activityTrail.length > 0) {
2492
2518
  lastActivityTrail = [...attachErr.activityTrail];
2493
2519
  }
@@ -2641,6 +2667,9 @@ export function createAgentChatAdapter(
2641
2667
 
2642
2668
  let idleSince: number | null = null;
2643
2669
  let lastSeenActive: Record<string, unknown> | null = null;
2670
+ let lastObservedActiveRunId = runId;
2671
+ let lastObservedServerProgressAt: number | null = null;
2672
+ let noProgressPollAttempts = 0;
2644
2673
  // Terminal runs already replayed once. A recoverable terminal error
2645
2674
  // event replays as an auto-continue signal (isAutoRecoverableError),
2646
2675
  // which used to re-drive a POST in foreground mode. In follow mode
@@ -2826,6 +2855,25 @@ export function createAgentChatAdapter(
2826
2855
  });
2827
2856
  return "completed";
2828
2857
  }
2858
+ const activeProgressAt =
2859
+ typeof active?.lastProgressAt === "number" &&
2860
+ Number.isFinite(active.lastProgressAt)
2861
+ ? active.lastProgressAt
2862
+ : null;
2863
+ const runChanged = activeRunId !== lastObservedActiveRunId;
2864
+ const serverProgressAdvanced =
2865
+ activeProgressAt !== null &&
2866
+ lastObservedServerProgressAt !== null &&
2867
+ activeProgressAt > lastObservedServerProgressAt;
2868
+ lastObservedActiveRunId = activeRunId;
2869
+ if (activeProgressAt !== null) {
2870
+ lastObservedServerProgressAt =
2871
+ lastObservedServerProgressAt === null || runChanged
2872
+ ? activeProgressAt
2873
+ : Math.max(lastObservedServerProgressAt, activeProgressAt);
2874
+ backgroundFollowLastServerProgressAt =
2875
+ lastObservedServerProgressAt;
2876
+ }
2829
2877
  // Server-authoritative "silently deferred, recovery in
2830
2878
  // progress" signal (see `awaitingRedispatch` on
2831
2879
  // `getActiveRunForThreadAsync`, run-manager.ts): a
@@ -2839,19 +2887,29 @@ export function createAgentChatAdapter(
2839
2887
  // resumes, so a truly stuck deferral still fails loud via the
2840
2888
  // existing timeout below.
2841
2889
  const awaitingRedispatch = active?.awaitingRedispatch === true;
2842
- if (attach === "detached" || awaitingRedispatch) {
2843
- // We really attached to a live stream (chunk boundary or
2844
- // transport blip), or the server told us recovery is
2845
- // in-flight the run demonstrably exists; keep following
2846
- // with a fresh idle window.
2890
+ const madeProgress = runChanged || serverProgressAdvanced;
2891
+ if (madeProgress || awaitingRedispatch) {
2892
+ // Only server-authoritative progress resets the idle window:
2893
+ // a successor run or a newer lastProgressAt timestamp. Raw
2894
+ // sequence advancement is not enough — keepalives and retry
2895
+ // `clear` events are sequenced too, but the run manager
2896
+ // deliberately excludes both from lastProgressAt because they
2897
+ // do not move the user's task forward.
2847
2898
  idleSince = null;
2899
+ noProgressPollAttempts = 0;
2900
+ backgroundFollowConsecutiveNoProgressDetaches = 0;
2848
2901
  } else {
2849
- // "gone": /runs/active reported the run but its event stream
2850
- // 404s (reaped row / cross-isolate lag). Let the idle window
2851
- // ACCUMULATE instead of resetting, so a persistently
2852
- // inconsistent state still terminates loudly instead of
2853
- // hot-looping for the whole reconnect window.
2902
+ // An absent stream and an attached stream with no newer
2903
+ // server-authoritative progress are the same no-progress
2904
+ // observation. Keep accumulating one idle window and back off
2905
+ // repeat attaches so a broken SQL tail cannot become a
2906
+ // reconnect storm.
2854
2907
  if (idleSince === null) idleSince = Date.now();
2908
+ noProgressPollAttempts += 1;
2909
+ if (attach === "detached") {
2910
+ backgroundFollowNoProgressDetaches += 1;
2911
+ backgroundFollowConsecutiveNoProgressDetaches += 1;
2912
+ }
2855
2913
  if (
2856
2914
  Date.now() - idleSince >=
2857
2915
  BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS
@@ -2889,7 +2947,27 @@ export function createAgentChatAdapter(
2889
2947
  return "completed";
2890
2948
  }
2891
2949
  }
2892
- await delay(BACKGROUND_FOLLOW_POLL_INTERVAL_MS, abortSignal);
2950
+ const backedOffPollDelayMs =
2951
+ noProgressPollAttempts > 0
2952
+ ? Math.min(
2953
+ BACKGROUND_FOLLOW_POLL_INTERVAL_MS *
2954
+ 2 ** Math.min(noProgressPollAttempts - 1, 3),
2955
+ 5_000,
2956
+ )
2957
+ : BACKGROUND_FOLLOW_POLL_INTERVAL_MS;
2958
+ const idleRemainingMs =
2959
+ idleSince === null
2960
+ ? Number.POSITIVE_INFINITY
2961
+ : Math.max(
2962
+ 0,
2963
+ BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS -
2964
+ (Date.now() - idleSince),
2965
+ );
2966
+ const nextPollDelayMs = Math.min(
2967
+ backedOffPollDelayMs,
2968
+ idleRemainingMs,
2969
+ );
2970
+ await delay(nextPollDelayMs, abortSignal);
2893
2971
  if (abortSignal.aborted) {
2894
2972
  clearActiveRun();
2895
2973
  return "completed";
@@ -762,14 +762,16 @@ export function McpIntegrationDialog({
762
762
  </div>
763
763
  </div>
764
764
  <div className="flex shrink-0 items-center justify-between gap-2 border-t border-border px-7 py-4">
765
- <button
766
- type="button"
767
- onClick={runTest}
768
- disabled={!url.trim() || busy}
769
- className="rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40"
770
- >
771
- {t("mcpIntegrations.test")}
772
- </button>
765
+ {!selectedRequiresSetup && (
766
+ <button
767
+ type="button"
768
+ onClick={runTest}
769
+ disabled={!url.trim() || busy}
770
+ className="rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40"
771
+ >
772
+ {t("mcpIntegrations.test")}
773
+ </button>
774
+ )}
773
775
  {!selected ? (
774
776
  <button
775
777
  type="button"
@@ -790,7 +792,7 @@ export function McpIntegrationDialog({
790
792
  href={selected.docsUrl}
791
793
  target="_blank"
792
794
  rel="noopener noreferrer"
793
- className="inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90"
795
+ className="ms-auto inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90"
794
796
  >
795
797
  {t("mcpIntegrations.viewSetup")}
796
798
  <IconExternalLink className="h-3 w-3" />
@@ -233,7 +233,12 @@ export function sseInFlightWorkDelta(ev: SSEEvent): number {
233
233
  if (ev.type === "tool_done") return -1;
234
234
  if (ev.type === "agent_call") {
235
235
  if (ev.status === "start") return 1;
236
- if (ev.status === "done" || ev.status === "error") return -1;
236
+ if (
237
+ ev.status === "done" ||
238
+ ev.status === "pending" ||
239
+ ev.status === "error"
240
+ )
241
+ return -1;
237
242
  }
238
243
  return 0;
239
244
  }
@@ -1455,7 +1460,11 @@ export function processEvent(
1455
1460
  args: {},
1456
1461
  activity: true,
1457
1462
  });
1458
- } else if (ev.status === "done" || ev.status === "error") {
1463
+ } else if (
1464
+ ev.status === "done" ||
1465
+ ev.status === "pending" ||
1466
+ ev.status === "error"
1467
+ ) {
1459
1468
  for (let i = content.length - 1; i >= 0; i--) {
1460
1469
  const part = content[i];
1461
1470
  if (
@@ -1464,7 +1473,12 @@ export function processEvent(
1464
1473
  (!ev.agentCallId || part.toolCallId === ev.agentCallId) &&
1465
1474
  part.result === undefined
1466
1475
  ) {
1467
- part.result = ev.status === "error" ? "Error calling agent" : "Done";
1476
+ part.result =
1477
+ ev.status === "error"
1478
+ ? "Error calling agent"
1479
+ : ev.status === "pending"
1480
+ ? "Remote agent task is still pending"
1481
+ : "Done";
1468
1482
  part.structuredMeta = {
1469
1483
  ...part.structuredMeta,
1470
1484
  ...(ev.durationMs != null
package/src/db/client.ts CHANGED
@@ -652,6 +652,7 @@ function sqlAndArgs(sql: DbExecStatement): {
652
652
  }
653
653
 
654
654
  const POSTGRES_STATEMENT_TIMEOUT_HEADROOM_MS = 250;
655
+ const POSTGRES_STATEMENT_TIMEOUT_RESET_MS = 5_000;
655
656
  const POSTGRES_MAX_INT = 2_147_483_647;
656
657
 
657
658
  function hasExplicitDbTimeout(statement: DbExecStatement): boolean {
@@ -1225,22 +1226,15 @@ async function createDbExecInternal(
1225
1226
  // with CONNECT_TIMEOUT. The serverless Pool handles wake-up transparently
1226
1227
  // and keeps the same `pg`-compatible query(...) interface we need here.
1227
1228
  if (isNeonUrl(url)) {
1228
- const { Pool, neonConfig } = await import("@neondatabase/serverless");
1229
- // In the durable background-function worker, route pool queries over Neon's
1230
- // stateless HTTP transport instead of a long-lived WebSocket. A frozen/thawed
1231
- // bg-fn instance can leave the pool's WebSocket connections half-dead, so
1232
- // queries after the first burst stall on connect()/query() — observed: the
1233
- // analytics worker stalls right after model resolution and never claims.
1234
- // HTTP-per-query (poolQueryViaFetch) has no persistent socket to die; the
1235
- // foreground keeps the WebSocket pool. See the bg-fn execute branch below.
1229
+ const { Pool, neon } = await import("@neondatabase/serverless");
1230
+ // A frozen/thawed background function can retain half-dead WebSocket
1231
+ // connections, so its direct executions use stateless Neon HTTP instead.
1232
+ // The foreground and transaction surface keep the WebSocket pool.
1236
1233
  const bgHttp = isBackgroundFunctionPoolContext();
1237
- if (bgHttp) {
1238
- (neonConfig as { poolQueryViaFetch?: boolean }).poolQueryViaFetch =
1239
- true;
1240
- }
1241
1234
  const pool = new Pool({ connectionString: url, max: neonPoolMax() });
1242
1235
  attachNeonPoolErrorLogger(pool);
1243
1236
  if (trackSingletonResources) _neonPool = pool;
1237
+ const httpSql = bgHttp ? neon(url, { fullResults: true }) : null;
1244
1238
  async function queryNeonClient(
1245
1239
  client: any,
1246
1240
  sql: Parameters<DbExec["execute"]>[0],
@@ -1282,7 +1276,7 @@ async function createDbExecInternal(
1282
1276
  await queryNeonClient(
1283
1277
  client,
1284
1278
  "RESET statement_timeout",
1285
- remainingMs(),
1279
+ Math.max(remainingMs(), POSTGRES_STATEMENT_TIMEOUT_RESET_MS),
1286
1280
  );
1287
1281
  } catch (err) {
1288
1282
  markClientForDiscard();
@@ -1293,17 +1287,63 @@ async function createDbExecInternal(
1293
1287
  }
1294
1288
  }
1295
1289
  }
1290
+ async function queryNeonHttp(sql: Parameters<DbExec["execute"]>[0]) {
1291
+ if (!httpSql) {
1292
+ throw new Error("Neon HTTP query used outside a background function");
1293
+ }
1294
+ const { rawSql, args } = sqlAndArgs(sql);
1295
+ const { timeoutMs } = dbExecQueryBudget(sql);
1296
+ const pgSql = sqliteToPostgresParams(rawSql);
1297
+ const controller = new AbortController();
1298
+ const run = async () => {
1299
+ if (!hasExplicitDbTimeout(sql)) {
1300
+ return httpSql.query(pgSql, args as any[], {
1301
+ fetchOptions: { signal: controller.signal },
1302
+ });
1303
+ }
1304
+ const statementDeadlineMs =
1305
+ Date.now() + postgresStatementTimeoutMs(timeoutMs);
1306
+ const results = await httpSql.transaction(
1307
+ [
1308
+ httpSql.query(
1309
+ `SELECT set_config(
1310
+ 'statement_timeout',
1311
+ GREATEST(
1312
+ 1,
1313
+ $1::bigint -
1314
+ FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000)::bigint
1315
+ )::text,
1316
+ true
1317
+ )`,
1318
+ [statementDeadlineMs],
1319
+ ),
1320
+ httpSql.query(pgSql, args as any[]),
1321
+ ],
1322
+ { fetchOptions: { signal: controller.signal } },
1323
+ );
1324
+ return results[1];
1325
+ };
1326
+ const result = await withDbTimeout("query", run, timeoutMs, () =>
1327
+ controller.abort(),
1328
+ );
1329
+ return {
1330
+ rows: result.rows,
1331
+ rowsAffected: result.rowCount ?? 0,
1332
+ };
1333
+ }
1296
1334
  return {
1297
1335
  async execute(sql) {
1298
1336
  const { timeoutMs, maxAttempts } = dbExecQueryBudget(sql);
1299
1337
  if (bgHttp) {
1300
- // HTTP-per-query path (poolQueryViaFetch=true): no pool.connect(), no
1301
- // persistent socket to stall. queryNeonClient calls pool.query(),
1302
- // which the driver routes over HTTP when poolQueryViaFetch is set.
1338
+ // HTTP-per-query path: no pool.connect() and no persistent socket
1339
+ // to survive a background-function freeze. Explicitly budgeted
1340
+ // statements run with SET LOCAL inside the same HTTP transaction,
1341
+ // so the server cancels the SQL before the fetch deadline without
1342
+ // leaking session state into Neon's pooled backends.
1303
1343
  return retryOnConnectionError<{
1304
1344
  rows: unknown[];
1305
1345
  rowsAffected: number;
1306
- }>(() => queryNeonClient(pool, sql), maxAttempts);
1346
+ }>(() => queryNeonHttp(sql), maxAttempts);
1307
1347
  }
1308
1348
  const result = await retryOnConnectionError<{
1309
1349
  rows: unknown[];
@@ -65,6 +65,8 @@ const ALLOWLIST_EXACT = new Set([
65
65
  "PORT",
66
66
  "HOST",
67
67
  "SECRETS_ENCRYPTION_KEY",
68
+ "WORKSPACE_SECRETS_ENCRYPTION_KEY",
69
+ "WORKSPACE_SECRETS_ENCRYPTION_KEY_PREVIOUS",
68
70
  ]);
69
71
 
70
72
  const ALLOWLIST_PREFIX = [
@@ -2067,7 +2067,9 @@ function createSlackRunProgress(
2067
2067
  ? "in_progress"
2068
2068
  : event.status === "done"
2069
2069
  ? "complete"
2070
- : "error";
2070
+ : event.status === "pending"
2071
+ ? "in_progress"
2072
+ : "error";
2071
2073
  const title = delegatedTaskTitle(event.agent);
2072
2074
  tasks.set(id, { title, status });
2073
2075
  await append({
@@ -2075,9 +2077,12 @@ function createSlackRunProgress(
2075
2077
  id,
2076
2078
  title,
2077
2079
  status,
2078
- ...(event.status === "start"
2080
+ ...(event.status === "start" || event.status === "pending"
2079
2081
  ? {
2080
- details: `I’m contacting ${shortTaskTitle(event.agent)} for an answer.`,
2082
+ details:
2083
+ event.status === "pending"
2084
+ ? `${shortTaskTitle(event.agent)} is still working and will need another status check.`
2085
+ : `I’m contacting ${shortTaskTitle(event.agent)} for an answer.`,
2081
2086
  }
2082
2087
  : {}),
2083
2088
  });
@@ -316,6 +316,50 @@ const messages = {
316
316
  unknownPlatform: "unknown",
317
317
  attemptsCount: "{{count}} attempts",
318
318
  noErrorMessage: "(no error message)",
319
+ threadDebugInspectFailure: "Inspect failed run",
320
+ threadDebugFailureCode: "Failure code",
321
+ threadDebugTerminalReason: "Terminal reason",
322
+ threadDebugDispatchMode: "Dispatch mode",
323
+ threadDebugLastStage: "Last stage",
324
+ threadDebugDuration: "Duration",
325
+ threadDebugLastProgress: "Last progress",
326
+ threadDebugTitle: "Thread Debug",
327
+ threadDebugDescription:
328
+ "Inspect failed agent runs, persisted threads, run events, and AI internals.",
329
+ threadDebugFailedRuns: "Failed runs",
330
+ threadDebugThreads: "Threads",
331
+ threadDebugSource: "Source",
332
+ threadDebugAllSources: "All sources",
333
+ threadDebugOwner: "Owner email",
334
+ threadDebugStatus: "Status",
335
+ threadDebugAllStatuses: "All statuses",
336
+ threadDebugErrored: "Errored",
337
+ threadDebugAborted: "Aborted",
338
+ threadDebugTruncated: "Truncated",
339
+ threadDebugRange: "Time range",
340
+ threadDebugRange24h: "Last 24 hours",
341
+ threadDebugRange7d: "Last 7 days",
342
+ threadDebugRange30d: "Last 30 days",
343
+ threadDebugFailureResults: "failed runs",
344
+ threadDebugCurrentScope: "current scope",
345
+ threadDebugPartialResults: "Partial results",
346
+ threadDebugUnavailableSources: "Unavailable sources:",
347
+ threadDebugDisconnected: "disconnected",
348
+ threadDebugUnsupported: "unsupported",
349
+ threadDebugUnavailable: "unavailable",
350
+ threadDebugRefreshFailures: "Refresh failed runs",
351
+ threadDebugNoFailures: "No failed runs found.",
352
+ threadDebugCurrentDatabase: "Current Dispatch DB",
353
+ threadDebugSearchPlaceholder: "Search title, preview, messages, tools",
354
+ threadDebugSearch: "Search",
355
+ threadDebugLookupPlaceholder: "Paste thread or request/run ID",
356
+ threadDebugInspect: "Inspect",
357
+ threadDebugAdminScope: "admin scope",
358
+ threadDebugOwnScope: "own scope",
359
+ threadDebugResults: "results",
360
+ threadDebugRefreshThreads: "Refresh threads",
361
+ threadDebugNoThreads: "No threads found.",
362
+ threadDebugSelectPrompt: "Select a failed run or thread to inspect.",
319
363
  browserChatUnavailableTitle: "Browser chat session unavailable",
320
364
  browserChatUnavailableDescription:
321
365
  "Reconnect from the Agent-Native browser extension.",
@@ -1,4 +1,7 @@
1
- import type { AgentLoopUsage } from "../agent/production-agent.js";
1
+ import type {
2
+ AgentLoopOutcome,
3
+ AgentLoopUsage,
4
+ } from "../agent/production-agent.js";
2
5
  import type { AgentChatEvent, AgentToolInput } from "../agent/types.js";
3
6
  import { type AgentSpan, endAgentSpan, startAgentSpan } from "./tracing.js";
4
7
  import { trackingIdentityProperties } from "./tracking-identity.js";
@@ -100,6 +103,7 @@ function emitLlmGenerationTrackingEvent(args: {
100
103
  failedTools: number;
101
104
  tools: GenerationToolCall[];
102
105
  toolsTruncated: boolean;
106
+ terminalOutcome?: AgentLoopOutcome;
103
107
  delegation?: {
104
108
  protocol: "a2a" | "mcp";
105
109
  callerApp?: string;
@@ -149,6 +153,16 @@ function emitLlmGenerationTrackingEvent(args: {
149
153
  failed_tools: args.failedTools,
150
154
  tools: args.tools,
151
155
  tools_truncated: args.toolsTruncated,
156
+ terminal_state: args.terminalOutcome?.state,
157
+ terminal_code:
158
+ args.terminalOutcome?.state === "failed" ||
159
+ args.terminalOutcome?.state === "input_required"
160
+ ? args.terminalOutcome.code
161
+ : undefined,
162
+ terminal_retryable:
163
+ args.terminalOutcome?.state === "failed"
164
+ ? args.terminalOutcome.retryable
165
+ : undefined,
152
166
  delegated: args.delegation ? true : undefined,
153
167
  delegation_protocol: args.delegation?.protocol,
154
168
  caller_app: args.delegation?.callerApp,
@@ -269,6 +283,7 @@ export async function instrumentAgentLoop(opts: {
269
283
  send: (event: AgentChatEvent) => void;
270
284
  signal: AbortSignal;
271
285
  onUsage?: (usage: AgentLoopUsage) => void;
286
+ onOutcome?: (outcome: AgentLoopOutcome) => void;
272
287
  providerOptions?: any;
273
288
  runId?: string;
274
289
  }) => Promise<AgentLoopUsage>;
@@ -282,6 +297,7 @@ export async function instrumentAgentLoop(opts: {
282
297
  send: (event: AgentChatEvent) => void;
283
298
  signal: AbortSignal;
284
299
  onUsage?: (usage: AgentLoopUsage) => void;
300
+ onOutcome?: (outcome: AgentLoopOutcome) => void;
285
301
  providerOptions?: any;
286
302
  runId?: string;
287
303
  };
@@ -381,9 +397,62 @@ export async function instrumentAgentLoop(opts: {
381
397
  // Track in-flight OTel tool spans so they're all ended even if the loop
382
398
  // throws before a matching `tool_done` arrives.
383
399
  const openOtelToolSpans = new Set<AgentSpan>();
400
+ let usage: AgentLoopUsage | undefined;
401
+ let runStatus: "success" | "error" = "success";
402
+ let errorMessage: string | null = null;
403
+ let runMetadata: Record<string, unknown> | null = opts.metadata ?? null;
404
+ let terminalOutcome: AgentLoopOutcome | undefined;
405
+
406
+ const instrumentedOutcome = (outcome: AgentLoopOutcome): void => {
407
+ terminalOutcome = outcome;
408
+ if (outcome.state === "completed") {
409
+ runStatus = "success";
410
+ errorMessage = null;
411
+ } else {
412
+ runStatus = "error";
413
+ errorMessage =
414
+ outcome.state === "canceled"
415
+ ? (outcome.message ?? "Agent run was canceled.")
416
+ : outcome.message;
417
+ }
418
+ runMetadata = {
419
+ ...(runMetadata ?? {}),
420
+ terminal_state: outcome.state,
421
+ ...("code" in outcome ? { terminal_code: outcome.code } : {}),
422
+ ...(outcome.state === "failed"
423
+ ? { terminal_retryable: outcome.retryable }
424
+ : {}),
425
+ };
426
+ try {
427
+ loopOpts.onOutcome?.(outcome);
428
+ } catch {
429
+ // Observability adapters cannot alter the agent run.
430
+ }
431
+ };
384
432
 
385
433
  const instrumentedSend = (event: AgentChatEvent): void => {
386
434
  try {
435
+ // Some guardrails intentionally stop the loop by emitting a terminal
436
+ // event and returning usage instead of throwing. Preserve that terminal
437
+ // state in telemetry so a tripwire/loop-limit/provider error cannot be
438
+ // counted as a successful delegated generation. A later clear/done means
439
+ // the wrapper recovered and finished cleanly, so reset in that case.
440
+ if (event.type === "clear" || event.type === "done") {
441
+ runStatus = "success";
442
+ errorMessage = null;
443
+ } else if (event.type === "error") {
444
+ runStatus = "error";
445
+ errorMessage = event.error;
446
+ } else if (event.type === "tripwire") {
447
+ runStatus = "error";
448
+ errorMessage = event.reason;
449
+ } else if (event.type === "loop_limit") {
450
+ runStatus = "error";
451
+ errorMessage = "Agent stopped at the loop limit";
452
+ } else if (event.type === "missing_api_key") {
453
+ runStatus = "error";
454
+ errorMessage = "Missing API key";
455
+ }
387
456
  if (event.type === "tool_start") {
388
457
  const counter = toolInvocationCounter++;
389
458
  const sid = spanId();
@@ -554,15 +623,12 @@ export async function instrumentAgentLoop(opts: {
554
623
  loopOpts.send(event);
555
624
  };
556
625
 
557
- let usage: AgentLoopUsage | undefined;
558
- let runStatus: "success" | "error" = "success";
559
- let errorMessage: string | null = null;
560
- let runMetadata: Record<string, unknown> | null = opts.metadata ?? null;
561
626
  try {
562
627
  usage = await runAgentLoop({
563
628
  ...loopOpts,
564
629
  runId,
565
630
  send: instrumentedSend,
631
+ onOutcome: instrumentedOutcome,
566
632
  });
567
633
  } catch (err: any) {
568
634
  const classification = opts.classifyError?.(err) ?? null;
@@ -727,6 +793,7 @@ export async function instrumentAgentLoop(opts: {
727
793
  .map(([, detail]) => detail),
728
794
  toolsTruncated:
729
795
  toolInvocationCounter > MAX_TRACKED_GENERATION_TOOL_CALLS,
796
+ terminalOutcome,
730
797
  delegation: opts.delegation,
731
798
  createdAt: runStart,
732
799
  experimentAssignments: opts.experimentAssignments,
@@ -811,6 +878,12 @@ export async function instrumentAgentLoop(opts: {
811
878
  "agent.input_tokens": usage?.inputTokens ?? 0,
812
879
  "agent.output_tokens": usage?.outputTokens ?? 0,
813
880
  "agent.cost_cents_x100": costCentsX100,
881
+ "agent.terminal_state": terminalOutcome?.state,
882
+ "agent.terminal_code":
883
+ terminalOutcome?.state === "failed" ||
884
+ terminalOutcome?.state === "input_required"
885
+ ? terminalOutcome.code
886
+ : undefined,
814
887
  },
815
888
  });
816
889
  } catch {