@agent-native/core 0.69.0 → 0.70.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/README.md +15 -15
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +109 -0
  4. package/corpus/core/docs/design/durable-agent-runs.md +217 -0
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/action.ts +89 -0
  7. package/corpus/core/src/agent/model-config.ts +0 -2
  8. package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
  9. package/corpus/core/src/changelog/parse.ts +245 -0
  10. package/corpus/core/src/cli/changelog.ts +199 -0
  11. package/corpus/core/src/cli/index.ts +19 -0
  12. package/corpus/core/src/cli/recap.ts +24 -1
  13. package/corpus/core/src/cli/skills.ts +74 -47
  14. package/corpus/core/src/client/AgentPanel.tsx +5 -3
  15. package/corpus/core/src/client/AssistantChat.tsx +8 -0
  16. package/corpus/core/src/client/CommandMenu.tsx +183 -75
  17. package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
  18. package/corpus/core/src/client/analytics.ts +181 -0
  19. package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
  20. package/corpus/core/src/client/client-surface.ts +41 -0
  21. package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
  22. package/corpus/core/src/client/feedback-context.ts +4 -0
  23. package/corpus/core/src/client/index.ts +12 -0
  24. package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
  25. package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
  26. package/corpus/core/src/client/sse-event-processor.ts +7 -1
  27. package/corpus/core/src/mcp/build-server.ts +57 -1
  28. package/corpus/core/src/mcp/embed-app.ts +197 -7
  29. package/corpus/core/src/mcp/oauth-route.ts +109 -13
  30. package/corpus/core/src/server/attribution.ts +211 -0
  31. package/corpus/core/src/server/auth.ts +6 -0
  32. package/corpus/core/src/server/better-auth-instance.ts +49 -5
  33. package/corpus/core/src/server/builder-browser.ts +27 -1
  34. package/corpus/core/src/server/core-routes-plugin.ts +136 -0
  35. package/corpus/core/src/server/google-oauth.ts +19 -6
  36. package/corpus/core/src/server/onboarding-html.ts +35 -0
  37. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  38. package/corpus/core/src/styles/agent-conversation.css +21 -0
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  40. package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  42. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
  43. package/corpus/templates/analytics/AGENTS.md +8 -1
  44. package/corpus/templates/analytics/CHANGELOG.md +10 -0
  45. package/corpus/templates/analytics/actions/install-dashboard-template.ts +99 -4
  46. package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
  47. package/corpus/templates/analytics/actions/update-dashboard.ts +39 -8
  48. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
  49. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
  50. package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -3
  51. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
  52. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -215
  53. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -6
  54. package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
  55. package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
  56. package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
  57. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
  58. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
  59. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
  60. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
  61. package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
  62. package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
  63. package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
  64. package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
  65. package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
  66. package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
  68. package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
  69. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
  70. package/corpus/templates/analytics/server/db/index.ts +1 -1
  71. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
  72. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
  73. package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
  74. package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
  75. package/corpus/templates/assets/CHANGELOG.md +10 -0
  76. package/corpus/templates/assets/actions/generate-image.ts +24 -0
  77. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
  78. package/corpus/templates/assets/app/global.css +17 -1
  79. package/corpus/templates/assets/app/root.tsx +7 -1
  80. package/corpus/templates/assets/app/routes/_index.tsx +94 -14
  81. package/corpus/templates/assets/app/routes/settings.tsx +6 -0
  82. package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
  83. package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
  84. package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
  85. package/corpus/templates/brain/CHANGELOG.md +10 -0
  86. package/corpus/templates/brain/app/root.tsx +7 -1
  87. package/corpus/templates/brain/app/routes/settings.tsx +8 -1
  88. package/corpus/templates/calendar/CHANGELOG.md +10 -0
  89. package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
  90. package/corpus/templates/calendar/app/root.tsx +7 -1
  91. package/corpus/templates/chat/CHANGELOG.md +10 -0
  92. package/corpus/templates/chat/app/root.tsx +7 -1
  93. package/corpus/templates/clips/CHANGELOG.md +10 -0
  94. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
  95. package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
  96. package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
  97. package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
  98. package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
  99. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
  100. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
  101. package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
  102. package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
  103. package/corpus/templates/clips/app/root.tsx +7 -1
  104. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
  105. package/corpus/templates/clips/app/routes/record.tsx +78 -5
  106. package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
  107. package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
  111. package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
  112. package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
  113. package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
  114. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
  115. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
  116. package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
  117. package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
  118. package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
  119. package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
  120. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
  121. package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
  122. package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
  123. package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
  124. package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
  125. package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
  126. package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
  127. package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
  128. package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
  129. package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
  130. package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
  131. package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
  132. package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
  133. package/corpus/templates/clips/desktop/src/main.tsx +3 -0
  134. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
  135. package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
  136. package/corpus/templates/clips/desktop/src/styles.css +119 -2
  137. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
  138. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +140 -1
  139. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
  140. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
  141. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +85 -6
  142. package/corpus/templates/clips/shared/share-attribution.ts +79 -0
  143. package/corpus/templates/content/AGENTS.md +20 -3
  144. package/corpus/templates/content/CHANGELOG.md +10 -0
  145. package/corpus/templates/content/actions/_database-utils.ts +15 -0
  146. package/corpus/templates/content/actions/_property-utils.ts +371 -4
  147. package/corpus/templates/content/actions/configure-document-property.ts +35 -1
  148. package/corpus/templates/content/actions/create-content-database.ts +5 -1
  149. package/corpus/templates/content/actions/delete-document-property.ts +52 -2
  150. package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
  151. package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
  152. package/corpus/templates/content/actions/set-document-property.ts +39 -0
  153. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
  154. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
  155. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
  156. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
  157. package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
  158. package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
  159. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
  160. package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
  161. package/corpus/templates/content/app/global.css +9 -0
  162. package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
  163. package/corpus/templates/content/app/root.tsx +7 -1
  164. package/corpus/templates/content/server/db/schema.ts +30 -0
  165. package/corpus/templates/content/server/plugins/db.ts +87 -0
  166. package/corpus/templates/content/shared/api.ts +7 -0
  167. package/corpus/templates/content/shared/properties.ts +109 -0
  168. package/corpus/templates/design/CHANGELOG.md +10 -0
  169. package/corpus/templates/design/actions/generate-design.ts +4 -0
  170. package/corpus/templates/design/app/root.tsx +7 -1
  171. package/corpus/templates/design/app/routes/settings.tsx +10 -2
  172. package/corpus/templates/dispatch/CHANGELOG.md +10 -0
  173. package/corpus/templates/dispatch/app/root.tsx +7 -1
  174. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
  175. package/corpus/templates/forms/CHANGELOG.md +10 -0
  176. package/corpus/templates/forms/actions/export-responses.ts +6 -0
  177. package/corpus/templates/forms/actions/list-responses.ts +2 -0
  178. package/corpus/templates/forms/actions/response-insights.ts +2 -0
  179. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
  180. package/corpus/templates/forms/app/root.tsx +7 -1
  181. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
  182. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
  183. package/corpus/templates/forms/server/db/schema.ts +7 -0
  184. package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
  185. package/corpus/templates/forms/server/lib/integrations.ts +76 -2
  186. package/corpus/templates/forms/server/plugins/db.ts +20 -0
  187. package/corpus/templates/forms/shared/types.ts +12 -0
  188. package/corpus/templates/macros/CHANGELOG.md +10 -0
  189. package/corpus/templates/macros/app/root.tsx +7 -1
  190. package/corpus/templates/mail/CHANGELOG.md +10 -0
  191. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
  192. package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
  193. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
  194. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
  195. package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
  196. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
  197. package/corpus/templates/plan/AGENTS.md +4 -0
  198. package/corpus/templates/plan/CHANGELOG.md +10 -0
  199. package/corpus/templates/plan/actions/view-screen.ts +5 -0
  200. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
  201. package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
  202. package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
  203. package/corpus/templates/plan/app/root.tsx +7 -1
  204. package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
  205. package/corpus/templates/plan/shared/share-attribution.ts +72 -0
  206. package/corpus/templates/slides/CHANGELOG.md +10 -0
  207. package/corpus/templates/slides/app/root.tsx +7 -1
  208. package/corpus/templates/videos/CHANGELOG.md +4 -151
  209. package/corpus/templates/videos/app/root.tsx +7 -1
  210. package/dist/action.js +87 -0
  211. package/dist/action.js.map +1 -1
  212. package/dist/agent/engine/builder-engine.d.ts +1 -1
  213. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  214. package/dist/agent/model-config.d.ts +2 -2
  215. package/dist/agent/model-config.d.ts.map +1 -1
  216. package/dist/agent/model-config.js +0 -2
  217. package/dist/agent/model-config.js.map +1 -1
  218. package/dist/agent/run-loop-with-resume.d.ts +13 -0
  219. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  220. package/dist/agent/run-loop-with-resume.js +44 -0
  221. package/dist/agent/run-loop-with-resume.js.map +1 -1
  222. package/dist/changelog/parse.d.ts +70 -0
  223. package/dist/changelog/parse.d.ts.map +1 -0
  224. package/dist/changelog/parse.js +200 -0
  225. package/dist/changelog/parse.js.map +1 -0
  226. package/dist/cli/changelog.d.ts +4 -0
  227. package/dist/cli/changelog.d.ts.map +1 -0
  228. package/dist/cli/changelog.js +166 -0
  229. package/dist/cli/changelog.js.map +1 -0
  230. package/dist/cli/index.js +18 -0
  231. package/dist/cli/index.js.map +1 -1
  232. package/dist/cli/recap.d.ts.map +1 -1
  233. package/dist/cli/recap.js +22 -1
  234. package/dist/cli/recap.js.map +1 -1
  235. package/dist/cli/skills.d.ts +3 -3
  236. package/dist/cli/skills.d.ts.map +1 -1
  237. package/dist/cli/skills.js +74 -47
  238. package/dist/cli/skills.js.map +1 -1
  239. package/dist/client/AgentPanel.d.ts.map +1 -1
  240. package/dist/client/AgentPanel.js +5 -3
  241. package/dist/client/AgentPanel.js.map +1 -1
  242. package/dist/client/AssistantChat.d.ts +6 -1
  243. package/dist/client/AssistantChat.d.ts.map +1 -1
  244. package/dist/client/AssistantChat.js +2 -2
  245. package/dist/client/AssistantChat.js.map +1 -1
  246. package/dist/client/CommandMenu.d.ts +17 -1
  247. package/dist/client/CommandMenu.d.ts.map +1 -1
  248. package/dist/client/CommandMenu.js +49 -13
  249. package/dist/client/CommandMenu.js.map +1 -1
  250. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  251. package/dist/client/agent-chat-adapter.js +43 -6
  252. package/dist/client/agent-chat-adapter.js.map +1 -1
  253. package/dist/client/analytics.d.ts +18 -0
  254. package/dist/client/analytics.d.ts.map +1 -1
  255. package/dist/client/analytics.js +177 -0
  256. package/dist/client/analytics.js.map +1 -1
  257. package/dist/client/changelog/Changelog.d.ts +47 -0
  258. package/dist/client/changelog/Changelog.d.ts.map +1 -0
  259. package/dist/client/changelog/Changelog.js +138 -0
  260. package/dist/client/changelog/Changelog.js.map +1 -0
  261. package/dist/client/client-surface.d.ts +17 -0
  262. package/dist/client/client-surface.d.ts.map +1 -0
  263. package/dist/client/client-surface.js +24 -0
  264. package/dist/client/client-surface.js.map +1 -0
  265. package/dist/client/composer/TiptapComposer.d.ts +26 -1
  266. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  267. package/dist/client/composer/TiptapComposer.js +27 -5
  268. package/dist/client/composer/TiptapComposer.js.map +1 -1
  269. package/dist/client/feedback-context.d.ts +3 -0
  270. package/dist/client/feedback-context.d.ts.map +1 -1
  271. package/dist/client/feedback-context.js +2 -0
  272. package/dist/client/feedback-context.js.map +1 -1
  273. package/dist/client/index.d.ts +3 -1
  274. package/dist/client/index.d.ts.map +1 -1
  275. package/dist/client/index.js +3 -1
  276. package/dist/client/index.js.map +1 -1
  277. package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
  278. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  279. package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
  280. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  281. package/dist/client/settings/useBuilderStatus.d.ts +2 -0
  282. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  283. package/dist/client/settings/useBuilderStatus.js +58 -10
  284. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  285. package/dist/client/sse-event-processor.d.ts.map +1 -1
  286. package/dist/client/sse-event-processor.js +7 -1
  287. package/dist/client/sse-event-processor.js.map +1 -1
  288. package/dist/mcp/build-server.d.ts +21 -0
  289. package/dist/mcp/build-server.d.ts.map +1 -1
  290. package/dist/mcp/build-server.js +43 -1
  291. package/dist/mcp/build-server.js.map +1 -1
  292. package/dist/mcp/embed-app.d.ts.map +1 -1
  293. package/dist/mcp/embed-app.js +197 -7
  294. package/dist/mcp/embed-app.js.map +1 -1
  295. package/dist/mcp/oauth-route.d.ts.map +1 -1
  296. package/dist/mcp/oauth-route.js +95 -12
  297. package/dist/mcp/oauth-route.js.map +1 -1
  298. package/dist/server/attribution.d.ts +83 -0
  299. package/dist/server/attribution.d.ts.map +1 -0
  300. package/dist/server/attribution.js +178 -0
  301. package/dist/server/attribution.js.map +1 -0
  302. package/dist/server/auth.d.ts.map +1 -1
  303. package/dist/server/auth.js +7 -0
  304. package/dist/server/auth.js.map +1 -1
  305. package/dist/server/better-auth-instance.d.ts +9 -1
  306. package/dist/server/better-auth-instance.d.ts.map +1 -1
  307. package/dist/server/better-auth-instance.js +32 -2
  308. package/dist/server/better-auth-instance.js.map +1 -1
  309. package/dist/server/builder-browser.d.ts +4 -0
  310. package/dist/server/builder-browser.d.ts.map +1 -1
  311. package/dist/server/builder-browser.js +20 -1
  312. package/dist/server/builder-browser.js.map +1 -1
  313. package/dist/server/core-routes-plugin.d.ts +25 -0
  314. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  315. package/dist/server/core-routes-plugin.js +101 -0
  316. package/dist/server/core-routes-plugin.js.map +1 -1
  317. package/dist/server/google-oauth.d.ts.map +1 -1
  318. package/dist/server/google-oauth.js +16 -2
  319. package/dist/server/google-oauth.js.map +1 -1
  320. package/dist/server/onboarding-html.d.ts.map +1 -1
  321. package/dist/server/onboarding-html.js +35 -0
  322. package/dist/server/onboarding-html.js.map +1 -1
  323. package/dist/shared/mcp-embed-headers.js +1 -1
  324. package/dist/shared/mcp-embed-headers.js.map +1 -1
  325. package/dist/styles/agent-conversation.css +21 -0
  326. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  327. package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  328. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  329. package/docs/design/durable-agent-runs.md +217 -0
  330. package/package.json +1 -1
  331. package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  332. package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  333. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  334. package/corpus/templates/analytics/app/pages/About.tsx +0 -108
  335. package/corpus/templates/analytics/app/routes/about.tsx +0 -9
  336. /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
