@agent-native/core 0.169.1 → 0.170.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (459) hide show
  1. package/agent-native.eject.json +4 -1
  2. package/bin/agent-native.js +23 -5
  3. package/corpus/README.md +1 -1
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
  5. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  6. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  7. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  8. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  9. package/corpus/templates/analytics/app/routes.ts +3 -1
  10. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  12. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  14. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  15. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  16. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  17. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  18. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  19. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  20. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  21. package/corpus/templates/analytics/vitest.config.ts +6 -1
  22. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  23. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  24. package/corpus/templates/assets/app/routes.ts +3 -1
  25. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  26. package/corpus/templates/assets/vitest.config.ts +6 -1
  27. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  28. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  29. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  30. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  31. package/corpus/templates/brain/vitest.config.ts +1 -0
  32. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  33. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  34. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  35. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  36. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  37. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  38. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  39. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  40. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  41. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  42. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  43. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  44. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  45. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  46. package/corpus/templates/calendar/app/routes.ts +3 -1
  47. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  48. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  49. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  50. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  51. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  52. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  53. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  54. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  55. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  56. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  57. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  58. package/corpus/templates/calendar/shared/api.ts +9 -1
  59. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  60. package/corpus/templates/chat/app/routes.ts +3 -1
  61. package/corpus/templates/chat/vitest.config.ts +8 -0
  62. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  63. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  64. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  65. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  66. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  67. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  68. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  69. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  70. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  71. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  72. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  73. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  74. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  75. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  76. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  80. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  81. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  82. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  83. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  84. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  86. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  87. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  88. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  89. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  90. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  91. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  92. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  93. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  94. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  95. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  96. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  97. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  98. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  99. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  100. package/corpus/templates/content/app/i18n-data.ts +25 -0
  101. package/corpus/templates/content/app/routes.ts +3 -1
  102. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  103. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  104. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  105. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  106. package/corpus/templates/content/vitest.config.ts +7 -1
  107. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  108. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  109. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
  110. package/corpus/templates/design/actions/generate-design.ts +98 -47
  111. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  112. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  114. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  115. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
  116. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  117. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  118. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
  119. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  120. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  121. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  122. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  123. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
  124. package/corpus/templates/design/app/i18n-data.ts +1 -0
  125. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  126. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  127. package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
  128. package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
  129. package/corpus/templates/design/app/pages/Index.tsx +2 -0
  130. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  131. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  132. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  134. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  135. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  136. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  137. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  138. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  139. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  140. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  141. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  142. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  143. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  144. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  145. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  146. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  147. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  148. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  149. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  152. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  153. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  154. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  155. package/corpus/templates/design/app/routes.ts +3 -1
  156. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  157. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  158. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  159. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  160. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  161. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  162. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  163. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  164. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  165. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  166. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  167. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  168. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  169. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  170. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  171. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  172. package/corpus/templates/design/package.json +2 -0
  173. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  174. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  175. package/corpus/templates/design/shared/pen-path.ts +37 -0
  176. package/corpus/templates/design/vitest.config.ts +7 -1
  177. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  178. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  179. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  180. package/corpus/templates/dispatch/app/routes.ts +3 -1
  181. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  182. package/corpus/templates/factory/.env.example +2 -7
  183. package/corpus/templates/factory/AGENTS.md +3 -0
  184. package/corpus/templates/factory/README.md +5 -3
  185. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  186. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  187. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  188. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  189. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  190. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  191. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  192. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  193. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  194. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  195. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  196. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  197. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  198. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  199. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  200. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  201. package/corpus/templates/factory/app/routes.ts +3 -1
  202. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  203. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  204. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  205. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  206. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  207. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  208. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  209. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  210. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  211. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  212. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  213. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  214. package/corpus/templates/factory/vitest.config.ts +17 -2
  215. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  216. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  217. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  218. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  219. package/corpus/templates/forms/vitest.config.ts +1 -0
  220. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  221. package/corpus/templates/macros/app/routes.ts +3 -1
  222. package/corpus/templates/macros/vitest.config.ts +6 -1
  223. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  224. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  225. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  226. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  227. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  228. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  229. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  230. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  231. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  232. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  233. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  234. package/corpus/templates/mail/app/routes.ts +3 -1
  235. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  236. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  237. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  238. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  239. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  240. package/corpus/templates/mail/server/onboarding.ts +66 -18
  241. package/corpus/templates/mail/vitest.config.ts +6 -1
  242. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  243. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  244. package/corpus/templates/plan/app/routes.ts +3 -1
  245. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  246. package/corpus/templates/plan/netlify.toml +1 -1
  247. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  248. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  249. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  250. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  252. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  253. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  254. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  255. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  256. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  257. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  258. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  259. package/corpus/templates/slides/app/routes.ts +3 -1
  260. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  261. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  262. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  263. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  264. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  265. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  266. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  267. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  268. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  269. package/corpus/templates/slides/tsconfig.json +5 -0
  270. package/corpus/templates/slides/vitest.config.ts +6 -1
  271. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  272. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  273. package/corpus/templates/tasks/app/routes.ts +3 -1
  274. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  275. package/corpus/templates/tasks/vitest.config.ts +7 -1
  276. package/dist/action.d.ts +91 -0
  277. package/dist/action.js +50 -0
  278. package/dist/agent/abort-reasons.d.ts +38 -0
  279. package/dist/agent/abort-reasons.js +49 -0
  280. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  281. package/dist/agent/engine/anthropic-engine.js +7 -5
  282. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  283. package/dist/agent/engine/first-event-timeout.js +67 -25
  284. package/dist/agent/production-agent.d.ts +23 -0
  285. package/dist/agent/production-agent.js +107 -102
  286. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  287. package/dist/agent/run-loop-with-resume.js +25 -40
  288. package/dist/agent/run-manager.js +5 -4
  289. package/dist/agent/run-store.d.ts +55 -0
  290. package/dist/agent/run-store.js +124 -1
  291. package/dist/agent/tool-search.js +2 -1
  292. package/dist/agent/types.d.ts +9 -4
  293. package/dist/app-config/configuration-error.d.ts +11 -0
  294. package/dist/app-config/configuration-error.js +14 -0
  295. package/dist/app-config/index.d.ts +1 -0
  296. package/dist/app-config/index.js +1 -0
  297. package/dist/app-config/integrations.d.ts +1 -0
  298. package/dist/app-config/integrations.js +10 -0
  299. package/dist/app-config/plugins.d.ts +34 -0
  300. package/dist/app-config/plugins.js +39 -0
  301. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  302. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  303. package/dist/app-config/schema.d.ts +16 -0
  304. package/dist/app-config/schema.js +2 -0
  305. package/dist/chat-threads/schema-migrations.js +20 -0
  306. package/dist/chat-threads/store.js +21 -4
  307. package/dist/cli/native-dependencies.d.ts +4 -0
  308. package/dist/cli/native-dependencies.js +15 -0
  309. package/dist/client/EnvironmentBadge.d.ts +1 -1
  310. package/dist/client/EnvironmentBadge.js +40 -5
  311. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  312. package/dist/client/MultiTabAssistantChat.js +35 -14
  313. package/dist/client/agent-chat/index.d.ts +1 -1
  314. package/dist/client/agent-chat/index.js +1 -1
  315. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  316. package/dist/client/agent-page/use-jobs.js +3 -5
  317. package/dist/client/agent-sidebar-state.js +3 -1
  318. package/dist/client/blocks/library/code-tabs.js +5 -0
  319. package/dist/client/blocks/library/code.js +1 -0
  320. package/dist/client/chat-first/apps-rail.js +2 -2
  321. package/dist/client/chat-model-groups.d.ts +12 -0
  322. package/dist/client/chat-model-groups.js +3 -2
  323. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  324. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  325. package/dist/client/integrations/index.d.ts +2 -0
  326. package/dist/client/integrations/index.js +2 -0
  327. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  328. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  329. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  330. package/dist/client/settings/SettingsTabsPage.js +10 -6
  331. package/dist/client/sharing/ShareButton.js +11 -2
  332. package/dist/client/use-chat-models.d.ts +6 -0
  333. package/dist/client/use-chat-models.js +10 -0
  334. package/dist/client/use-db-sync.js +27 -9
  335. package/dist/connections/catalog.d.ts +111 -9
  336. package/dist/connections/catalog.js +86 -30
  337. package/dist/db/create-get-db.js +18 -0
  338. package/dist/db/ddl-guard.d.ts +0 -4
  339. package/dist/db/ddl-guard.js +46 -0
  340. package/dist/deploy/build.d.ts +19 -0
  341. package/dist/deploy/build.js +190 -16
  342. package/dist/deploy/function-bundle.d.ts +45 -0
  343. package/dist/deploy/function-bundle.js +337 -0
  344. package/dist/deploy/workspace-deploy.js +19 -1
  345. package/dist/eject/workspace-connections.js +4 -0
  346. package/dist/email-catalog/registry.d.ts +4 -0
  347. package/dist/email-catalog/registry.js +79 -14
  348. package/dist/extensions/content-patch.js +14 -2
  349. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  350. package/dist/integrations/plugin.d.ts +10 -0
  351. package/dist/integrations/plugin.js +40 -6
  352. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  353. package/dist/jobs/actions/run-automation-now.js +11 -5
  354. package/dist/jobs/frontmatter.js +53 -2
  355. package/dist/jobs/run-now.d.ts +11 -1
  356. package/dist/jobs/run-now.js +42 -7
  357. package/dist/jobs/scheduler.d.ts +1 -0
  358. package/dist/jobs/scheduler.js +2 -1
  359. package/dist/localization/core-messages/ar-SA.js +3 -0
  360. package/dist/localization/core-messages/de-DE.js +3 -0
  361. package/dist/localization/core-messages/en-US.d.ts +3 -0
  362. package/dist/localization/core-messages/en-US.js +3 -0
  363. package/dist/localization/core-messages/es-ES.js +3 -0
  364. package/dist/localization/core-messages/fr-FR.js +3 -0
  365. package/dist/localization/core-messages/hi-IN.js +3 -0
  366. package/dist/localization/core-messages/ja-JP.js +3 -0
  367. package/dist/localization/core-messages/ko-KR.js +3 -0
  368. package/dist/localization/core-messages/pt-BR.js +3 -0
  369. package/dist/localization/core-messages/zh-CN.js +3 -0
  370. package/dist/localization/core-messages/zh-TW.js +3 -0
  371. package/dist/localization/core-messages.d.ts +3 -0
  372. package/dist/localization/default-messages.d.ts +2 -5
  373. package/dist/localization/default-messages.js +2 -5
  374. package/dist/mcp/build-server.d.ts +9 -0
  375. package/dist/mcp/build-server.js +37 -8
  376. package/dist/mcp-client/oauth-client.d.ts +7 -0
  377. package/dist/mcp-client/oauth-client.js +12 -1
  378. package/dist/oauth-tokens/index.d.ts +1 -1
  379. package/dist/oauth-tokens/index.js +1 -1
  380. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  381. package/dist/oauth-tokens/lifecycle.js +17 -0
  382. package/dist/oauth-tokens/store.js +7 -0
  383. package/dist/observability/posthog-ai.d.ts +15 -1
  384. package/dist/observability/posthog-ai.js +24 -12
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/observability/traces.js +158 -28
  387. package/dist/onboarding/app-profile.js +2 -2
  388. package/dist/onboarding/plugin.js +10 -2
  389. package/dist/onboarding/types.d.ts +2 -0
  390. package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
  391. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  392. package/dist/provider-api/index.js +2 -0
  393. package/dist/resources/store.js +13 -4
  394. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  395. package/dist/secrets/register-framework-secrets.js +1 -1
  396. package/dist/server/action-discovery.js +5 -0
  397. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  398. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  399. package/dist/server/agent-chat-plugin.js +36 -9
  400. package/dist/server/agent-discovery.js +43 -20
  401. package/dist/server/auth.js +18 -16
  402. package/dist/server/beta-opt-out-html.js +45 -4
  403. package/dist/server/better-auth-instance.d.ts +2 -1
  404. package/dist/server/better-auth-instance.js +23 -7
  405. package/dist/server/builder-design-systems.d.ts +4 -1
  406. package/dist/server/builder-design-systems.js +87 -6
  407. package/dist/server/builder-oauth.d.ts +1 -7
  408. package/dist/server/builder-oauth.js +80 -163
  409. package/dist/server/core-routes-plugin.d.ts +29 -0
  410. package/dist/server/core-routes-plugin.js +100 -20
  411. package/dist/server/default-plugins.d.ts +18 -0
  412. package/dist/server/default-plugins.js +22 -0
  413. package/dist/server/edge.d.ts +1 -0
  414. package/dist/server/edge.js +1 -0
  415. package/dist/server/framework-request-handler.js +31 -3
  416. package/dist/server/google-oauth.d.ts +3 -0
  417. package/dist/server/google-oauth.js +3 -0
  418. package/dist/server/index.d.ts +4 -4
  419. package/dist/server/index.js +3 -3
  420. package/dist/server/onboarding-html.js +37 -3
  421. package/dist/server/realtime-token.d.ts +1 -1
  422. package/dist/server/transcribe-voice.d.ts +1 -1
  423. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  424. package/dist/server/workspace-provider-oauth.js +72 -20
  425. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  426. package/dist/shared/agent-sidebar-url.js +1 -0
  427. package/dist/shared/environment-lanes.d.ts +2 -0
  428. package/dist/shared/environment-lanes.js +3 -1
  429. package/dist/shared/index.d.ts +3 -1
  430. package/dist/shared/index.js +3 -1
  431. package/dist/shared/surface-visibility.d.ts +31 -0
  432. package/dist/shared/surface-visibility.js +57 -0
  433. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  434. package/dist/templates/chat/app/routes.ts +3 -1
  435. package/dist/templates/chat/vitest.config.ts +8 -0
  436. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  437. package/dist/templates/default/app/routes.ts +3 -1
  438. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  439. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  440. package/dist/tracking/registry.d.ts +11 -0
  441. package/dist/tracking/registry.js +5 -2
  442. package/dist/triggers/actions.js +10 -3
  443. package/dist/usage/store.js +23 -3
  444. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  445. package/dist/vite/client.js +24 -5
  446. package/docs/content/actions-access-control.mdx +43 -4
  447. package/docs/content/actions-defining.mdx +16 -0
  448. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  449. package/docs/content/template-clips-developers.mdx +4 -4
  450. package/docs/content/template-clips.mdx +3 -1
  451. package/package.json +2 -2
  452. package/src/eject/workspace-connections.ts +4 -0
  453. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  454. package/src/templates/chat/app/routes.ts +3 -1
  455. package/src/templates/chat/vitest.config.ts +8 -0
  456. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  457. package/src/templates/default/app/routes.ts +3 -1
  458. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  459. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
