@agent-native/core 0.90.4 → 0.90.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +34 -7
  2. package/corpus/README.md +1 -1
  3. package/corpus/core/CHANGELOG.md +21 -0
  4. package/corpus/core/docs/content/agent-native-toolkit.mdx +1 -1
  5. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  6. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  8. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  9. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  10. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  11. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  12. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  13. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  14. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  15. package/corpus/core/docs/content/toolkit-agent-ux.mdx +1 -1
  16. package/corpus/core/docs/content/toolkit-app-adapters.mdx +1 -1
  17. package/corpus/core/docs/content/toolkit-collaboration-ui.mdx +1 -1
  18. package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
  19. package/corpus/core/docs/content/toolkit-command-navigation.mdx +2 -2
  20. package/corpus/core/docs/content/toolkit-comments-review.mdx +1 -1
  21. package/corpus/core/docs/content/toolkit-history.mdx +1 -1
  22. package/corpus/core/docs/content/toolkit-observability.mdx +1 -1
  23. package/corpus/core/docs/content/toolkit-org-team.mdx +1 -1
  24. package/corpus/core/docs/content/toolkit-resources.mdx +1 -1
  25. package/corpus/core/docs/content/toolkit-settings.mdx +1 -1
  26. package/corpus/core/docs/content/toolkit-setup-connections.mdx +1 -1
  27. package/corpus/core/docs/content/toolkit-sharing-ui.mdx +1 -1
  28. package/corpus/core/docs/content/toolkit-sharing.mdx +1 -1
  29. package/corpus/core/docs/content/toolkit-shell-hooks.mdx +1 -1
  30. package/corpus/core/docs/content/toolkit-ui.mdx +1 -1
  31. package/corpus/core/package.json +1 -1
  32. package/corpus/core/src/agent/durable-background.ts +18 -18
  33. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +8 -2
  34. package/corpus/core/src/agent/engine/anthropic-engine.ts +11 -1
  35. package/corpus/core/src/agent/production-agent.ts +22 -11
  36. package/corpus/core/src/agent/run-manager.ts +17 -6
  37. package/corpus/core/src/agent/run-store.ts +16 -11
  38. package/corpus/core/src/cli/design-connect.ts +16 -2
  39. package/corpus/core/src/client/KeepTabOpenNotice.tsx +20 -15
  40. package/corpus/core/src/client/RunStuckBanner.tsx +14 -13
  41. package/corpus/core/src/client/agent-chat-adapter.ts +28 -17
  42. package/corpus/core/src/client/use-db-sync.ts +99 -1
  43. package/corpus/core/src/client/use-run-stuck-detection.ts +8 -5
  44. package/corpus/core/src/collab/client.ts +49 -4
  45. package/corpus/core/src/deploy/build.ts +103 -0
  46. package/corpus/core/src/server/core-routes-plugin.ts +137 -8
  47. package/corpus/templates/clips/changelog/2026-07-07-faster-local-whisper-dictation-start.md +6 -0
  48. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +311 -31
  49. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +2 -0
  50. package/corpus/templates/content/AGENTS.md +1 -0
  51. package/corpus/templates/content/actions/_database-source-utils.ts +73 -8
  52. package/corpus/templates/content/actions/_database-utils.ts +2 -1
  53. package/corpus/templates/content/actions/prepare-builder-source-review.ts +20 -1
  54. package/corpus/templates/content/actions/stage-builder-source-bulk-update.ts +663 -0
  55. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +33 -7
  56. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +53 -4
  57. package/corpus/templates/content/app/components/editor/database/settings.tsx +24 -0
  58. package/corpus/templates/content/app/hooks/use-content-database.ts +70 -1
  59. package/corpus/templates/content/app/hooks/use-document-properties.ts +63 -5
  60. package/corpus/templates/content/app/i18n/zh-TW.ts +3 -0
  61. package/corpus/templates/content/app/i18n-data.ts +31 -0
  62. package/corpus/templates/content/changelog/2026-07-01-builder-source-rows-can-be-staged-in-bulk-with-a-reviewable.md +6 -0
  63. package/corpus/templates/content/changelog/2026-07-07-builder-backed-database-fields-now-edit-like-normal-content-fields.md +6 -0
  64. package/corpus/templates/content/parity/matrix.md +24 -24
  65. package/corpus/templates/content/parity/matrix.ts +2 -0
  66. package/corpus/templates/content/shared/api.ts +59 -4
  67. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +9 -0
  68. package/corpus/templates/design/actions/connect-localhost.ts +26 -3
  69. package/corpus/templates/design/actions/open-visual-edit.ts +4 -37
  70. package/corpus/templates/design/actions/read-source-file.ts +28 -0
  71. package/corpus/templates/design/actions/update-file.ts +76 -7
  72. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +207 -11
  73. package/corpus/templates/design/app/components/design/EditPanel.tsx +4 -0
  74. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +387 -25
  75. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1110 -88
  76. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +368 -16
  77. package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +24 -0
  78. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +27 -6
  79. package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +18 -0
  80. package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +5 -4
  81. package/corpus/templates/design/app/components/design/multi-screen/handle-hit-zones.ts +124 -0
  82. package/corpus/templates/design/app/components/design/multi-screen/types.ts +23 -0
  83. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  84. package/corpus/templates/design/app/i18n-data.ts +19 -0
  85. package/corpus/templates/design/changelog/2026-07-07-dragging-a-free-floating-element-into-a-layout-column-or-row.md +6 -0
  86. package/corpus/templates/design/changelog/2026-07-07-dragging-a-repeated-list-item-like-a-to-do-card-generated-fr.md +6 -0
  87. package/corpus/templates/design/changelog/2026-07-07-dragging-an-element-onto-a-button-or-chip-s-middle-no-longer.md +6 -0
  88. package/corpus/templates/design/changelog/2026-07-07-elements-dropped-into-another-board-shape-now-stay-exactly-w.md +6 -0
  89. package/corpus/templates/design/changelog/2026-07-07-fixed-drag-reordering-elements-within-a-screen-no-longer-sil.md +6 -0
  90. package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-an-element-from-a-screen-onto-the-canvas-now-.md +6 -0
  91. package/corpus/templates/design/changelog/2026-07-07-fixed-dragging-elements-between-screens-into-ai-generated-co.md +6 -0
  92. package/corpus/templates/design/changelog/2026-07-07-fixed-moving-elements-between-screens-no-longer-bakes-intern.md +6 -0
  93. package/corpus/templates/design/changelog/2026-07-07-fixed-the-cross-screen-drop-indicator-now-points-at-the-corr.md +6 -0
  94. package/corpus/templates/design/changelog/2026-07-07-fixed-the-zoom-menu-no-longer-leaves-the-canvas-unresponsive.md +6 -0
  95. package/corpus/templates/design/changelog/2026-07-07-local-visual-edit-keeps-bridge-access-when-opening-previousl.md +6 -0
  96. package/corpus/templates/design/changelog/2026-07-07-local-visual-edit-now-keeps-the-live-app-connection-authenti.md +6 -0
  97. package/corpus/templates/design/changelog/2026-07-07-text-drawn-on-the-canvas-is-now-readable-white-instead-of-in.md +6 -0
  98. package/corpus/templates/design/server/source-workspace.ts +27 -3
  99. package/corpus/templates/design/shared/board-file.ts +359 -0
  100. package/corpus/templates/design/shared/breakpoint-media.ts +21 -3
  101. package/corpus/templates/design/shared/code-layer.ts +145 -10
  102. package/dist/agent/durable-background.d.ts +12 -12
  103. package/dist/agent/durable-background.js +18 -18
  104. package/dist/agent/durable-background.js.map +1 -1
  105. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  106. package/dist/agent/engine/ai-sdk-engine.js +8 -2
  107. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  108. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  109. package/dist/agent/engine/anthropic-engine.js +11 -1
  110. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  111. package/dist/agent/production-agent.d.ts +2 -2
  112. package/dist/agent/production-agent.d.ts.map +1 -1
  113. package/dist/agent/production-agent.js +18 -11
  114. package/dist/agent/production-agent.js.map +1 -1
  115. package/dist/agent/run-manager.d.ts +7 -1
  116. package/dist/agent/run-manager.d.ts.map +1 -1
  117. package/dist/agent/run-manager.js +6 -1
  118. package/dist/agent/run-manager.js.map +1 -1
  119. package/dist/agent/run-store.d.ts +1 -1
  120. package/dist/agent/run-store.d.ts.map +1 -1
  121. package/dist/agent/run-store.js +15 -10
  122. package/dist/agent/run-store.js.map +1 -1
  123. package/dist/cli/design-connect.d.ts.map +1 -1
  124. package/dist/cli/design-connect.js +12 -2
  125. package/dist/cli/design-connect.js.map +1 -1
  126. package/dist/client/KeepTabOpenNotice.d.ts +9 -10
  127. package/dist/client/KeepTabOpenNotice.d.ts.map +1 -1
  128. package/dist/client/KeepTabOpenNotice.js +8 -4
  129. package/dist/client/KeepTabOpenNotice.js.map +1 -1
  130. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  131. package/dist/client/RunStuckBanner.js +14 -13
  132. package/dist/client/RunStuckBanner.js.map +1 -1
  133. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  134. package/dist/client/agent-chat-adapter.js +25 -17
  135. package/dist/client/agent-chat-adapter.js.map +1 -1
  136. package/dist/client/use-db-sync.d.ts +18 -0
  137. package/dist/client/use-db-sync.d.ts.map +1 -1
  138. package/dist/client/use-db-sync.js +88 -1
  139. package/dist/client/use-db-sync.js.map +1 -1
  140. package/dist/client/use-run-stuck-detection.d.ts +1 -1
  141. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  142. package/dist/client/use-run-stuck-detection.js +6 -4
  143. package/dist/client/use-run-stuck-detection.js.map +1 -1
  144. package/dist/collab/client.d.ts.map +1 -1
  145. package/dist/collab/client.js +43 -4
  146. package/dist/collab/client.js.map +1 -1
  147. package/dist/collab/routes.d.ts +1 -1
  148. package/dist/collab/struct-routes.d.ts +1 -1
  149. package/dist/deploy/build.d.ts +1 -0
  150. package/dist/deploy/build.d.ts.map +1 -1
  151. package/dist/deploy/build.js +57 -0
  152. package/dist/deploy/build.js.map +1 -1
  153. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  154. package/dist/notifications/routes.d.ts +2 -2
  155. package/dist/resources/handlers.d.ts +3 -3
  156. package/dist/secrets/routes.d.ts +9 -9
  157. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  158. package/dist/server/core-routes-plugin.d.ts +10 -0
  159. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  160. package/dist/server/core-routes-plugin.js +103 -9
  161. package/dist/server/core-routes-plugin.js.map +1 -1
  162. package/docs/content/agent-native-toolkit.mdx +1 -1
  163. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +1 -1
  164. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +1 -1
  165. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +1 -1
  166. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +1 -1
  167. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +1 -1
  168. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +1 -1
  169. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +1 -1
  170. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +1 -1
  171. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +1 -1
  172. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +1 -1
  173. package/docs/content/toolkit-agent-ux.mdx +1 -1
  174. package/docs/content/toolkit-app-adapters.mdx +1 -1
  175. package/docs/content/toolkit-collaboration-ui.mdx +1 -1
  176. package/docs/content/toolkit-collaboration.mdx +1 -1
  177. package/docs/content/toolkit-command-navigation.mdx +2 -2
  178. package/docs/content/toolkit-comments-review.mdx +1 -1
  179. package/docs/content/toolkit-history.mdx +1 -1
  180. package/docs/content/toolkit-observability.mdx +1 -1
  181. package/docs/content/toolkit-org-team.mdx +1 -1
  182. package/docs/content/toolkit-resources.mdx +1 -1
  183. package/docs/content/toolkit-settings.mdx +1 -1
  184. package/docs/content/toolkit-setup-connections.mdx +1 -1
  185. package/docs/content/toolkit-sharing-ui.mdx +1 -1
  186. package/docs/content/toolkit-sharing.mdx +1 -1
  187. package/docs/content/toolkit-shell-hooks.mdx +1 -1
  188. package/docs/content/toolkit-ui.mdx +1 -1
  189. package/package.json +1 -1