package/README.md CHANGED
@@ -21,18 +21,6 @@ export default defineAction({
21
21
  - **Agent runtime**: Chat, tools, skills, memory, jobs, observability, and handoffs ship together.
22
22
  - **Backend agnostic**: Plug in any Drizzle-supported SQL database and Nitro-compatible host.
23
23
 
24
- ## Agents and UIs, Fully Connected
25
-
26
- The agent and the UI are equal citizens of one system. Every action works both ways: click it or ask for it.
27
-
28
- ![Agents and UIs fully connected](https://cdn.builder.io/api/v1/file/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fadc1e9e9368e4a8cb1b4dbb5aae5aaa2)
29
-
30
- - **Everything syncs**: One database, one state. Changes from either side show up instantly on the other.
31
- - **Real-time multiplayer**: Humans and agents edit the same document together, with the agent as a first-class peer.
32
- - **Context-aware**: The agent knows what you're looking at. Select text, hit Cmd+I, and tell it what to do.
33
- - **Agents call agents**: Tag another agent from any app and they coordinate over A2A.
34
- - **Self-improving**: The agent can add features, fix bugs, and refine the UI over time.
35
-
36
24
  ## Templates
37
25
 
38
26
  Start with a full featured template. Each one is a complete, 100% free and open-source SaaS app: cloneable, not scaffolded, except you own the code and can customize everything.
@@ -43,11 +31,11 @@ Start with a full featured template. Each one is a complete, 100% free and open-
43
31
 
44
32
  **Clips**
45
33
 
46
- <a href="https://agent-native.com/templates/clips"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F678be5a501a14ab8a508e5f7bc92c468?format=webp&width=800" alt="Clips template" width="100%" /></a>
34
+ <a href="https://agent-native.com/templates/clips"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F189ebd9b2f2b4f0ead3b33138d4e4c10?format=webp&width=800" alt="Clips template" width="100%" /></a>
47
35
 
48
- **Agent-Native Loom**
36
+ **Agent-Native Loom + Jam**
49
37
 
50
- Record your screen with auto-transcripts, shareable links, and an agent that summarizes, captions, and edits clips on demand.
38
+ Record your screen with auto-transcripts and captured browser debug logs, share a link, and let an agent read the transcript, see timestamped frames, and fix the bug.
51
39
 
52
40
  </td>
53
41
  <td width="33%" align="center" valign="top">
@@ -112,6 +100,18 @@ Connect analytics data sources, prompt for real charts, and build reusable dashb
112
100
 
113
101
  View the full template gallery at **[agent-native.com/templates](https://agent-native.com/templates)**.
114
102
 
103
+ ## Agents and UIs, Fully Connected
104
+
105
+ The agent and the UI are equal citizens of one system. Every action works both ways: click it or ask for it.
106
+
107
+ ![Agents and UIs fully connected](https://cdn.builder.io/api/v1/file/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fadc1e9e9368e4a8cb1b4dbb5aae5aaa2)
108
+
109
+ - **Everything syncs**: One database, one state. Changes from either side show up instantly on the other.
110
+ - **Real-time multiplayer**: Humans and agents edit the same document together, with the agent as a first-class peer.
111
+ - **Context-aware**: The agent knows what you're looking at. Select text, hit Cmd+I, and tell it what to do.
112
+ - **Agents call agents**: Tag another agent from any app and they coordinate over A2A.
113
+ - **Self-improving**: The agent can add features, fix bugs, and refine the UI over time.
114
+
115
115
  ## Try it with a skill
116
116
 
117
117
  Don't want to scaffold a whole app yet? Add visual planning and PR recaps to Claude Code, Codex, Cursor, Pi, OpenCode, GitHub Copilot / VS Code, and similar agents with one command:
package/corpus/README.md CHANGED
@@ -27,5 +27,5 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
27
27
 
28
28
  ## Generated Counts
29
29
 
30
- - core files: 1138
31
- - template files: 3945
30
+ - core files: 1146
31
+ - template files: 3993
@@ -1,5 +1,114 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.70.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8003c56: Coerce gateway-stringified tool arguments before action validation. Some model gateways (notably Builder's Gemini-backed gateway) hand structured tool-call arguments back as JSON strings — an array param arrives as `"[{...}]"`, a boolean as `"true"`. Standard Schema (zod) validation does not coerce, so these calls failed validation and the agent could thrash retrying different shapes (and hang). The validation wrapper now coerces a string value to the type its schema field declares (array/object via `JSON.parse`, boolean, number/integer) when — and only when — the schema expects a non-string type and the string parses cleanly to it; ambiguous or unparseable values are left untouched so the normal validation error still surfaces.
8
+ - 8003c56: Composer model picker improvements. The picker now supports an optional secondary "image model" menu via a new `imageModelMenu` prop on `AgentChatSurface` / `AssistantChat` (opt-in; chat-only apps are unaffected) — apps that drive a separate generation model (e.g. Assets' image model) can surface it in the same dropdown so it's clear which model reasons about the request and which produces the output. The reasoning-effort list is now a collapsed-by-default accordion (matching the provider groups) instead of always-expanded, keeping the menu compact. Model catalog: the Builder gateway list now lists Opus 4.8 (was 4.7) and drops the retired GPT-5.1 Codex Mini entry.
9
+ - 8003c56: Remove the setup/onboarding checklist that appeared above the agent chat (the
10
+ "Setup N of 5" panel with Connect an AI engine / image & video generation /
11
+ asset storage / email / GitHub steps) and its header "Setup" re-open button.
12
+ Setup is now surfaced in better places — the settings panel and per-feature
13
+ setup affordances — so the panel no longer takes up sidebar space in any app.
14
+ - 8003c56: Feedback submissions now forward a `clientSurface` hint (web / electron / tauri)
15
+ alongside the existing page URL, so form owners can tell whether feedback came
16
+ from the Agent Native desktop app, a Tauri shell (e.g. Clips), or a browser.
17
+ Detection is exposed as a reusable `getClientSurface()` client helper and is
18
+ passed through as hidden metadata — it never appears as a visible form field.
19
+ - 8003c56: Fix the "Sign in with Google" button getting stuck disabled when the OAuth
20
+ window is closed without finishing (e.g. to retry in a different browser
21
+ profile). The button was only ever re-enabled on an explicit OAuth error or
22
+ the 5-minute poll timeout, so a cancelled sign-in left the primary CTA greyed
23
+ out with no way to retry short of refreshing. The sign-in screen now re-enables
24
+ the button (and stops the pending exchange poll) when the window regains focus
25
+ or becomes visible again — mirroring the existing email-verification recovery.
26
+ - 8003c56: Add observability and a safety valve for inline MCP App embeds, on top of the
27
+ Codex/Cursor transplant fix already shipped in 0.70.0.
28
+
29
+ When an inline embed cannot load in a host, the shell now reports a bounded,
30
+ structured diagnostic (stage, message, HTTP status, host, render mode, bridge
31
+ type) to a new CORS-open `POST /_agent-native/mcp/embed-error` route, which
32
+ forwards it to Sentry via `captureError` — so embed failures across Codex,
33
+ Cursor, ChatGPT, and Claude are inspectable instead of an opaque spinner. The
34
+ failure card also surfaces the specific cause (e.g. "Embedded app returned HTTP
35
+ 500" / session-expired) and promotes "Open in new tab" to the primary action.
36
+
37
+ Adds a deploy-toggleable kill switch for inline MCP App embeds, **off by
38
+ default**. Set `AGENT_NATIVE_MCP_APPS_INLINE=1` to enable inline embeds for an
39
+ environment; while it is off, accounts listed in
40
+ `AGENT_NATIVE_MCP_APPS_INLINE_ALLOW_EMAILS` (comma/space separated) still get
41
+ them, so a fix can be verified in production before it reaches normal users.
42
+ When disabled, no `ui://` resource is advertised or referenced and tool results
43
+ fall back to their deep-link text — no skills/instructions change required.
44
+
45
+ - 8003c56: Show a friendly "You're all set" confirmation page after authorizing an MCP
46
+ client whose redirect is a native deep link (cursor://, vscode://, …). Instead
47
+ of leaving the browser tab dangling on a blank page after the OS handed the code
48
+ to the app, the tab now shows a checkmark, a "return to your agent to continue"
49
+ message, and re-fires the deep link so the client still receives the code.
50
+ https/loopback callbacks keep the standard redirect.
51
+ - 8003c56: Clarify the "Where should visual plans and recaps live?" install prompt: move
52
+ the "(recommended)" marker into the hosted option's label and tighten its
53
+ description to "100% free and open source. Supports comments, browser editor,
54
+ and sharing. Requires one-time browser sign-in."
55
+ - 8003c56: When a hosted run is cut off mid-step and exhausts its in-invocation
56
+ continuation budget without finishing, the chat now ends with a loud,
57
+ unambiguous "stopped before finishing" terminal instead of a silent stall or a
58
+ misleading clean `done`. The terminal carries a machine-readable
59
+ `run_budget_exhausted` error code that is deliberately excluded from the
60
+ client's auto-recoverable allow-list, so the chain terminates rather than
61
+ looping another continuation into the same wall, and any half-streamed partial
62
+ text is cleared so the message stands alone.
63
+
64
+ ## 0.70.0
65
+
66
+ ### Minor Changes
67
+
68
+ - b35c8cb: Add an in-app changelog ("What's new") surface. Every app can now ship a
69
+ user-facing `CHANGELOG.md` that renders in the command menu (Cmd+K) and in
70
+ settings. Core provides `<ChangelogDialog>`, `<ChangelogSettingsCard>`, a
71
+ `changelog` prop on `CommandMenu` (with an unseen-release dot), and an
72
+ `agent-native changelog add|release|list` CLI that authors changeset-style
73
+ pending entry files and rolls them up into the dated `CHANGELOG.md`.
74
+
75
+ ### Patch Changes
76
+
77
+ - b35c8cb: Fix MCP app embeds for OpenAI's default web-sandbox origin and keep an Open in new tab fallback available when inline app loading fails.
78
+ - b35c8cb: Return native redirect responses from web OAuth callbacks so successful sign-ins
79
+ land on the clean return URL instead of retaining provider callback query
80
+ parameters.
81
+ - b35c8cb: Add a public `GET /_agent-native/health` route that runs a trivial `SELECT 1`
82
+ to report database liveness and, as a side effect, keep a scale-to-zero
83
+ serverless database (e.g. Neon) warm. A scheduled ping against this endpoint
84
+ prevents the multi-second cold-start that otherwise stalls the first request
85
+ to an idle app. The probe always responds (apps with no database report
86
+ `db: false` rather than failing) and is never cached. Disable it with the
87
+ `disableHealth` core-routes option.
88
+ - b35c8cb: Fix MCP app embeds rendering only a flashing/permanent loading state in Codex
89
+ and Cursor. These standards-track hosts render the `ui://` resource in a strict
90
+ opaque-origin sandbox (`sandbox="allow-scripts"`) and talk to it over the
91
+ postMessage `ui/*` bridge. The shell's handshake was already correct, but for
92
+ these hosts it fell through to self-navigating the sandboxed iframe to the real
93
+ app origin, which tears down the host bridge and loses the opaque-origin auth
94
+ context. Any host connected through the native MCP Apps bridge (Codex, Cursor,
95
+ the SDK App fallback, our own renderer) now transplants the app document into
96
+ the shell — the same robust path Claude already uses — keeping the bridge alive
97
+ and loading via embed-token auth. Also handle the spec `host-context-changed`
98
+ notification and bump the cached resource shell version so hosts refetch.
99
+ - b35c8cb: Fix the missing inline screenshot on PR Visual Recap comments. The `recap shot`
100
+ command runs `page.evaluate`/`addInitScript` payloads that contain named inner
101
+ functions; when the CLI is run through `tsx`/esbuild (CI's trusted-workspace
102
+ path), esbuild's `keepNames` wraps those functions in `__name(...)`, which
103
+ Playwright then serializes into the browser where `__name` is undefined —
104
+ throwing `ReferenceError: __name is not defined`, dropping the screenshot, and
105
+ falling back to a link-only comment. `runShot` now injects an identity `__name`
106
+ shim as the first browser init script, so every main-world payload is safe
107
+ regardless of how the CLI was transpiled (the tsc-built published package, which
108
+ never emits `__name`, is unaffected).
109
+ - b35c8cb: When a long agent run is cut off mid-stream while assembling one large tool input (a generation that exceeds the ~40s soft-timeout window), the auto-continue nudge now points the resumed model at the incremental-edit path for that specific action instead of only handling `create-extension`. Designs (`generate-design` → `edit-design`), plans (`create-visual-plan`/`create-ui-plan` → `update-visual-plan`/`patch-visual-plan-source`), and dashboards (`update-dashboard` incremental `ops`) get tailored "ship a compact first version, then refine" guidance, with a generic compact-first fallback for any other large-payload action. This breaks the re-stream-the-same-oversized-payload thrash loop that could otherwise burn the whole continuation budget without making progress.
110
+ - b35c8cb: Capture first-touch referral attribution and enrich the signup event (`referral_source`, `referrer_user`, UTM, `first_touch_path`) to measure app virality. The browser records an anonymous visitor's first-touch context (`ref`/`via`/`utm_*` params, landing path, and referring host) into an `an_attribution` localStorage key and a first-party `an_ft` cookie, and the server-side `signup` event is enriched from that cookie so every template can see where new users came from.
111
+
3
112
  ## 0.69.0
4
113
 
5
114
  ### Minor Changes
@@ -0,0 +1,217 @@
1
+ # Design: Durable / Checkpointed Agent Runs
2
+
3
+ Status: proposed
4
+ Owner: core / run-manager
5
+ Related code: `packages/core/src/agent/run-manager.ts`,
6
+ `packages/core/src/agent/engine/builder-engine.ts`
7
+
8
+ ## Problem
9
+
10
+ Hosted agent runs are bounded by a ~40s soft timeout enforced in
11
+ `run-manager.ts` (`DEFAULT_HOSTED_RUN_SOFT_TIMEOUT_MS = 40_000`, also the
12
+ `HOSTED_SOFT_TIMEOUT_CEILING_MS`). That budget is deliberate and correct: it
13
+ sits just under a stack of upstream walls that the framework does not control.
14
+
15
+ When the soft timeout fires, the run-manager aborts the current chunk, persists
16
+ the partial turn, writes a terminal event, and emits an `auto_continue` event
17
+ (`reason: "run_timeout"`) so the client transparently resumes the turn in a
18
+ fresh chunk. This works well for a single long model call that just needs more
19
+ wall-clock time.
20
+
21
+ It does **not** work well for long _multi-step_ operations. A turn that performs
22
+ many sequential side effects — for example an agent appending many dashboard
23
+ panels through many separate write calls, or any "do N independent mutations in
24
+ a loop" workflow — fails in a characteristic way:
25
+
26
+ - **Continuation thrash / re-hydration.** Each `auto_continue` chunk starts the
27
+ model over from the rebuilt context. If the work isn't expressed as resumable
28
+ progress, the model frequently re-reasons about and re-issues steps it already
29
+ attempted in the previous chunk instead of advancing. Successive chunks burn
30
+ their entire 40s budget re-deciding rather than completing new steps.
31
+ - **Partial or zero net progress.** Because each chunk can be cut mid-step and
32
+ the next chunk may redo earlier steps, the run can churn for many chunks while
33
+ the _persisted_ end state barely moves — or, when nothing reaches a committed
34
+ state before each cutoff, moves not at all.
35
+ - **Silent "looked-done" failure.** A tool call that returned a success marker
36
+ (✓) in an aborted chunk does not guarantee its effect was committed and
37
+ survived the cutoff. The model can reasonably believe a step succeeded, report
38
+ the whole task complete, and leave nothing (or only some rows) actually
39
+ persisted. The user is told it worked; the data says otherwise.
40
+
41
+ Net effect: long multi-step runs can spin indefinitely, never finish, and
42
+ terminate with an untruthful "done" state.
43
+
44
+ ## Goals
45
+
46
+ 1. Long multi-step runs **complete reliably** — they make monotonic forward
47
+ progress across continuation chunks rather than re-doing work.
48
+ 2. The user always gets a **truthful terminal state**: either "completed, here
49
+ is concrete proof (N of N persisted, ids …)", or an honest "did not finish,
50
+ here is what was committed (M of N) and what remains" — never a false
51
+ success.
52
+ 3. No change to the upstream walls and no raising of the 40s soft timeout (see
53
+ Guardrail).
54
+
55
+ ## Non-goals
56
+
57
+ - Raising or removing the soft timeout. It is correct; see Guardrail.
58
+ - Changing the gateway, serverless function limits, or model call timeout.
59
+ - Replacing `auto_continue`. Both approaches below build on it.
60
+
61
+ ## Guardrail: the 40s soft timeout is correct and must not be raised
62
+
63
+ `DEFAULT_HOSTED_RUN_SOFT_TIMEOUT_MS` / `HOSTED_SOFT_TIMEOUT_CEILING_MS` =
64
+ `40_000` is intentional headroom under the upstream hard walls. Raising it does
65
+ not buy more time — it just converts a graceful hand-off into a hard kill. The
66
+ walls, in order:
67
+
68
+ 1. **Builder model gateway hard cap — ~45s.**
69
+ `MAX_BUILDER_GATEWAY_TIMEOUT_MS = 45_000` in
70
+ `packages/core/src/agent/engine/builder-engine.ts`. A single model call is
71
+ killed at the gateway after 45s. **Not raisable** by the framework.
72
+ 2. **Serverless function kill — ~60–65s.** The hosting function is terminated
73
+ shortly after; the heartbeat then reaps the run row as `stale_run`.
74
+
75
+ 40s leaves ~5s under the gateway wall to abort, persist the partial turn, write
76
+ the terminal event, and emit a clean `auto_continue` so the client resumes. A
77
+ larger value (production saw per-template overrides like `240_000`) pushes the
78
+ cutoff past both walls, so `auto_continue` never fires and the run dies as
79
+ `builder_gateway_timeout` / `stale_run` instead. The ceiling clamp in
80
+ `resolveRunSoftTimeoutMs` exists precisely to defeat that footgun. **Do not
81
+ raise it. Fix durability above the timeout, not by moving the timeout.**
82
+
83
+ ## Approach options
84
+
85
+ Both options keep the 40s budget and build on the existing `auto_continue`
86
+ mechanism. They differ in _where the long work lives_.
87
+
88
+ ### Option A — Checkpointed / idempotent continuation
89
+
90
+ Keep the work inside the normal run/`auto_continue` loop, but make each
91
+ continuation chunk **resume from committed progress instead of restarting**.
92
+
93
+ Mechanism:
94
+
95
+ - **Persist a progress record** for the operation (a checkpoint): the planned
96
+ unit of work (the N items / steps), and which units are already committed.
97
+ This lives in SQL so it survives chunk boundaries and function recycling, the
98
+ same way run rows do.
99
+ - **Idempotent steps.** Each step keys off a stable identity so re-issuing a
100
+ completed step is a no-op (upsert by natural key, or "skip if checkpoint says
101
+ done"). Re-hydration after `auto_continue` then can't double-apply or
102
+ thrash — a redone step costs a cheap check, not a duplicate write.
103
+ - **Resume, don't replan.** On `auto_continue`, the next chunk reads the
104
+ checkpoint, skips committed units, and continues with the remainder. Progress
105
+ is monotonic: every chunk that does anything moves the committed count up.
106
+ - **Truthful terminal state from the checkpoint.** "Done" means the checkpoint
107
+ shows N of N committed. If the run is cut for good (e.g. it exhausts a
108
+ continuation budget), the checkpoint still reports M of N committed and the
109
+ exact remainder — so the terminal message is honest by construction.
110
+
111
+ Interaction with the walls and the 40s budget:
112
+
113
+ - Fully respects the 40s soft timeout and the gateway/function walls — it never
114
+ needs a single chunk to outlast them. It just makes the _sequence_ of chunks
115
+ productive.
116
+ - Works hand-in-glove with `auto_continue`: today a continuation can redo work;
117
+ with a checkpoint, a continuation can only advance.
118
+
119
+ Tradeoffs:
120
+
121
+ - Pro: smallest change to the runtime model; no new infrastructure; the user
122
+ keeps watching one live turn; degrades gracefully (even a half-finished run is
123
+ truthful and re-runnable).
124
+ - Pro: directly kills re-hydration thrash, the actual failure mode.
125
+ - Con: still bounded by however many continuation chunks the client/turn budget
126
+ allows. A truly enormous job (thousands of steps) can still run out of chunks
127
+ — but it now ends _truthfully partial and resumable_, not silently empty.
128
+ - Con: requires per-operation work to define the unit of progress and make
129
+ steps idempotent. Best paid down once at the primitive/action layer (see
130
+ Tie-in) so individual agents don't have to.
131
+
132
+ ### Option B — Out-of-band durable background execution
133
+
134
+ Hand a long run to a **queued background job** that executes beyond the
135
+ function/gateway lifetime and reports progress back into the run/event stream.
136
+
137
+ Mechanism:
138
+
139
+ - The foreground turn **enqueues** a durable job (the full operation + its
140
+ inputs) and returns immediately with "started, tracking as job X". The
141
+ user-facing run does not try to do the work itself within 40s.
142
+ - A durable worker (outside the per-request serverless function lifetime — e.g.
143
+ the core run-manager / agent-teams background infrastructure the framework
144
+ already mandates for background agents) runs the job to completion, free of
145
+ the 45s gateway cap and the ~60s function kill on the _original_ request.
146
+ - The worker **streams progress** (committed counts, ids, errors) back so the
147
+ UI and the agent can observe and the final state is truthful.
148
+
149
+ Interaction with the walls and the 40s budget:
150
+
151
+ - Sidesteps the gateway/function walls for the _long_ work by moving it off the
152
+ request path. The walls still apply to each individual model call the worker
153
+ makes, so the worker itself should checkpoint internally (i.e. Option B is
154
+ strongest when it contains Option A).
155
+ - `auto_continue` becomes a lightweight "is the job still running / what's its
156
+ progress" poll on the foreground turn rather than the vehicle for the work.
157
+
158
+ Tradeoffs:
159
+
160
+ - Pro: removes the hard ceiling on total operation length — genuinely large
161
+ jobs can finish.
162
+ - Pro: the foreground turn stays responsive and cheap; the user can leave and
163
+ come back.
164
+ - Con: more infrastructure and lifecycle complexity (job queue, durable worker,
165
+ progress fan-in, failure/retry semantics, surfacing job state in the UI and
166
+ to the agent).
167
+ - Con: changes the UX from "one live turn" to "fire-and-track"; needs clear
168
+ status surfacing so it doesn't become its own kind of silent failure.
169
+
170
+ ## Recommendation
171
+
172
+ Build **Option A first**, then layer **Option B** for the genuinely unbounded
173
+ cases. Option A delivers the most reliability per unit of effort: it directly
174
+ removes re-hydration thrash and silent looked-done failure for the common case
175
+ (tens of steps), needs no new infrastructure, and makes terminal state truthful
176
+ by construction. Option B is the right ceiling-remover but is a larger build and
177
+ is most valuable _on top of_ a checkpointed core (the durable worker should
178
+ itself checkpoint).
179
+
180
+ ### Phased plan
181
+
182
+ 1. **Phase 0 — Stop hitting the ceiling so often (near-term, cheapest).** Land
183
+ the mitigations in the Tie-in below (one-call atomic primitives,
184
+ self-documenting actions, loud termination, proof-of-done verification).
185
+ These don't fix the ceiling but sharply cut how often multi-step loops are
186
+ even attempted, and make the failures that remain _loud and truthful_ instead
187
+ of silent. Capture the agent-facing half as the `reliable-mutations` skill.
188
+ 2. **Phase 1 — Checkpointed continuation (Option A).** Add a SQL-backed progress
189
+ checkpoint for long operations and make their steps idempotent/resumable so
190
+ each `auto_continue` chunk advances committed progress instead of replanning.
191
+ Drive terminal state ("N of N", or "M of N + remainder") from the checkpoint.
192
+ This is the primary reliability win.
193
+ 3. **Phase 2 — Durable background execution (Option B).** For operations that
194
+ can exceed any reasonable number of continuation chunks, enqueue them onto the
195
+ core background infrastructure, have the durable worker run them to completion
196
+ (checkpointing internally per Phase 1), and stream truthful progress back to
197
+ the foreground run and UI.
198
+
199
+ ## Tie-in: cheaper near-term mitigations reduce, but do not replace, the fix
200
+
201
+ The following reduce _how often_ the 40s ceiling is hit and make the remaining
202
+ failures honest. They are valuable and should ship first (Phase 0), but the
203
+ **actual fix is durable/checkpointed runs** (Phases 1–2):
204
+
205
+ - **One-call atomic primitives.** Where an action can accept the whole batch
206
+ (e.g. "set all panels" / "append many in one call"), a single call commits
207
+ atomically inside one chunk instead of looping N writes that race the budget.
208
+ - **Self-documenting actions.** Action descriptions that steer agents toward the
209
+ atomic/batch call and away from per-item loops.
210
+ - **Loud termination.** On a time-budget cutoff, fail loud with what was and
211
+ wasn't committed — never report success on an aborted chunk.
212
+ - **Proof-of-done verification.** After a write, re-read the end state and report
213
+ concrete proof (counts/ids) rather than trusting a tool ✓.
214
+
215
+ The agent-facing rules for these live in the `reliable-mutations` skill
216
+ (`.agents/skills/reliable-mutations/SKILL.md`). They lower the blast radius;
217
+ checkpointed and durable runs remove the ceiling itself.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.69.0",
3
+ "version": "0.70.1",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -908,6 +908,94 @@ function zodDefToJsonSchema(def: any): any {
908
908
  // Runtime validation wrapper
909
909
  // ---------------------------------------------------------------------------
910
910
 
911
+ const NO_COERCE = Symbol("no-coerce");
912
+
913
+ /**
914
+ * Coerce a single stringified value to one of the JSON-schema types the field
915
+ * expects. Returns NO_COERCE when nothing safe applies, so the caller leaves
916
+ * the original value untouched and the normal validation error still surfaces.
917
+ */
918
+ function coerceStringToSchemaType(raw: string, types: string[]): unknown {
919
+ const trimmed = raw.trim();
920
+ if (types.includes("boolean")) {
921
+ if (trimmed === "true") return true;
922
+ if (trimmed === "false") return false;
923
+ }
924
+ if (
925
+ (types.includes("array") &&
926
+ trimmed.startsWith("[") &&
927
+ trimmed.endsWith("]")) ||
928
+ (types.includes("object") &&
929
+ trimmed.startsWith("{") &&
930
+ trimmed.endsWith("}"))
931
+ ) {
932
+ try {
933
+ const parsed = JSON.parse(trimmed);
934
+ if (types.includes("array") && Array.isArray(parsed)) return parsed;
935
+ if (
936
+ types.includes("object") &&
937
+ parsed &&
938
+ typeof parsed === "object" &&
939
+ !Array.isArray(parsed)
940
+ ) {
941
+ return parsed;
942
+ }
943
+ } catch {
944
+ // fall through — leave the original so validation reports the real error
945
+ }
946
+ }
947
+ if (
948
+ (types.includes("number") || types.includes("integer")) &&
949
+ trimmed !== "" &&
950
+ Number.isFinite(Number(trimmed))
951
+ ) {
952
+ const n = Number(trimmed);
953
+ if (types.includes("number") || Number.isInteger(n)) return n;
954
+ }
955
+ return NO_COERCE;
956
+ }
957
+
958
+ /**
959
+ * Defensively coerce gateway-stringified tool arguments to the types the schema
960
+ * expects. Some model gateways (notably Builder's Gemini-backed gateway) hand
961
+ * back structured tool-call arguments as JSON strings — an array param arrives
962
+ * as `"[{...}]"`, a boolean as `"true"`. Standard Schema (zod) `validate` does
963
+ * not coerce, so these fail validation and the agent thrashes retrying shapes
964
+ * (and can hang). We only touch a string value when the schema expects a
965
+ * non-string type and the string parses cleanly to it; anything ambiguous
966
+ * (schema also allows string) or unparseable is left as-is. Operates on
967
+ * top-level properties only — once an array/object param is parsed, its nested
968
+ * members are already native and validate normally.
969
+ */
970
+ function coerceGatewayStringifiedArgs(
971
+ args: unknown,
972
+ parameters?: ActionTool["parameters"],
973
+ ): unknown {
974
+ const properties = parameters?.properties as
975
+ | Record<string, { type?: string | string[] }>
976
+ | undefined;
977
+ if (!properties) return args;
978
+ if (!args || typeof args !== "object" || Array.isArray(args)) return args;
979
+ let out: Record<string, unknown> | null = null;
980
+ for (const [key, raw] of Object.entries(args as Record<string, unknown>)) {
981
+ if (typeof raw !== "string") continue;
982
+ const spec = properties[key];
983
+ if (!spec) continue;
984
+ const types = Array.isArray(spec.type)
985
+ ? spec.type
986
+ : spec.type
987
+ ? [spec.type]
988
+ : [];
989
+ // No declared type, or the field legitimately accepts a string → leave it.
990
+ if (types.length === 0 || types.includes("string")) continue;
991
+ const coerced = coerceStringToSchemaType(raw, types);
992
+ if (coerced === NO_COERCE) continue;
993
+ if (!out) out = { ...(args as Record<string, unknown>) };
994
+ out[key] = coerced;
995
+ }
996
+ return out ?? args;
997
+ }
998
+
911
999
  /**
912
1000
  * Wrap an action's run function with schema validation.
913
1001
  * Invalid inputs get a clear error message (including what was actually passed)
@@ -919,6 +1007,7 @@ function wrapWithValidation(
919
1007
  toolParameters?: ActionTool["parameters"],
920
1008
  ): (args: any, ctx?: ActionRunContext) => any {
921
1009
  return async (args: any, ctx?: ActionRunContext) => {
1010
+ args = coerceGatewayStringifiedArgs(args, toolParameters);
922
1011
  const result = await schema["~standard"].validate(args);
923
1012
  if (result.issues) {
924
1013
  // Split issues into "missing required field" vs other validation errors
@@ -39,7 +39,6 @@ const MODEL_CONTEXT_WINDOWS: Record<string, number> = {
39
39
  "gpt-5-5": 1_050_000,
40
40
  "gpt-5-4": 1_050_000,
41
41
  "gpt-5-4-mini": 400_000,
42
- "gpt-5-1-codex-mini": 128_000,
43
42
 
44
43
  // ── Gemini (Builder gateway IDs) ─────────────────────────────────────────
45
44
  "gemini-3-1-pro": 1_048_576,
@@ -145,7 +144,6 @@ export const AGENT_MODEL_CONFIG = {
145
144
  FRAMEWORK_DEFAULT_BUILDER_OPENAI_MODEL,
146
145
  "gpt-5-4",
147
146
  "gpt-5-4-mini",
148
- "gpt-5-1-codex-mini",
149
147
  "gemini-3-1-pro",
150
148
  "gemini-3-5-flash",
151
149
  "gemini-3-1-flash-lite",
@@ -90,6 +90,24 @@ async function appendToolCallJournalNote(
90
90
  */
91
91
  export const MAX_RUN_LOOP_CONTINUATIONS = 6;
92
92
 
93
+ /** Machine-readable code carried on the give-up terminal `error` event so the
94
+ * client renders a loud "stopped before finishing" terminal instead of an
95
+ * ambiguous silent stall. Deliberately NOT in the client's auto-recoverable
96
+ * allow-list (`isAutoRecoverableError`) so it terminates the chain rather than
97
+ * looping another POST that would hit the same wall. */
98
+ export const RUN_BUDGET_EXHAUSTED_ERROR_CODE = "run_budget_exhausted";
99
+
100
+ /** User-facing terminal message when a hosted run is cut off mid-step and
101
+ * exhausts its in-invocation continuation budget without finishing. Generic and
102
+ * framework-level (not app-specific). Mirrors the `reliable-mutations` skill's
103
+ * "fail loud, retry as a single bulk action" guidance so the user understands
104
+ * the turn stopped before finishing and was not partially saved by the run
105
+ * itself. */
106
+ export const RUN_BUDGET_EXHAUSTED_MESSAGE =
107
+ "I ran out of time before finishing this step (hosted runs have a ~40s budget). " +
108
+ "I stopped rather than leave things half-done — nothing was partially saved by me here. " +
109
+ "Please retry, ideally as a single bulk action.";
110
+
93
111
  /**
94
112
  * Internal entry point used by the agent-chat plugin's run handler. Wraps
95
113
  * `runAgentLoop` with soft-timeout + resumable-error continuation recovery.
@@ -124,8 +142,16 @@ export async function runAgentLoopDirectWithSoftTimeout(
124
142
  };
125
143
 
126
144
  let attempts = 0;
145
+ // Tracks whether the most recent attempt ended by scheduling another
146
+ // continuation (soft-timeout or resumable error → `continue`) rather than
147
+ // returning a finished turn. When the loop then exits because the budget is
148
+ // exhausted (NOT because the user aborted and NOT because the turn finished),
149
+ // this is the silent give-up case: emit a loud terminal so the user sees an
150
+ // unambiguous "stopped before finishing" instead of a bare done/"…".
151
+ let lastAttemptWasUnfinishedContinuation = false;
127
152
  while (!upstreamSignal.aborted && attempts < MAX_RUN_LOOP_CONTINUATIONS) {
128
153
  attempts++;
154
+ lastAttemptWasUnfinishedContinuation = false;
129
155
  const controller = new AbortController();
130
156
  const abortFromUpstream = () => controller.abort();
131
157
  if (upstreamSignal.aborted) {
@@ -150,6 +176,7 @@ export async function runAgentLoopDirectWithSoftTimeout(
150
176
  });
151
177
  addUsage(nextUsage);
152
178
  if (softTimedOut && !upstreamSignal.aborted) {
179
+ lastAttemptWasUnfinishedContinuation = true;
153
180
  appendAgentLoopContinuation(opts.messages, "run_timeout");
154
181
  await appendToolCallJournalNote(opts.messages, opts.threadId);
155
182
  continue;
@@ -159,6 +186,7 @@ export async function runAgentLoopDirectWithSoftTimeout(
159
186
  if (softTimedOut && !upstreamSignal.aborted) {
160
187
  // Clear partial text the client received before the abort so the
161
188
  // resumed model doesn't re-emit it and produce duplicated output.
189
+ lastAttemptWasUnfinishedContinuation = true;
162
190
  opts.send({ type: "clear" });
163
191
  appendAgentLoopContinuation(opts.messages, "run_timeout");
164
192
  await appendToolCallJournalNote(opts.messages, opts.threadId);
@@ -178,6 +206,7 @@ export async function runAgentLoopDirectWithSoftTimeout(
178
206
  // (the partial text was already sent to the client but never entered
179
207
  // the in-memory messages array, so the next attempt re-emits it).
180
208
  if (!upstreamSignal.aborted && isResumableEngineError(err)) {
209
+ lastAttemptWasUnfinishedContinuation = true;
181
210
  opts.send({ type: "clear" });
182
211
  appendAgentLoopContinuation(
183
212
  opts.messages,
@@ -193,5 +222,24 @@ export async function runAgentLoopDirectWithSoftTimeout(
193
222
  }
194
223
  }
195
224
 
225
+ // The loop exited without a clean return. If the user aborted, that's a Stop —
226
+ // stay silent. Otherwise we only get here by exhausting
227
+ // MAX_RUN_LOOP_CONTINUATIONS while the last attempt was still trying to
228
+ // continue (soft-timeout / resumable error). That is the genuinely-silent
229
+ // give-up the run-manager would otherwise report as a clean `done`: emit a
230
+ // loud, non-auto-continuing terminal so the user knows the turn stopped
231
+ // before finishing and nothing was partially saved by the run itself.
232
+ if (!upstreamSignal.aborted && lastAttemptWasUnfinishedContinuation) {
233
+ // Discard any partial text already streamed for the unfinished attempt so
234
+ // the terminal message stands alone instead of trailing a half sentence.
235
+ opts.send({ type: "clear" });
236
+ opts.send({
237
+ type: "error",
238
+ error: RUN_BUDGET_EXHAUSTED_MESSAGE,
239
+ errorCode: RUN_BUDGET_EXHAUSTED_ERROR_CODE,
240
+ recoverable: true,
241
+ });
242
+ }
243
+
196
244
  return usage;
197
245
  }