@@ -2,8 +2,8 @@ import { randomUUID } from "node:crypto";
2
2
  import Ajv from "ajv";
3
3
  import { defineEventHandler, getHeader, setResponseHeader, setResponseStatus, getMethod, } from "h3";
4
4
  import { parseA2AAgentActivityPart } from "../a2a/activity.js";
5
- import { describeToolParameterSignature, isAgentActionStopError, stripUnsupportedSchemaKeywords, } from "../action.js";
6
- import { ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS, MAX_BACKGROUND_RUN_CONTINUATIONS, MAX_CONSECUTIVE_NO_PROGRESS_CONTINUATIONS, MAX_TURN_WALL_CLOCK_MS, MODEL_STREAM_NO_PROGRESS_TIMEOUT_MS, } from "../app-config/run-lifecycle-invariants.js";
5
+ import { describeToolParameterSignature, isActionHiddenFromEveryAgentSurface, isAgentActionStopError, stripUnsupportedSchemaKeywords, } from "../action.js";
6
+ import { MAX_BACKGROUND_RUN_CONTINUATIONS, MAX_CONSECUTIVE_NO_PROGRESS_CONTINUATIONS, MAX_TURN_WALL_CLOCK_MS, } from "../app-config/run-lifecycle-invariants.js";
7
7
  import { readAppState } from "../application-state/script-helpers.js";