@@ -13,7 +13,7 @@ that operators use to understand what happened.
13
13
  <Screen
14
14
  surface="desktop"
15
15
  html={
16
- "<div style='min-height:560px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:1fr 300px;gap:16px'><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><h2 style='margin:0'>Observability</h2><div style='display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px'><div class='wf-box'>Runs 482</div><div class='wf-box'>Spend $42</div><div class='wf-box'>Errors 3</div></div><div class='wf-box' style='height:260px'>Replay timeline and traces</div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Diagnostics</strong><div class='wf-box'>Run failed: missing key</div><div class='wf-box'>User feedback: thumbs down</div><div class='wf-box'>Slow tool: provider-api-request</div><button class='primary'>Open run</button></aside></div>"
16
+ "<div style='min-height:540px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:1fr 300px;gap:16px'><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><h2 style='margin:0'>Observability</h2><div style='display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px'><div class='wf-box'><small class='wf-muted'>Runs</small><br/><strong style='font-size:20px'>482</strong></div><div class='wf-box'><small class='wf-muted'>Spend</small><br/><strong style='font-size:20px'>$42</strong></div><div class='wf-box'><small class='wf-muted'>Errors</small><br/><strong style='font-size:20px'>3</strong></div></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Runs per day</small><div style='display:flex;align-items:flex-end;gap:6px;height:150px'><div style='flex:1;height:40%;background:var(--wf-accent-soft);border-radius:3px'></div><div style='flex:1;height:60%;background:var(--wf-accent-soft);border-radius:3px'></div><div style='flex:1;height:50%;background:var(--wf-accent-soft);border-radius:3px'></div><div style='flex:1;height:75%;background:var(--wf-accent-soft);border-radius:3px'></div><div style='flex:1;height:65%;background:var(--wf-accent-soft);border-radius:3px'></div><div style='flex:1;height:90%;background:var(--wf-accent);border-radius:3px'></div><div style='flex:1;height:80%;background:var(--wf-accent-soft);border-radius:3px'></div></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Diagnostics</strong><div class='wf-box' style='display:flex;align-items:center;gap:8px'><span data-icon='x'></span><div style='flex:1'>Run failed: missing key</div></div><div class='wf-box' style='display:flex;align-items:center;gap:8px'><span data-icon='bell'></span><div style='flex:1'>Feedback: thumbs down</div></div><div class='wf-box' style='display:flex;align-items:center;gap:8px'><span data-icon='calendar'></span><div style='flex:1'>Slow tool: provider-api</div></div><div style='flex:1'></div><button class='primary'>Open run</button></aside></div>"
17
17
  }