8
8
  import { isReadOnlyShellCommand } from "../coding-tools/index.js";
9
9
  import { getDbExec, isTransientDatabaseError } from "../db/client.js";
@@ -746,7 +746,6 @@ function maxRetriesForError(err) {
746
746
  return MAX_RETRIES;
747
747
  }
748
748
  const TOOL_INPUT_ACTIVITY_INTERVAL_MS = 1500;
749
- const ACTION_PREPARATION_ZERO_BYTE_RESTART_LIMIT = 2;
750
749
  /**
751
750
  * How long an attempt must have run before its retry is worth narrating.
752
751
  *
@@ -2187,7 +2186,10 @@ export function actionsToEngineTools(actions) {
2187
2186
  */
2188
2187
  export async function executeAgentToolCall(options) {
2189
2188
  const entry = options.actions[options.name];
2190
- if (!entry || entry.agentTool === false) {
2189
+ // The caller's registry is the surface: A2A hands this the external one, so
2190
+ // reject only what no surface may run — an MCP-only action is `agentTool:
2191
+ // false` and still legitimately callable here.
2192
+ if (!entry || isActionHiddenFromEveryAgentSurface(entry)) {
2191
2193
  return {
2192
2194
  status: "failed",
2193
2195
  output: `Unknown or unavailable tool: ${options.name}`,
@@ -3286,12 +3288,22 @@ export async function runAgentLoop(opts) {
3286
3288
  : 0;
3287
3289
  // A per-tool timeout above the chunk's own soft timeout can never fire — the
3288
3290
  // chunk boundary always wins — so the 12-minute default is dead code on a
3289
- // ~40s hosted foreground chunk. Background-function runs resolve to a ~13min
3290
- // ceiling and keep the default unchanged.
3291
- const runToolTimeoutCeilingMs = resolveRunToolTimeoutCeilingMs(resolveRunSoftTimeoutMs(undefined, {
3292
- useHostedDefault: true,
3293
- backgroundFunction: isInBackgroundFunctionRuntime(),
3294
- }));
3291
+ // ~40s hosted foreground chunk.
3292
+ //
3293
+ // TAKEN FROM THE CALLER'S ACTUAL BUDGET, not re-derived. Re-deriving it asked
3294
+ // `resolveRunSoftTimeoutMs` for the generic background ceiling (13 min) even
3295
+ // when the caller was a background AUTOMATION, whose real budget is its own
3296
+ // hard abort minus headroom (10 min − 20s = 9m40s via
3297
+ // `resolveBackgroundAutomationSoftTimeoutMs`). The ceiling came out ABOVE the
3298
+ // run budget, so every per-tool timeout on that path was dead code and the
3299
+ // chunk boundary won instead — which is the exact failure
3300
+ // `RUN_TOOL_TIMEOUT_HEADROOM_MS` exists to prevent, reintroduced by guessing
3301
+ // at a number the caller already knew.
3302
+ const runToolTimeoutCeilingMs = resolveRunToolTimeoutCeilingMs(opts.runSoftTimeoutMs ??
3303
+ resolveRunSoftTimeoutMs(undefined, {
3304
+ useHostedDefault: true,
3305
+ backgroundFunction: isInBackgroundFunctionRuntime(),
3306
+ }));
3295
3307
  const toolCallHistory = [];
3296
3308
  const sourceSweepToolCallHistory = seedSourceSweepToolCallsFromHistory(messages, actions);
3297
3309
  let sourceSweepDelegationGuardActive = hasExhaustedSourceSweepBudget({
@@ -3495,7 +3507,6 @@ export async function runAgentLoop(opts) {
3495
3507
  const toolInputBytes = new Map();
3496
3508
  let lastToolInputActivityAt = 0;
3497
3509
  const activeToolInputs = new Map();
3498
- let zeroByteToolInputRestart;
3499
3510
  let endedForNoProgress = false;
3500
3511
  // Bracket the engine call for the run manager's no-progress backstop
3501
3512
  // (`inFlightWorkDelta` in run-manager.ts). That backstop measures the
@@ -3547,48 +3558,55 @@ export async function runAgentLoop(opts) {
3547
3558
  ...(typeof progressBytes === "number" ? { progressBytes } : {}),
3548
3559
  });
3549
3560
  };
3550
- const actionPreparationDeadlineAt = () => {
3551
- let deadlineAt = Number.POSITIVE_INFINITY;
3552
- if (zeroByteToolInputRestart) {
3553
- deadlineAt = Math.min(deadlineAt, zeroByteToolInputRestart.firstStartedAt +
3554
- ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS);
3555
- }
3556
- let earliestStartedAt = Number.POSITIVE_INFINITY;
3557
- let latestPositiveProgressAt = 0;
3558
- for (const active of activeToolInputs.values()) {
3559
- if (active.startedAt < earliestStartedAt) {
3560
- earliestStartedAt = active.startedAt;
3561
- }
3562
- if (active.bytes > 0 &&
3563
- active.lastProgressAt > latestPositiveProgressAt) {
3564
- latestPositiveProgressAt = active.lastProgressAt;
3565
- }
3566
- }
3567
- const progressAt = latestPositiveProgressAt > 0
3568
- ? latestPositiveProgressAt
3569
- : earliestStartedAt;
3570
- if (Number.isFinite(progressAt)) {
3571
- deadlineAt = Math.min(deadlineAt, progressAt + ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS);
3572
- }
3573
- return Number.isFinite(deadlineAt) ? deadlineAt : undefined;
3574
- };
3575
- const modelStreamNoProgressDeadlineAt = () => {
3576
- const baseDeadlineAt = lastModelStreamProgressAt + MODEL_STREAM_NO_PROGRESS_TIMEOUT_MS;
3577
- // FIX 2: cap the FIRST event's deadline tighter on the clamped
3578
- // foreground runtime — see FOREGROUND_FIRST_MODEL_EVENT_TIMEOUT_MS
3579
- // for the ordering invariant this protects.
3561
+ /**
3562
+ * The ONLY in-loop stall bound left, and it covers exactly one thing:
3563
+ * a model call whose stream opened and produced NOTHING AT ALL.
3564
+ *
3565
+ * WHAT WAS HERE, AND WHY IT IS GONE. Two 90s watchdogs used to run for
3566
+ * the whole stream — one on silence between engine frames, one on a
3567
+ * tool input whose byte count stopped growing — plus a zero-byte
3568
+ * restart tripwire. Each inferred death from the ABSENCE of a
3569
+ * particular event, and that inference is unsound on this transport:
3570
+ * the Anthropic SDK drops the provider's `ping` keepalives before they
3571
+ * reach any consumer (`core/streaming.js`: `if (sse.event === 'ping')
3572
+ * continue;`, with no opt-out), so a healthy stream mid-generation is
3573
+ * byte-for-byte indistinguishable from a wedged one.
3574
+ *
3575
+ * That is not an edge case, it is normal operation. A tool whose input
3576
+ * is not eagerly streamed emits no `input_json_delta` at all while the
3577
+ * provider composes its arguments, so writing a large file or filing a
3578
+ * long structured result is a content-silent window whose length is set
3579
+ * by the size of the argument. Production bore it out: of 27 one-shot
3580
+ * analyst runs, 2 completed. Guards added for reliability were the
3581
+ * thing taking it away.
3582
+ *
3583
+ * WHAT STILL CATCHES A REAL WEDGE — none of which can fire on
3584
+ * slow-but-healthy work:
3585
+ * • the engine's own first-event abort
3586
+ * (`FIRST_STREAM_EVENT_TIMEOUT_MS`, 120s): a connection that opens
3587
+ * and never speaks
3588
+ * • the engine's total-stream deadline (`STREAM_TOTAL_TIMEOUT_MS`,
3589
+ * 14min): one model call end to end, which is what bounds a socket
3590
+ * that wedges MID-stream on the runtimes with no outer budget
3591
+ * (local dev and self-hosted resolve the soft timeout to 0)
3592
+ * • the run-manager backstop, for the segments OUTSIDE the stream
3593
+ * (`inFlightWorkDelta` suspends it while the stream is open)
3594
+ * • the per-tool timeout, which bounds tool EXECUTION at the tool
3595
+ * • the chunk / run budget, which bounds COST rather than health
3596
+ * • the stale reaper, which bounds worker liveness
3597
+ *
3598
+ * The cap below survives only because it guards the "nothing has
3599
+ * happened yet" window on the clamped hosted FOREGROUND runtime, where
3600
+ * the ~57s platform wall arrives before the engine's 120s bound could.
3601
+ * The first real frame releases it, so long thinking, long tool inputs
3602
+ * and long outputs are all past it by construction.
3603
+ */
3604
+ const noProgressDeadlineAt = () => {
3580
3605
  if (hasReceivedFirstEngineEvent ||
3581
3606
  !isClampedForegroundRuntimeForThisCall) {
3582
- return baseDeadlineAt;
3607
+ return Number.POSITIVE_INFINITY;
3583
3608
  }
3584
- return Math.min(baseDeadlineAt, lastModelStreamProgressAt + FOREGROUND_FIRST_MODEL_EVENT_TIMEOUT_MS);
3585
- };
3586
- const noProgressDeadlineAt = () => {
3587
- const actionDeadlineAt = actionPreparationDeadlineAt();
3588
- const modelDeadlineAt = modelStreamNoProgressDeadlineAt();
3589
- return actionDeadlineAt === undefined
3590
- ? modelDeadlineAt
3591
- : Math.min(actionDeadlineAt, modelDeadlineAt);
3609
+ return (lastModelStreamProgressAt + FOREGROUND_FIRST_MODEL_EVENT_TIMEOUT_MS);
3592
3610
  };
3593
3611
  const hasNoProgressStalled = () => Date.now() >= noProgressDeadlineAt();
3594
3612
  const checkpointNoProgress = () => {
@@ -3624,6 +3642,14 @@ export async function runAgentLoop(opts) {
3624
3642
  };
3625
3643
  const nextEngineEventWithNoProgressTimeout = async (iterator) => {
3626
3644
  const deadlineAt = noProgressDeadlineAt();
3645
+ // No deadline at all is the COMMON case now — every runtime except a
3646
+ // clamped hosted foreground call that has not yet seen its first
3647
+ // frame. Await the iterator directly rather than racing it: a
3648
+ // `setTimeout` of Infinity is coerced to 1ms by Node and would
3649
+ // checkpoint instantly, turning "no bound" into "the tightest bound
3650
+ // there is".
3651
+ if (!Number.isFinite(deadlineAt))
3652
+ return iterator.next();
3627
3653
  const timeoutMs = Math.max(0, deadlineAt - Date.now());
3628
3654
  if (timeoutMs <= 0) {
3629
3655
  checkpointNoProgress();
@@ -3662,37 +3688,6 @@ export async function runAgentLoop(opts) {
3662
3688
  bytes,
3663
3689
  });
3664
3690
  };
3665
- const resetZeroByteToolInputRestart = (toolName) => {
3666
- if (!zeroByteToolInputRestart)
3667
- return;
3668
- if (!toolName || zeroByteToolInputRestart.toolName === toolName) {
3669
- zeroByteToolInputRestart = undefined;
3670
- }
3671
- };
3672
- const noteZeroByteToolInputStart = (toolName) => {
3673
- if (!toolName)
3674
- return false;
3675
- const now = Date.now();
3676
- if (zeroByteToolInputRestart?.toolName === toolName) {
3677
- zeroByteToolInputRestart = {
3678
- ...zeroByteToolInputRestart,
3679
- lastStartedAt: now,
3680
- count: zeroByteToolInputRestart.count + 1,
3681
- };
3682
- }
3683
- else {
3684
- zeroByteToolInputRestart = {
3685
- toolName,
3686
- firstStartedAt: now,
3687
- lastStartedAt: now,
3688
- count: 1,
3689
- };
3690
- }
3691
- return (zeroByteToolInputRestart.count >=
3692
- ACTION_PREPARATION_ZERO_BYTE_RESTART_LIMIT &&
3693
- now - zeroByteToolInputRestart.firstStartedAt >=
3694
- ACTION_PREPARATION_NO_PROGRESS_TIMEOUT_MS);
3695
- };
3696
3691
  const eventIterator = eventStream[Symbol.asyncIterator]();
3697
3692
  let eventIteratorDone = false;
3698
3693
  openModelStreamBracket();
@@ -3734,7 +3729,6 @@ export async function runAgentLoop(opts) {
3734
3729
  }
3735
3730
  }
3736
3731
  if (event.type === "text-delta") {
3737
- resetZeroByteToolInputRestart();
3738
3732
  streamedAssistantText += event.text;
3739
3733
  send({ type: "text", text: event.text });
3740
3734
  }
@@ -3758,17 +3752,12 @@ export async function runAgentLoop(opts) {
3758
3752
  ...(event.id ? { id: event.id } : {}),
3759
3753
  });
3760
3754
  sendToolInputActivity(event.name, key, undefined, true);
3761
- if (noteZeroByteToolInputStart(event.name)) {
3762
- checkpointNoProgress();
3763
- break;
3764
- }
3765
3755
  }
3766
3756
  else if (event.type === "tool-input-delta") {
3767
3757
  const key = event.id ?? event.name;
3768
3758
  const toolName = event.name ??
3769
3759
  (event.id ? toolInputNames.get(event.id) : undefined);
3770
3760
  let progressBytes;
3771
- let startedZeroByteInput = false;
3772
3761
  if (key) {
3773
3762
  const hadByteRecord = toolInputBytes.has(key);
3774
3763
  const previous = hadByteRecord
@@ -3780,12 +3769,6 @@ export async function runAgentLoop(opts) {
3780
3769
  toolInputBytes.set(key, progressBytes);
3781
3770
  if (!hadByteRecord || progressBytes > previous) {
3782
3771
  trackActiveToolInput(key, toolName, progressBytes);
3783
- if (progressBytes > 0) {
3784
- resetZeroByteToolInputRestart();
3785
- }
3786
- else if (!hadByteRecord) {
3787
- startedZeroByteInput = true;
3788
- }
3789
3772
  }
3790
3773
  }
3791
3774
  if (event.text) {
@@ -3797,12 +3780,6 @@ export async function runAgentLoop(opts) {
3797
3780
  });
3798
3781
  }
3799
3782
  sendToolInputActivity(toolName, key, progressBytes);
3800
- if (startedZeroByteInput &&
3801
- toolName &&
3802
- noteZeroByteToolInputStart(toolName)) {
3803
- checkpointNoProgress();
3804
- break;
3805
- }
3806
3783
  }
3807
3784
  else if (event.type === "gateway-heartbeat") {
3808
3785
  send({ type: "stream_keepalive" });
@@ -7801,6 +7778,20 @@ export function createProductionAgentHandler(options) {
7801
7778
  backgroundFunction: false,
7802
7779
  }))
7803
7780
  : null;
7781
+ // The budget this run ACTUALLY executes inside, resolved once and used by
7782
+ // both `startRun` (which arms the chunk timer with it) and the agent loop
7783
+ // (which clamps per-tool timeouts under it). Resolving it only inside
7784
+ // `startRun` left the loop to re-derive a generic hosted/background
7785
+ // ceiling, so an app-configured chunk shorter than that ceiling got
7786
+ // per-tool timeouts longer than the chunk containing them — dead code, and
7787
+ // the chunk boundary won instead. `resolveRunSoftTimeoutMs` clamps an
7788
+ // already-resolved number to itself, so passing it back in is a no-op.
7789
+ const resolvedRunSoftTimeoutMs = resolveRunSoftTimeoutMs(selfChainBudget && !selfChainBudget.skipToBoundary
7790
+ ? selfChainBudget.softTimeoutMs
7791
+ : options.runSoftTimeoutMs, {
7792
+ useHostedDefault: true,
7793
+ backgroundFunction: runsInBackgroundFunction,
7794
+ });
7804
7795
  const startedRun = startRun(runId, effectiveThreadId, async (rawSend, signal) => {
7805
7796
  const send = (event) => {
7806
7797
  rawSend(event);
@@ -7895,6 +7886,15 @@ export function createProductionAgentHandler(options) {
7895
7886
  providerOptions: options.providerOptions,
7896
7887
  executionMode: requestMode,
7897
7888
  maxIterations: loopSettings.maxIterations,
7889
+ // Same `startRun` chunk and same signal as the main loop, so
7890
+ // the same budget. Left off, the loop re-derives the generic
7891
+ // hosted/background ceiling, which can sit above the chunk
7892
+ // these nested calls actually run inside — and then the
7893
+ // per-tool timeout is unreachable and the chunk boundary
7894
+ // preempts it.
7895
+ ...(resolvedRunSoftTimeoutMs > 0
7896
+ ? { runSoftTimeoutMs: resolvedRunSoftTimeoutMs }
7897
+ : {}),
7898
7898
  });
7899
7899
  // Attribute custom-agent sub-calls under their own label
7900
7900
  // so the Usage panel separates them from the main chat.
@@ -8054,6 +8054,13 @@ export function createProductionAgentHandler(options) {
8054
8054
  priorTurnInputTokens: turnInputTokens,
8055
8055
  finalResponseGuard: options.finalResponseGuard,
8056
8056
  finalResponseGuardRequestText: messageToPersist,
8057
+ // The chunk this loop is running inside, so a per-tool timeout is
8058
+ // clamped under the budget it can actually spend rather than under a
8059
+ // re-derived generic ceiling. `0` (local dev) keeps the loop's own
8060
+ // fallback.
8061
+ ...(resolvedRunSoftTimeoutMs > 0
8062
+ ? { runSoftTimeoutMs: resolvedRunSoftTimeoutMs }
8063
+ : {}),
8057
8064
  ...(options.toolLimits ? { toolLimits: options.toolLimits } : {}),
8058
8065
  ...(threadId
8059
8066
  ? { threadId: effectiveThreadId, turnId: effectiveTurnId }
@@ -8216,9 +8223,7 @@ export function createProductionAgentHandler(options) {
8216
8223
  // (durable-background worker, plain foreground POST) is unaffected:
8217
8224
  // `selfChainBudget` is `null` for them and this falls through to the
8218
8225
  // exact prior value.
8219
- softTimeoutMs: selfChainBudget && !selfChainBudget.skipToBoundary
8220
- ? selfChainBudget.softTimeoutMs
8221
- : options.runSoftTimeoutMs,
8226
+ softTimeoutMs: resolvedRunSoftTimeoutMs,
8222
8227
  useHostedSoftTimeoutDefault: true,
8223
8228
  // Lift the soft-timeout clamp to ~13min ONLY when this run is actually
8224
8229
  // executing inside a real Netlify `-background` function (15-min budget,
@@ -20,6 +20,7 @@
20
20
  * Both paths route through `appendAgentLoopContinuation` so the agent sees a
21
21
  * uniform "continue" instruction regardless of which recovery fired.
22
22
  */
23
+ import { SERVER_OWNED_ABORT_REASONS, clientAbortReason } from "./abort-reasons.js";
23
24
  import type { EngineMessage } from "./engine/types.js";
24
25
  import { runAgentLoop, type AgentLoopContinuationReason } from "./production-agent.js";
25
26
  import type { ResolveRunSoftTimeoutOptions, RunChunkControl } from "./run-manager.js";
@@ -38,34 +39,7 @@ export declare function appendDurableContinuationContext(messages: EngineMessage
38
39
  */
39
40
  export declare const MAX_BACKGROUND_RATE_LIMIT_CONTINUATIONS = 1;
40
41
  export declare const BACKGROUND_RATE_LIMIT_CONTINUATION_DELAY_MS = 20000;
41
- /**
42
- * Abort reasons the SERVER sets on a run's own controller. Everything else —
43
- * including any reason a client passes to the abort route — is a user Stop.
44
- *
45
- * Kept deliberately short. Each entry is a bound this package owns and can name
46
- * in a terminal outcome; if you are adding a fourth, check first whether the
47
- * bound belongs in `run-manager.ts` at all.
48
- *
49
- * Exported so the abort route can refuse these words from a client. That check
50
- * belongs at the boundary where untrusted input enters, not here: by the time a
51
- * reason reaches an `AbortSignal` it is just a string, and nothing downstream
52
- * can tell who wrote it.
53
- */
54
- export declare const SERVER_OWNED_ABORT_REASONS: Set<string>;
55
- /**
56
- * The abort reason to record for a client-initiated Stop.
57
- *
58
- * A caller reaching the abort route is a person pressing Stop, so it must not
59
- * be able to name a bound only the server can reach: the terminal outcome keys
60
- * off the abort reason, and a client sending `background_automation_hard_timeout`
61
- * would file its own Stop as a server-side failure. Anything unrecognised,
62
- * malformed, or reserved falls back to `"user"`.
63
- *
64
- * Normalised here rather than in the route because this is where the meaning of
65
- * the string is decided — downstream it is just a string, and nothing can tell
66
- * who wrote it.
67
- */
68
- export declare function clientAbortReason(raw: unknown): string;
42
+ export { SERVER_OWNED_ABORT_REASONS, clientAbortReason };
69
43
  /** Machine-readable code carried on the give-up terminal `error` event so the
70
44
  * client renders a loud "stopped before finishing" terminal instead of an
71
45
  * ambiguous silent stall. Deliberately NOT in the client's auto-recoverable
@@ -21,6 +21,7 @@
21
21
  * uniform "continue" instruction regardless of which recovery fired.
22
22
  */
23
23
  import { MAX_BACKGROUND_RUN_LOOP_CONTINUATIONS, MAX_RUN_LOOP_CONTINUATIONS, } from "../app-config/run-lifecycle-invariants.js";
24
+ import { SERVER_OWNED_ABORT_REASONS, clientAbortReason, } from "./abort-reasons.js";
24
25
  import { runAgentLoop, appendAgentLoopContinuation, isResumableEngineError, isTransientProviderRateLimitError, continuationReasonForResumableError, lastUnfinishedPreparingActionToolFromEvents, resolveFinalResponseGuardRequestText, SELF_CHAIN_MIN_CONTINUATION_BUDGET_MS, } from "./production-agent.js";
25
26
  import { resolveRunSoftTimeoutMs } from "./run-manager.js";
26
27
  import { getCurrentTurnEventsForThread } from "./run-store.js";
@@ -194,45 +195,10 @@ function waitForBackgroundRateLimitCooldown(signal) {
194
195
  signal.addEventListener("abort", finish, { once: true });
195
196
  });
196
197
  }
197
- /**
198
- * Abort reasons the SERVER sets on a run's own controller. Everything else —
199
- * including any reason a client passes to the abort route — is a user Stop.
200
- *
201
- * Kept deliberately short. Each entry is a bound this package owns and can name
202
- * in a terminal outcome; if you are adding a fourth, check first whether the
203
- * bound belongs in `run-manager.ts` at all.
204
- *
205
- * Exported so the abort route can refuse these words from a client. That check
206
- * belongs at the boundary where untrusted input enters, not here: by the time a
207
- * reason reaches an `AbortSignal` it is just a string, and nothing downstream
208
- * can tell who wrote it.
209
- */
210
- export const SERVER_OWNED_ABORT_REASONS = new Set([
211
- "no_progress",
212
- "run_timeout",
213
- "background_automation_hard_timeout",
214
- ]);
215
- /**
216
- * The abort reason to record for a client-initiated Stop.
217
- *
218
- * A caller reaching the abort route is a person pressing Stop, so it must not
219
- * be able to name a bound only the server can reach: the terminal outcome keys
220
- * off the abort reason, and a client sending `background_automation_hard_timeout`
221
- * would file its own Stop as a server-side failure. Anything unrecognised,
222
- * malformed, or reserved falls back to `"user"`.
223
- *
224
- * Normalised here rather than in the route because this is where the meaning of
225
- * the string is decided — downstream it is just a string, and nothing can tell
226
- * who wrote it.
227
- */
228
- export function clientAbortReason(raw) {
229
- if (typeof raw !== "string")
230
- return "user";
231
- const reason = raw.trim();
232
- if (!/^[a-z0-9_-]{1,64}$/i.test(reason))
233
- return "user";
234
- return SERVER_OWNED_ABORT_REASONS.has(reason.toLowerCase()) ? "user" : reason;
235
- }
198
+ // Re-exported from the leaf module so existing importers keep working. Callers
199
+ // that need ONLY these two symbols must import `./abort-reasons.js` directly —
200
+ // reaching them through this module drags the whole run loop into their graph.
201
+ export { SERVER_OWNED_ABORT_REASONS, clientAbortReason };
236
202
  /** Machine-readable code carried on the give-up terminal `error` event so the
237
203
  * client renders a loud "stopped before finishing" terminal instead of an
238
204
  * ambiguous silent stall. Deliberately NOT in the client's auto-recoverable
@@ -268,8 +234,19 @@ export async function runAgentLoopDirectWithSoftTimeout(opts, softTimeoutMs, tim
268
234
  control) {
269
235
  const finalResponseGuardRequestText = opts.finalResponseGuardRequestText ??
270
236
  resolveFinalResponseGuardRequestText(opts.messages);
271
- const stableOpts = { ...opts, finalResponseGuardRequestText };
272
237
  const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs, timeoutOptions);
238
+ // Hand the loop the budget it is ACTUALLY running inside, so a per-tool
239
+ // timeout is clamped under this chunk rather than under a re-derived generic
240
+ // ceiling. A background automation's budget is its own hard abort minus
241
+ // headroom and is materially smaller than the background chat ceiling; the
242
+ // loop had no way to know that and guessed high, which made every per-tool
243
+ // timeout on that path unreachable. `0` means "no soft-timeout regime"
244
+ // (local dev), where the loop's own fallback is the right answer.
245
+ const stableOpts = {
246
+ ...opts,
247
+ finalResponseGuardRequestText,
248
+ ...(timeoutMs > 0 ? { runSoftTimeoutMs: timeoutMs } : {}),
249
+ };
273
250
  let finalOutcomeReported = false;
274
251
  const reportFinalOutcome = (outcome) => {
275
252
  if (finalOutcomeReported)
@@ -475,6 +452,14 @@ control) {
475
452
  let attemptOutcome;
476
453
  const nextUsage = await runAgentLoop({
477
454
  ...stableOpts,
455
+ // THIS round's budget, not the invocation's. `stableOpts` carries the
456
+ // full `timeoutMs`, but round 2+ runs inside `roundTimeoutMs` — what
457
+ // is left after the earlier rounds spent wall-clock. Clamping a
458
+ // per-tool timeout against the full window puts it above the round
459
+ // that contains it, so the round timer wins and the per-tool timeout
460
+ // is unreachable — the same inversion `RUN_TOOL_TIMEOUT_HEADROOM_MS`
461
+ // exists to prevent, one scope down.
462
+ runSoftTimeoutMs: roundTimeoutMs,
478
463
  send,
479
464
  signal: controller.signal,
480
465
  onOutcome: (outcome) => {
@@ -140,10 +140,11 @@ export function resolveRunNoProgressTimeoutMs(params) {
140
140
  * Every pair listed here suspends the no-progress backstop for as long as it is
141
141
  * open, so each one MUST be bounded by a watchdog of its own — tool calls by
142
142
  * the per-tool timeout, cross-app calls by the A2A poll timeout, the model
143
- * stream by `MODEL_STREAM_NO_PROGRESS_TIMEOUT_MS`, which the agent loop races
144
- * against every wait for the next engine frame. A pair added here without such
145
- * a bound turns the backstop off for the rest of the run, which is strictly
146
- * worse than the stall it was meant to catch.
143
+ * stream by the engine's own first-event abort plus the chunk budget (the 90s
144
+ * in-loop watchdog that used to sit here is gone — see
145
+ * run-lifecycle-invariants.ts). A pair added here without SOME bound turns the
146
+ * backstop off for the rest of the run, which is strictly worse than the stall
147
+ * it was meant to catch.
147
148
  *
148
149
  * Note what that leaves: the model-stream bound covers waiting for the engine,
149
150
  * not a hang while the loop processes a frame it already has. Nothing here
@@ -268,6 +268,43 @@ export declare function insertRun(id: string, threadId: string, turnId?: string,
268
268
  */
269
269
  dispatchPayload?: string;
270
270
  }): Promise<void>;
271
+ /**
272
+ * Which stale window the reaper applied to a row, in ms.
273
+ *
274
+ * MIRRORS `backgroundAwareStaleCutoffSql`, which decides the same thing in SQL
275
+ * because it has to run inside the conditional UPDATE. Kept beside it and
276
+ * covered by a test asserting the three cases agree — a drift here reports the
277
+ * wrong window on a real incident, which is worse than reporting none.
278
+ */
279
+ export declare function staleWindowMsForRow(row: {
280
+ dispatchMode?: string | null;
281
+ hasDispatchPayload?: boolean;
282
+ maxStaleMs?: number;
283
+ }): number;
284
+ /**
285
+ * The liveness forensics for one reap, as a compact `key=value` line.
286
+ *
287
+ * THE FIELD THAT MATTERS IS `hbAheadOfProgress`. A worker that died takes its
288
+ * heartbeat with it, so heartbeat and last-progress stop together and this is
289
+ * ~0. A worker still running while the agent loop stops producing keeps
290
+ * heartbeating, and this grows without bound — those are opposite bugs that
291
+ * look identical in `agent_runs` today. Production showed runs where the
292
+ * heartbeat ran 3,000s past the last progress; nothing recorded that, so
293
+ * nothing could act on it.
294
+ *
295
+ * Numbers, booleans and an enum only — no prompt, no result, no user content —
296
+ * so this obeys the same privacy rule as event properties and log lines.
297
+ */
298
+ export declare function describeStaleReap(row: {
299
+ startedAt?: number | null;
300
+ heartbeatAt?: number | null;
301
+ lastProgressAt?: number | null;
302
+ inFlightSince?: number | null;
303
+ dispatchMode?: string | null;
304
+ hasDispatchPayload?: boolean;
305
+ maxStaleMs?: number;
306
+ now: number;
307
+ }): string;
271
308
  /**
272
309
  * Atomically claim a background-dispatched run for processing. The foreground
273
310
  * POST inserts the run row with `dispatch_mode = 'background'`; the FIRST
@@ -480,6 +517,24 @@ export declare const RUN_DIAG_STAGE: {
480
517
  * no boundary previously recorded anywhere.
481
518
  */
482
519
  readonly runBoundaryReached: "run_boundary_reached";
520
+ /**
521
+ * A stale reaper flipped this run to `errored`. Detail carries the liveness
522
+ * forensics — see `describeStaleReap`.
523
+ *
524
+ * WHY THIS EXISTS. `stale_run` is the single largest terminal outcome on the
525
+ * one-shot automation path (14 of 27 runs in one production deployment) and
526
+ * the row records nothing about WHY: `error_detail` is a fixed sentence for
527
+ * every reap, so a correct reap and a false one are indistinguishable after
528
+ * the fact. Every question worth asking needed a number nobody stored — was
529
+ * the worker dead, or was it heartbeating happily while the loop stopped
530
+ * producing? which of the three stale windows fired? was the in-flight grace
531
+ * in play? One production run heartbeated 3,309s past a 600s hard abort and
532
+ * there is no way to tell from the row what kept it alive.
533
+ *
534
+ * Diagnostics only: nothing reads this to make a decision, and it cannot
535
+ * change whether a row is reaped.
536
+ */
537
+ readonly staleRunReaped: "stale_run_reaped";
483
538
  };
484
539
  export type RunDiagStage = (typeof RUN_DIAG_STAGE)[keyof typeof RUN_DIAG_STAGE];
485
540
  /**