18
18
  />
19
19
  </WireframeBlock>
@@ -14,7 +14,7 @@ connections, service tokens, and app switching.
14
14
  <Screen
15
15
  surface="desktop"
16
16
  html={
17
- "<div style='min-height:540px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:240px 1fr;gap:18px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:12px'><strong>Workspace</strong><div class='wf-box'>OrgSwitcher: Acme</div><div class='wf-pill'>Analytics</div><div class='wf-pill'>Content</div><div class='wf-pill'>Slides</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Team</h2><div style='flex:1'></div><button class='primary'>Invite</button></div><div class='wf-box'>Allowed domain: acme.com</div><div class='wf-box'>Steve - owner</div><div class='wf-box'>Maya - admin</div><div class='wf-box'>Kai - member</div><div class='wf-box'>Pending invites: 3</div></main></div>"
17
+ "<div style='min-height:540px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:210px 1fr;gap:18px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Organization</small><div class='wf-box' style='display:flex;align-items:center;gap:8px;padding:8px 10px'><div style='width:24px;height:24px;border-radius:7px;background:var(--wf-accent-soft);display:flex;align-items:center;justify-content:center;font-size:11px;flex:none'>A</div><strong style='flex:1'>Acme</strong><span data-icon='chevronDown'></span></div><div style='display:flex;flex-direction:column;gap:4px;margin-top:4px'><div style='padding:6px 9px;border-radius:8px;background:var(--wf-accent-soft)'>Analytics</div><div style='padding:6px 9px;border-radius:8px'>Content</div><div style='padding:6px 9px;border-radius:8px'>Slides</div></div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Team</h2><span class='wf-pill'>8 members</span><div style='flex:1'></div><button class='primary'><span data-icon='plus'></span> Invite</button></div><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Steve Ray</strong><br/><small class='wf-muted'>steve@acme.com</small></div><span class='wf-pill'>Owner</span></div><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Maya Chen</strong><br/><small class='wf-muted'>maya@acme.com</small></div><span class='wf-pill'>Admin <span data-icon='chevronDown'></span></span></div><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Kai Wong</strong><br/><small class='wf-muted'>kai@acme.com</small></div><span class='wf-pill'>Member <span data-icon='chevronDown'></span></span></div><hr/><div style='display:flex;align-items:center;gap:8px'><span data-icon='mail'></span><div style='flex:1'>Anyone with an acme.com email can join</div></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='user'></span><div style='flex:1'>Pending invites</div><span class='wf-pill'>3</span></div></main></div>"
18
18
  }
19
19
  />
20
20
  </WireframeBlock>
@@ -14,7 +14,7 @@ for repo-backed content.
14
14
  <Screen
15
15
  surface="desktop"
16
16
  html={
17
- "<div style='min-height:560px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:260px 1fr 240px;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Resources</strong><div class='wf-box'>docs/</div><div class='wf-box'>blog/</div><div class='wf-box'>assets/</div><div class='wf-box'>Q3 forecast.md</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><h2 style='margin:0'>Q3 forecast.md</h2><div class='wf-box' style='height:330px'>ResourceEditor</div><button class='primary'>Save</button></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Attachments</strong><div class='wf-box'>Drop file</div><div class='wf-box'>Search resources</div><div class='wf-box'>local file mode: on</div></aside></div>"
17
+ "<div style='min-height:540px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:230px 1fr 220px;gap:14px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:4px'><div style='display:flex;align-items:center;gap:8px;margin-bottom:6px'><strong style='flex:1'>Resources</strong><span data-icon='search'></span><span data-icon='plus'></span></div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px'><span data-icon='chevronDown'></span> docs</div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px 6px 22px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='edit'></span> Q3 forecast.md</div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px 6px 22px'><span data-icon='edit'></span> roadmap.md</div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px'><span data-icon='chevronRight'></span> blog</div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px'><span data-icon='chevronRight'></span> assets</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 forecast.md</h2><div style='flex:1'></div><button class='primary'>Save</button></div><div style='display:flex;flex-direction:column;gap:8px'><div style='height:11px;width:60%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:92%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:85%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:95%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:70%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:88%;background:var(--wf-line);border-radius:4px'></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Attachments</strong><div style='border:1.6px dashed var(--wf-line);border-radius:var(--wf-radius);padding:16px;text-align:center'><span data-icon='plus'></span><br/><small class='wf-muted'>Drop files</small></div><div class='wf-box' style='display:flex;align-items:center;gap:8px'><span data-icon='search'></span><span class='wf-muted'>Search resources</span></div><div style='flex:1'></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='check'></span><small>Local file mode on</small></div></aside></div>"
18
18
  }
19
19
  />
20
20
  </WireframeBlock>
@@ -14,7 +14,7 @@ page; framework tabs can be mounted inside it.
14
14
  <Screen
15
15
  surface="desktop"
16
16
  html={
17
- "<div style='min-height:540px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:220px 1fr;gap:18px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Settings</strong><div class='wf-pill'>General</div><div class='wf-pill'>AI and models</div><div class='wf-pill'>Connections</div><div class='wf-pill'>Team</div><div class='wf-pill'>Developer</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><h2 style='margin:0'>AI and models</h2><div class='wf-box'>Default model: GPT-5</div><div class='wf-box'>LLM keys: OpenAI configured, Anthropic missing</div><div class='wf-box'>Provider readiness: Builder connected</div><div style='display:flex;gap:10px'><button>Open agent settings</button><button class='primary'>Save changes</button></div></main></div>"
17
+ "<div style='min-height:520px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:200px 1fr;gap:18px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:6px'><strong style='margin-bottom:4px'>Settings</strong><div style='padding:7px 9px;border-radius:8px'>General</div><div style='padding:7px 9px;border-radius:8px;background:var(--wf-accent-soft);display:flex;align-items:center;gap:8px'><span data-icon='settings'></span> AI and models</div><div style='padding:7px 9px;border-radius:8px'>Connections</div><div style='padding:7px 9px;border-radius:8px'>Team</div><div style='padding:7px 9px;border-radius:8px'>Developer</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><h2 style='margin:0'>AI and models</h2><div style='display:flex;flex-direction:column;gap:6px'><small class='wf-muted'>Default model</small><div class='wf-box' style='display:flex;align-items:center;gap:8px'><div style='flex:1'>GPT-5</div><span data-icon='chevronDown'></span></div></div><div style='display:flex;flex-direction:column;gap:8px'><small class='wf-muted'>Provider keys</small><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='check'></span><div style='flex:1'>OpenAI</div><span class='wf-pill'>Connected</span></div><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='lock'></span><div style='flex:1'>Anthropic</div><button>Add key</button></div><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='check'></span><div style='flex:1'>Builder</div><span class='wf-pill'>Connected</span></div></div><div style='flex:1'></div><div style='display:flex;gap:10px'><button>Open agent settings</button><div style='flex:1'></div><button class='primary'>Save changes</button></div></main></div>"
18
18
  }
19
19
  />
20
20
  </WireframeBlock>
@@ -14,7 +14,7 @@ what is missing and link users to the exact fix.
14
14
  <Screen
15
15
  surface="desktop"
16
16
  html={
17
- "<div style='min-height:540px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:1fr 330px;gap:18px'><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><h2 style='margin:0'>Setup checklist</h2><div class='wf-box'>1. Connect Builder - complete</div><div class='wf-box'>2. Add OpenAI key - needs attention</div><div class='wf-box'>3. Connect Slack workspace - optional</div><div class='wf-box'>4. Enable GitHub OAuth - ready</div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:12px'><strong>Provider readiness</strong><div class='wf-box'>Builder: connected</div><div class='wf-box'>LLM: missing key</div><div class='wf-box'>GitHub: OAuth ready</div><button class='primary'>Open Settings</button></aside></div>"
17
+ "<div style='min-height:520px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:1fr 300px;gap:18px'><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><h2 style='margin:0'>Finish setup</h2><small class='wf-muted'>2 of 4 steps complete</small><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='check'></span><div style='flex:1'>Connect Builder</div><span class='wf-pill'>Done</span></div><div class='wf-box' style='display:flex;align-items:center;gap:10px;border-color:var(--wf-accent)'><span data-icon='lock'></span><div style='flex:1'><strong>Add OpenAI key</strong><br/><small class='wf-muted'>Needed for the agent to run</small></div><button class='primary'>Fix</button></div><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='plus'></span><div style='flex:1'>Connect Slack</div><span class='wf-muted'>Optional</span></div><div class='wf-box' style='display:flex;align-items:center;gap:10px'><span data-icon='check'></span><div style='flex:1'>Enable GitHub OAuth</div><span class='wf-pill'>Ready</span></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Provider readiness</strong><div style='display:flex;align-items:center;gap:8px'><span data-icon='check'></span><div style='flex:1'>Builder</div><span class='wf-pill'>Connected</span></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='x'></span><div style='flex:1'>LLM key</div><span class='wf-pill'>Missing</span></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='check'></span><div style='flex:1'>GitHub</div><span class='wf-pill'>OAuth ready</span></div><div style='flex:1'></div><button class='primary'>Open settings</button></aside></div>"
18
18
  }
19
19
  />
20
20
  </WireframeBlock>
@@ -13,7 +13,7 @@ mutations; core and app wrappers inject data and callbacks.
13
13
  <Screen
14
14
  surface="desktop"
15
15
  html={
16
- "<div style='min-height:480px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:1fr 300px;gap:16px'><main class='wf-card' style='display:flex;flex-direction:column;gap:12px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Resource header</h2><span class='wf-pill'>Org visible</span><div style='flex:1'></div><button>Share</button></div><div class='wf-box' style='height:120px'>Share list row</div><div class='wf-box' style='height:180px'>Shared resource preview</div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Presentational pieces</strong><div class='wf-box'>VisibilityBadge</div><div class='wf-box'>Grant row</div><div class='wf-box'>Role selector</div><div class='wf-box'>Policy hint</div></aside></div>"
16
+ "<div style='min-height:480px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:1fr 300px;gap:16px'><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Roadmap</h2><span class='wf-pill accent'>Org visible</span><div style='flex:1'></div><button><span data-icon='user'></span> Share</button></div><small class='wf-muted'>Visibility badges</small><div style='display:flex;gap:6px'><span class='wf-pill'><span data-icon='lock'></span> Private</span><span class='wf-pill'>Shared</span><span class='wf-pill accent'>Org</span><span class='wf-pill'>Public</span></div><div style='display:flex;flex-direction:column;gap:8px'><div style='height:11px;width:88%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:72%;background:var(--wf-line);border-radius:4px'></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Share</strong><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Maya Chen</strong><br/><small class='wf-muted'>maya@acme.com</small></div><span class='wf-pill'>Editor <span data-icon='chevronDown'></span></span></div><div class='wf-card' style='display:flex;flex-direction:column;gap:2px;padding:6px'><div style='padding:6px 8px;border-radius:6px;background:var(--wf-accent-soft);display:flex;align-items:center;gap:8px'><span data-icon='check'></span> Editor</div><div style='padding:6px 8px'>Viewer</div><div style='padding:6px 8px'>Remove</div></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='lock'></span><small class='wf-muted'>Public links disabled by policy</small></div></aside></div>"
17
17
  }
18
18
  />
19
19
  </WireframeBlock>
@@ -14,7 +14,7 @@ links.
14
14
  <Screen
15
15
  surface="desktop"
16
16
  html={
17
- "<div style='min-height:540px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:1fr 320px;gap:18px'><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><span class='wf-pill'>Org visible</span><div style='flex:1'></div><button>Share</button></div><div class='wf-box' style='height:92px'>Dashboard preview</div><div class='wf-box' style='height:260px'>Resource content</div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:12px'><strong>Share resource</strong><div class='wf-box'>Visibility: Organization</div><div class='wf-box'>Invite teammate@example.com</div><div class='wf-box'>Role: Editor</div><button class='primary'>Send invite</button><div class='wf-box'>Public link disabled by policy</div></aside></div>"
17
+ "<div style='min-height:540px;box-sizing:border-box;padding:26px;display:grid;grid-template-columns:1fr 320px;gap:18px'><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Q3 Forecast</h2><span class='wf-pill accent'>Org visible</span><div style='flex:1'></div><button><span data-icon='user'></span> Share</button></div><div class='wf-box' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Revenue by month</small><div style='display:flex;align-items:flex-end;gap:10px;height:120px'><div style='flex:1;height:50%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:75%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:60%;background:var(--wf-accent-soft);border-radius:4px'></div><div style='flex:1;height:92%;background:var(--wf-accent);border-radius:4px'></div></div></div><div style='display:flex;flex-direction:column;gap:8px'><div style='height:11px;width:70%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:90%;background:var(--wf-line);border-radius:4px'></div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:12px'><strong>Share Q3 Forecast</strong><div style='display:flex;align-items:center;gap:8px'><div class='wf-box' style='flex:1;display:flex;align-items:center;gap:8px;padding:8px 10px'><span data-icon='mail'></span><span class='wf-muted'>Add people or teams</span></div><button class='primary'>Invite</button></div><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Steve Ray</strong><br/><small class='wf-muted'>steve@acme.com</small></div><small class='wf-muted'>Owner</small></div><div style='display:flex;align-items:center;gap:10px'><div style='width:28px;height:28px;border-radius:999px;background:var(--wf-accent-soft);flex:none'></div><div style='flex:1;min-width:0'><strong>Maya Chen</strong><br/><small class='wf-muted'>maya@acme.com</small></div><span class='wf-pill'>Editor <span data-icon='chevronDown'></span></span></div><hr/><div style='display:flex;align-items:center;gap:8px'><span data-icon='user'></span><div style='flex:1'>Anyone at Acme</div><span class='wf-pill'>Can view <span data-icon='chevronDown'></span></span></div><div style='display:flex;align-items:center;gap:8px'><span data-icon='lock'></span><div style='flex:1'>Public link</div><span class='wf-muted'>Off</span></div></aside></div>"
18
18
  }
19
19
  />
20
20
  </WireframeBlock>
@@ -11,7 +11,7 @@ Toolkit includes small shell helpers and hooks that are useful across apps:
11
11
  <Screen
12
12
  surface="desktop"
13
13
  html={
14
- "<div style='min-height:480px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:230px 1fr;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Shell</strong><div class='wf-pill'>Header actions</div><div class='wf-pill'>Mobile state</div><div class='wf-pill'>Toasts</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><div style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Page title</h2><div style='flex:1'></div><button>Export</button><button class='primary'>Create</button></div><div class='wf-box' style='height:250px'>App content using shared shell hooks</div><div class='wf-box'>Toast: Saved changes</div></main></div>"
14
+ "<div style='min-height:460px;box-sizing:border-box;padding:24px;display:grid;grid-template-columns:200px 1fr;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:6px'><strong style='margin-bottom:4px'>Analytics</strong><div style='padding:6px 9px;border-radius:8px;background:var(--wf-accent-soft)'>Dashboards</div><div style='padding:6px 9px;border-radius:8px'>Reports</div><div style='padding:6px 9px;border-radius:8px'>Settings</div></aside><main style='position:relative;display:flex;flex-direction:column;gap:14px'><div class='wf-card' style='display:flex;align-items:center;gap:10px'><h2 style='margin:0'>Dashboards</h2><div style='flex:1'></div><button><span data-icon='send'></span> Export</button><button class='primary'><span data-icon='plus'></span> Create</button></div><div class='wf-card' style='flex:1;display:flex;flex-direction:column;gap:8px'><div style='height:11px;width:70%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:90%;background:var(--wf-line);border-radius:4px'></div><div style='height:11px;width:80%;background:var(--wf-line);border-radius:4px'></div></div><div class='wf-card' style='display:flex;align-items:center;gap:8px;border-color:var(--wf-accent);position:absolute;right:0;bottom:0;width:230px'><span data-icon='check'></span><div style='flex:1'>Saved changes</div><span data-icon='x'></span></div></main></div>"
15
15
  }
16
16
  />
17
17
  </WireframeBlock>
@@ -12,7 +12,7 @@ shared shadcn-style building blocks used by templates and reusable kits.
12
12
  <Screen
13
13
  surface="desktop"
14
14
  html={
15
- "<div style='min-height:480px;box-sizing:border-box;padding:28px;display:grid;grid-template-columns:220px 1fr;gap:16px'><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Primitives</strong><div class='wf-pill'>Button</div><div class='wf-pill'>Dialog</div><div class='wf-pill'>Popover</div><div class='wf-pill'>Tooltip</div></aside><main class='wf-card' style='display:flex;flex-direction:column;gap:14px'><h2 style='margin:0'>Reusable kit surface</h2><div style='display:flex;gap:10px'><button>Cancel</button><button class='primary'>Save</button></div><div class='wf-box' style='height:96px'>Dialog content</div><div class='wf-box' style='height:150px'>Popover or menu content</div></main></div>"
15
+ "<div style='min-height:460px;box-sizing:border-box;padding:26px;display:flex;flex-direction:column;gap:16px'><h2 style='margin:0'>UI primitives</h2><div style='display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px'><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Buttons</small><div style='display:flex;gap:8px'><button>Cancel</button><button class='primary'>Save</button></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Input</small><div class='wf-box' style='display:flex;align-items:center;gap:8px'><span data-icon='search'></span><span class='wf-muted'>Search...</span></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Select</small><div class='wf-box' style='display:flex;align-items:center;gap:8px'><div style='flex:1'>Editor</div><span data-icon='chevronDown'></span></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><small class='wf-muted'>Badges</small><div style='display:flex;gap:6px'><span class='wf-pill accent'>Active</span><span class='wf-pill'>Draft</span></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:8px'><small class='wf-muted'>Dialog</small><strong>Delete file?</strong><small class='wf-muted'>This cannot be undone.</small><div style='display:flex;gap:8px;justify-content:flex-end'><button>Cancel</button><button class='primary'>Delete</button></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:6px'><small class='wf-muted'>Menu</small><div style='display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:8px;background:var(--wf-accent-soft)'><span data-icon='edit'></span> Rename</div><div style='display:flex;align-items:center;gap:8px;padding:6px 8px'><span data-icon='user'></span> Share</div></div></div></div>"
16
16
  }
17
17
  />
18
18
  </WireframeBlock>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.90.4",
3
+ "version": "0.90.7",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -340,17 +340,17 @@ export function isAgentChatDurableBackgroundEnabled(options?: {
340
340
  }
341
341
 
342
342
  /**
343
- * Env flag for the FOREGROUND server-driven self-chain. DEFAULT-OFF (opt-in):
344
- * unset means disabled; an app opts IN with an explicit truthy value
345
- * (`true`/`1`/`yes`/`on`) — same parsing convention as
346
- * `AGENT_CHAT_DURABLE_BACKGROUND`, deliberately kept as a separate flag so
347
- * this narrower capability can be enabled/disabled independently of the full
348
- * durable-background worker path.
343
+ * Env flag for the FOREGROUND server-driven self-chain. DEFAULT-ON for hosted
344
+ * deployments with `A2A_SECRET`: unset/empty/unknown means enabled, and an app
345
+ * opts OUT with an explicit falsy value (`false`/`0`/`no`/`off`). Deliberately
346
+ * kept separate from `AGENT_CHAT_DURABLE_BACKGROUND` so this narrower
347
+ * capability can be disabled independently of the full durable-background
348
+ * worker path.
349
349
  */
350
350
  export const AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV =
351
351
  "AGENT_CHAT_FOREGROUND_SELF_CHAIN";
352
352
 
353
- function isForegroundSelfChainFlagEnabled(): boolean {
353
+ function isForegroundSelfChainExplicitlyDisabled(): boolean {
354
354
  // Read the literal key (not `process.env[CONST]`) so guard:no-env-credentials
355
355
  // can statically verify it against the allowlisted `AGENT_*` prefix. Keep this
356
356
  // in sync with AGENT_CHAT_FOREGROUND_SELF_CHAIN_ENV.
@@ -358,26 +358,26 @@ function isForegroundSelfChainFlagEnabled(): boolean {
358
358
  if (raw == null) return false;
359
359
  const normalized = raw.trim().toLowerCase();
360
360
  return (
361
- normalized === "1" ||
362
- normalized === "true" ||
363
- normalized === "yes" ||
364
- normalized === "on"
361
+ normalized === "0" ||
362
+ normalized === "false" ||
363
+ normalized === "no" ||
364
+ normalized === "off"
365
365
  );
366
366
  }
367
367
 
368
368
  /**
369
- * Gate for the OPT-IN foreground self-chain: a normal (non-durable-background)
369
+ * Gate for the foreground self-chain: a normal (non-durable-background)
370
370
  * agent-chat turn that hits its soft-timeout chunk boundary continues via a
371
371
  * server-side self-dispatch on the REGULAR function (not a Netlify
372
372
  * `-background` function) instead of depending on the client to re-POST
373
373
  * `auto_continue`. Composes exactly like `isAgentChatDurableBackgroundEnabled`:
374
- * true only when the env flag is explicitly truthy AND the runtime is hosted
375
- * AND `A2A_SECRET` is configured (the HMAC handoff authenticates the
376
- * self-dispatch). False otherwise — and false means the existing
377
- * client-driven `auto_continue` re-POST path is used unchanged, byte-for-byte.
374
+ * true when the runtime is hosted AND `A2A_SECRET` is configured (the HMAC
375
+ * handoff authenticates the self-dispatch), unless the env flag is explicitly
376
+ * falsy. False otherwise — and false means the existing client-driven
377
+ * `auto_continue` re-POST path is used unchanged, byte-for-byte.
378
378
  *
379
379
  * Deliberately independent of `isAgentChatDurableBackgroundEnabled`: an app can
380
- * enable this narrower capability without opting into the full 15-min
380
+ * use this narrower capability without opting into the full 15-min
381
381
  * background-function worker path, and the two gates never need to agree.
382
382
  * When BOTH would be true for a given run, the durable-background dispatch
383
383
  * decision in `production-agent.ts` is evaluated first and takes precedence —
@@ -386,7 +386,7 @@ function isForegroundSelfChainFlagEnabled(): boolean {
386
386
  */
387
387
  export function isAgentChatForegroundSelfChainEnabled(): boolean {
388
388
  return (
389
- isForegroundSelfChainFlagEnabled() &&
389
+ !isForegroundSelfChainExplicitlyDisabled() &&
390
390
  isHostedRuntimeForDurableBackground() &&
391
391
  hasConfiguredA2ASecret()
392
392
  );
@@ -384,8 +384,14 @@ class AISDKEngine implements AgentEngine {
384
384
  type: "stop",
385
385
  reason: "error",
386
386
  error: err?.message ?? String(err),
387
- ...(statusCode === 401 ? { errorCode: "http_401" } : {}),
388
- ...(statusCode !== undefined ? { statusCode } : {}),
387
+ // Tag every known status with `http_<status>` (not just 401) so a
388
+ // rate limit surfaces as `http_429`. The structured statusCode
389
+ // already drives turn-level retries, but the run-level continuation
390
+ // logic keys off the errorCode, so this lets a rate-limited turn
391
+ // auto-resume too — matching the Builder gateway path.
392
+ ...(statusCode !== undefined
393
+ ? { errorCode: `http_${statusCode}`, statusCode }
394
+ : {}),
389
395
  ...(providerRetryable !== undefined ? { providerRetryable } : {}),
390
396
  };
391
397
  throw err;
@@ -227,7 +227,17 @@ class AnthropicEngine implements AgentEngine {
227
227
  type: "stop",
228
228
  reason: "error",
229
229
  error: err?.message ?? String(err),
230
- ...(statusCode === 401 ? { errorCode: "http_401", statusCode } : {}),
230
+ // Forward the provider HTTP status for EVERY known status, not just
231
+ // 401. The Anthropic SDK reports empty-body failures as a bare
232
+ // "429 status code (no body)" message, so without a structured
233
+ // statusCode/errorCode `isRetryableError` couldn't classify a rate
234
+ // limit (it matches "529"/"502" substrings but not "429") and the
235
+ // run failed hard instead of backing off + retrying like the Builder
236
+ // gateway path does. `http_429`/`http_529` also let the run-level
237
+ // continuation logic auto-resume a rate-limited turn.
238
+ ...(statusCode !== undefined
239
+ ? { errorCode: `http_${statusCode}`, statusCode }
240
+ : {}),
231
241
  };
232
242
  throw err;
233
243
  }
@@ -1132,6 +1132,7 @@ export function isRetryableError(err: unknown): boolean {
1132
1132
  return (
1133
1133
  code === "builder_gateway_error" ||
1134
1134
  code === "builder_gateway_network_error" ||
1135
+ code === "http_429" ||
1135
1136
  code === "http_500" ||
1136
1137
  code === "http_502" ||
1137
1138
  code === "http_503" ||
@@ -1140,6 +1141,9 @@ export function isRetryableError(err: unknown): boolean {
1140
1141
  // Anthropic
1141
1142
  msg.includes("overloaded") ||
1142
1143
  msg.includes("rate_limit") ||
1144
+ // Bare provider rate-limit messages that carry no structured status,
1145
+ // e.g. the Anthropic/AI-SDK "429 status code (no body)" format.
1146
+ /\b429\b/.test(msg) ||
1143
1147
  msg.includes("529") ||
1144
1148
  // OpenAI phrasing
1145
1149
  msg.includes("rate limit reached") ||
@@ -4620,8 +4624,8 @@ export const MAX_BACKGROUND_RUN_CONTINUATIONS = 20;
4620
4624
  * budget:
4621
4625
  * - a durable-background WORKER run (`isBackgroundWorker`) — unconditional,
4622
4626
  * unchanged from before; or
4623
- * - a FOREGROUND run when the opt-in `foregroundSelfChainEligible` flag is
4624
- * set (see `isAgentChatForegroundSelfChainEnabled` in
4627
+ * - a FOREGROUND run when the resolved `foregroundSelfChainEligible` gate is
4628
+ * true (see `isAgentChatForegroundSelfChainEnabled` in
4625
4629
  * `durable-background.ts`) AND this specific run was never dispatched to
4626
4630
  * the durable background worker (`dispatchedToBackground` false) — a run
4627
4631
  * already headed to the durable background path chains via the
@@ -6189,12 +6193,12 @@ export function createProductionAgentHandler(
6189
6193
  turnId: effectiveTurnId,
6190
6194
  }
6191
6195
  : null;
6192
- // Opt-in (default-OFF) foreground self-chain: gated on the env flag AND
6193
- // this specific run never having been routed to the durable background
6194
- // worker. A run that WAS dispatched to background (`dispatchToBackground`)
6195
- // already has its recovery owned by the background circuit-breaker /
6196
- // `isBackgroundWorker` chain above — this flag must never double up with
6197
- // that path, only stand in for it on plain foreground turns. A persistent
6196
+ // Foreground self-chain: gated on hosted runtime + A2A_SECRET, with an
6197
+ // explicit env opt-out, AND this specific run never having been routed to
6198
+ // the durable background worker. A run that WAS dispatched to background
6199
+ // (`dispatchToBackground`) already has its recovery owned by the background
6200
+ // circuit-breaker / `isBackgroundWorker` chain above — this flag must never
6201
+ // double up with that path, only stand in for it on plain foreground turns. A persistent
6198
6202
  // threadId is required: the client discovers the pre-inserted successor
6199
6203
  // via `/runs/active?threadId` and the successor chunk resumes from the
6200
6204
  // thread's persisted thread_data — without a thread there is neither a
@@ -6302,8 +6306,8 @@ export function createProductionAgentHandler(
6302
6306
 
6303
6307
  // Wrap so the background worker is unblocked even when there is no app
6304
6308
  // onRunComplete / tracked-progress callback configured. Also installed for
6305
- // a foreground run eligible for the opt-in self-chain — that path needs
6306
- // this same wrapper to fire the continuation dispatch below.
6309
+ // a foreground run eligible for self-chain — that path needs this same
6310
+ // wrapper to fire the continuation dispatch below.
6307
6311
  const handleRunComplete =
6308
6312
  isBackgroundWorker || foregroundSelfChainEligible || baseHandleRunComplete
6309
6313
  ? async (run: ActiveRun) => {
@@ -6897,6 +6901,9 @@ export function createProductionAgentHandler(
6897
6901
  // assistant message. Falls back to the runId (turn == run) when the
6898
6902
  // client doesn't supply a turnId.
6899
6903
  turnId: effectiveTurnId,
6904
+ dispatchMode: foregroundSelfChainEligible
6905
+ ? "foreground-self-chain"
6906
+ : "foreground",
6900
6907
  },
6901
6908
  );
6902
6909
 
@@ -6920,7 +6927,11 @@ export function createProductionAgentHandler(
6920
6927
  setResponseHeader(event, "Cache-Control", "no-cache");
6921
6928
  setResponseHeader(event, "Connection", "keep-alive");
6922
6929
  setResponseHeader(event, "X-Run-Id", runId);
6923
- setResponseHeader(event, "X-Dispatch-Mode", "foreground");
6930
+ setResponseHeader(
6931
+ event,
6932
+ "X-Dispatch-Mode",
6933
+ foregroundSelfChainEligible ? "foreground-self-chain" : "foreground",
6934
+ );
6924
6935
 
6925
6936
  return stream;
6926
6937
  });
@@ -264,6 +264,12 @@ export interface StartRunOptions {
264
264
  * and to disabled otherwise (local dev stays unbounded).
265
265
  */
266
266
  noProgressTimeoutMs?: number;
267
+ /**
268
+ * Lifecycle metadata persisted to `agent_runs.dispatch_mode` and surfaced to
269
+ * clients through `/runs/active`. This does not change run-manager behavior;
270
+ * callers use it to describe who owns continuation at hosted chunk boundaries.
271
+ */
272
+ dispatchMode?: "foreground" | "foreground-self-chain";
267
273
  }
268
274
 
269
275
  export interface ResolveRunSoftTimeoutOptions {
@@ -480,11 +486,16 @@ export function startRun(
480
486
  // Persist run to SQL without blocking the response. Keep the promise so
481
487
  // final status cannot race ahead of a slow initial INSERT and then get
482
488
  // overwritten by a late row stuck at status='running'.
483
- const insertRunPromise = insertRun(runId, threadId, options?.turnId).catch(
484
- (error) => {
485
- captureRunPersistenceError(error, "insert-run");
486
- },
487
- );
489
+ const insertOptions = options?.dispatchMode
490
+ ? { dispatchMode: options.dispatchMode }
491
+ : undefined;
492
+ const insertRunPromise = (
493
+ insertOptions
494
+ ? insertRun(runId, threadId, options?.turnId, insertOptions)
495
+ : insertRun(runId, threadId, options?.turnId)
496
+ ).catch((error) => {
497
+ captureRunPersistenceError(error, "insert-run");
498
+ });
488
499
 
489
500
  // Per-run event persistence chain: events are chained so SQL inserts commit
490
501
  // in seq order. Without this, a fast seq=5 commit before a slow seq=4 means
@@ -1356,7 +1367,7 @@ export async function getActiveRunForThreadAsync(threadId: string): Promise<{
1356
1367
  status: string;
1357
1368
  heartbeatAt: number;
1358
1369
  lastProgressAt: number | null;
1359
- /** How the run was dispatched (NULL/foreground, background, background-processing). */
1370
+ /** How the run was dispatched/continued (foreground, foreground-self-chain, background...). */
1360
1371
  dispatchMode?: string | null;
1361
1372
  /** Compact terminal classification, e.g. done, run_timeout, stale_run. */
1362
1373
  terminalReason?: string | null;
@@ -183,9 +183,11 @@ async function ensureRunTables(): Promise<void> {
183
183
  // at completion so errored/cut-off runs are queryable for
184
184
  // pattern analysis (see listErroredRuns).
185
185
  // dispatch_mode marks how a run was started: NULL/"foreground" for the
186
- // normal synchronous path, "background" for a run dispatched into a
187
- // Netlify background function. The reaper/claim widen the stale window
188
- // for background rows so a slow cold-start isn't falsely reaped.
186
+ // normal client-continued synchronous path, "foreground-self-chain" for
187
+ // a foreground run whose continuation boundary is server-driven, and
188
+ // "background" for a run dispatched into a Netlify background function.
189
+ // The reaper/claim widen the stale window for background rows so a slow
190
+ // cold-start isn't falsely reaped.
189
191
  // diag_stage records the last reached pipeline stage (+ any error) for a
190
192
  // background-dispatched run so a silent worker death is DIAGNOSABLE from
191
193
  // the client (/runs/active surfaces it) without reading the unreadable
@@ -273,9 +275,11 @@ async function ensureRunTables(): Promise<void> {
273
275
  // at completion so errored/cut-off runs are queryable for
274
276
  // pattern analysis (see listErroredRuns).
275
277
  // dispatch_mode marks how a run was started: NULL/"foreground" for the
276
- // normal synchronous path, "background" for a run dispatched into a
277
- // Netlify background function. The reaper/claim widen the stale window
278
- // for background rows so a slow cold-start isn't falsely reaped.
278
+ // normal client-continued synchronous path, "foreground-self-chain" for
279
+ // a foreground run whose continuation boundary is server-driven, and
280
+ // "background" for a run dispatched into a Netlify background function.
281
+ // The reaper/claim widen the stale window for background rows so a slow
282
+ // cold-start isn't falsely reaped.
279
283
  // diag_stage records the last reached pipeline stage (+ any error) for a
280
284
  // background-dispatched run so a silent worker death is DIAGNOSABLE from
281
285
  // the client (/runs/active surfaces it) without reading the unreadable
@@ -420,7 +424,7 @@ export async function insertRun(
420
424
  threadId: string,
421
425
  turnId?: string,
422
426
  options?: {
423
- dispatchMode?: "foreground" | "background";
427
+ dispatchMode?: "foreground" | "foreground-self-chain" | "background";
424
428
  /**
425
429
  * JSON-serialized request body for a background dispatch. Persisted on the
426
430
  * run row so the self-POST to the background function carries only the
@@ -456,10 +460,11 @@ export async function insertRun(
456
460
  * subtracted by the resolved window so the comparison is
457
461
  * `COALESCE(heartbeat_at, started_at) < (now - window)`.
458
462
  *
459
- * `dispatch_mode` is one of NULL/"foreground" (normal sync path), "background"
460
- * (foreground inserted the row for a background dispatch), or
461
- * "background-processing" (the background worker claimed it). Both background
462
- * states get the wider window via a LIKE-prefix match.
463
+ * `dispatch_mode` is one of NULL/"foreground" (normal client-continued sync
464
+ * path), "foreground-self-chain" (server-driven continuation at the foreground
465
+ * chunk boundary), "background" (foreground inserted the row for a background
466
+ * dispatch), or "background-processing" (the background worker claimed it). Both
467
+ * background states get the wider window via a LIKE-prefix match.
463
468
  */
464
469
  function backgroundAwareStaleCutoffSql(): string {
465
470
  // `CAST(? AS BIGINT)` is required: without it Postgres infers the param as
@@ -33,6 +33,16 @@ const BRIDGE_OPERATIONS = [
33
33
 
34
34
  type BridgeOperation = (typeof BRIDGE_OPERATIONS)[number];
35
35
 
36
+ const SERVER_REGISTRATION_BRIDGE_OPERATIONS = new Set<BridgeOperation>([
37
+ "select",
38
+ "resolveNodeToFile",
39
+ "readFile",
40
+ "applyEdit",
41
+ "writeFile",
42
+ "captureSnapshot",
43
+ "captureState",
44
+ ]);
45
+
36
46
  /** Additive manifest capability flags advertised alongside the operation list. */
37
47
  const MANIFEST_CAPABILITIES = {
38
48
  listFiles: true,
@@ -1276,10 +1286,12 @@ export async function startDesignConnectBridge(
1276
1286
  manifest.devServerUrl,
1277
1287
  targetUrl,
1278
1288
  );
1289
+ const includeEditorBridge =
1290
+ requestUrl.searchParams.get("bridge") !== "0";
1279
1291
  const html = injectLiveEditBridge(
1280
1292
  snapshot.html,
1281
1293
  new URL("/", manifest.bridgeUrl).toString(),
1282
- liveEditBridgeScript,
1294
+ includeEditorBridge ? liveEditBridgeScript : "",
1283
1295
  );
1284
1296
  sendText(
1285
1297
  res,
@@ -1680,7 +1692,9 @@ export async function registerConnectionWithServer(
1680
1692
  devServerUrl: manifest.devServerUrl,
1681
1693
  bridgeUrl: manifest.bridgeUrl,
1682
1694
  rootPath: manifest.rootPath,
1683
- capabilities: manifest.capabilities,
1695
+ capabilities: manifest.capabilities.filter((capability) =>
1696
+ SERVER_REGISTRATION_BRIDGE_OPERATIONS.has(capability.operation),
1697
+ ),
1684
1698
  routeManifest: {
1685
1699
  version: 1 as const,
1686
1700
  sourceType: "localhost" as const,
@@ -9,23 +9,22 @@ import { cn } from "./utils.js";
9
9
  export const DEFAULT_KEEP_TAB_OPEN_AFTER_MS = 30_000;
10
10
 
11
11
  /**
12
- * Subtle, non-blocking notice that a long-running FOREGROUND agent turn
13
- * depends on this tab staying open.
12
+ * Subtle, non-blocking notice that a long-running client-continued foreground
13
+ * agent turn depends on this tab staying open.
14
14
  *
15
15
  * On hosted deployments a foreground turn runs in ~40s chunks and the CLIENT
16
- * re-POSTs `auto_continue` to start each next chunk — close the tab
17
- * mid-turn and the work silently stops at the next chunk boundary. Only
18
- * server-driven runs (`dispatchMode` starting with "background": the durable
19
- * background worker, or a server self-chained continuation) survive a closed
20
- * tab, and for those this notice never shows.
16
+ * may need to re-POST `auto_continue` to start each next chunk. Server-owned
17
+ * runs (`dispatchMode` starting with "background" or equal to
18
+ * "foreground-self-chain") survive a closed tab, and for those this notice
19
+ * never shows.
21
20
  *
22
21
  * Visibility rules (show only while the condition is true — no new
23
22
  * always-visible chrome):
24
- * - a foreground-dispatched run for this thread has been continuously
23
+ * - a client-continued foreground run for this thread has been continuously
25
24
  * running for `showAfterMs` (default 30s — approaching the hosted ~40s
26
25
  * chunk boundary where the client-driven continuation starts), and
27
- * - the run is NOT background-dispatched (hidden immediately when the
28
- * server owns recovery), and
26
+ * - the run is not server-continued (hidden immediately when the server owns
27
+ * recovery), and
29
28
  * - this is a production client bundle (`hosted` auto-detect): local dev
30
29
  * runs a turn unbounded in a single chunk that survives a closed tab,
31
30
  * so the notice would be wrong there.
@@ -78,6 +77,13 @@ function isDevClientBundle(): boolean {
78
77
  }
79
78
  }
80
79
 
80
+ function isServerContinuedDispatch(dispatchMode: string | null): boolean {
81
+ return (
82
+ dispatchMode === "foreground-self-chain" ||
83
+ dispatchMode?.startsWith("background") === true
84
+ );
85
+ }
86
+
81
87
  export function KeepTabOpenNotice({
82
88
  threadId,
83
89
  enabled = true,
@@ -93,10 +99,9 @@ export function KeepTabOpenNotice({
93
99
  apiUrl,
94
100
  pollIntervalMs: NOTICE_POLL_INTERVAL_MS,
95
101
  });
96
- const isBackgroundDispatch =
97
- state.dispatchMode?.startsWith("background") === true;
102
+ const isServerContinued = isServerContinuedDispatch(state.dispatchMode);
98
103
  const foregroundRunning =
99
- state.status === "running" && Boolean(state.runId) && !isBackgroundDispatch;
104
+ state.status === "running" && Boolean(state.runId) && !isServerContinued;
100
105
 
101
106
  const [visible, setVisible] = useState(false);
102
107
  const runningSinceRef = useRef<number | null>(null);
@@ -109,7 +114,7 @@ export function KeepTabOpenNotice({
109
114
  }, [threadId]);
110
115
 
111
116
  useEffect(() => {
112
- if (!effectiveHosted || isBackgroundDispatch) {
117
+ if (!effectiveHosted || isServerContinued) {
113
118
  // Server-owned turn (or non-hosted client): the tab is not load-bearing.
114
119
  // Hide immediately and reset — no linger.
115
120
  runningSinceRef.current = null;
@@ -143,7 +148,7 @@ export function KeepTabOpenNotice({
143
148
  }, [
144
149
  effectiveHosted,
145
150
  foregroundRunning,
146
- isBackgroundDispatch,
151
+ isServerContinued,
147
152
  showAfterMs,
148
153
  visible,
149
154
  ]);