@agent-native/core 0.132.2 → 0.133.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (436) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +161 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/a2a/correlation.ts +11 -1
  5. package/corpus/core/src/a2a/types.ts +11 -3
  6. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +33 -46
  7. package/corpus/core/src/agent/engine/builder-engine.ts +22 -10
  8. package/corpus/core/src/agent/engine/error-detail.ts +184 -3
  9. package/corpus/core/src/agent/engine/failure-taxonomy.ts +123 -0
  10. package/corpus/core/src/agent/engine/index.ts +8 -0
  11. package/corpus/core/src/agent/engine/registry.ts +92 -8
  12. package/corpus/core/src/agent/engine/translate-ai-sdk.ts +17 -2
  13. package/corpus/core/src/agent/production-agent.ts +13 -33
  14. package/corpus/core/src/agent/run-loop-with-resume.ts +1 -1
  15. package/corpus/core/src/agent/run-manager.ts +43 -14
  16. package/corpus/core/src/agent/run-store.ts +30 -3
  17. package/corpus/core/src/agent/thread-data-builder.ts +36 -4
  18. package/corpus/core/src/cli/templates-meta.ts +13 -0
  19. package/corpus/core/src/cli/workspace-dev.ts +1 -0
  20. package/corpus/core/src/client/error-format.ts +12 -0
  21. package/corpus/core/src/credentials/index.ts +51 -12
  22. package/corpus/core/src/extensions/url-safety.ts +46 -12
  23. package/corpus/core/src/integrations/adapters/slack.ts +32 -10
  24. package/corpus/core/src/integrations/google-docs-poller.ts +12 -1
  25. package/corpus/core/src/integrations/installations-store.ts +30 -0
  26. package/corpus/core/src/integrations/plugin.ts +5 -5
  27. package/corpus/core/src/integrations/types.ts +7 -0
  28. package/corpus/core/src/integrations/webhook-handler.ts +24 -1
  29. package/corpus/core/src/jobs/background-automation-runner.ts +38 -1
  30. package/corpus/core/src/provider-api/index.ts +8 -2
  31. package/corpus/core/src/scripts/call-agent.ts +6 -0
  32. package/corpus/core/src/server/agent-chat-plugin.ts +30 -9
  33. package/corpus/core/src/server/agent-discovery.ts +2 -0
  34. package/corpus/core/src/server/builder-design-systems.ts +21 -0
  35. package/corpus/core/src/server/credential-provider.ts +51 -12
  36. package/corpus/core/src/server/index.ts +1 -0
  37. package/corpus/core/src/server/onboarding-html.ts +37 -2
  38. package/corpus/core/src/shared/reasoning-effort.ts +1 -1
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  40. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +6 -2
  41. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +39 -19
  42. package/corpus/templates/assets/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  43. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +30 -3
  44. package/corpus/templates/brain/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  45. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
  46. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +54 -25
  47. package/corpus/templates/calendar/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  48. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  49. package/corpus/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  50. package/corpus/templates/clips/app/components/library/library-layout.tsx +37 -21
  51. package/corpus/templates/clips/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  52. package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +1 -1
  53. package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +1 -1
  54. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +34 -17
  55. package/corpus/templates/content/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  56. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -2
  57. package/corpus/templates/design/actions/create-design-system.ts +1 -0
  58. package/corpus/templates/design/actions/set-default-design-system.ts +34 -26
  59. package/corpus/templates/design/app/components/layout/Sidebar.tsx +21 -4
  60. package/corpus/templates/design/app/i18n-data.ts +39 -0
  61. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +229 -12
  62. package/corpus/templates/design/app/pages/DesignSystems.tsx +10 -4
  63. package/corpus/templates/design/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  64. package/corpus/templates/design/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
  65. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +19 -4
  66. package/corpus/templates/dispatch/AGENTS.md +4 -0
  67. package/corpus/templates/factory/.agents/skills/actions/SKILL.md +562 -0
  68. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +198 -0
  69. package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +115 -0
  70. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +182 -0
  71. package/corpus/templates/factory/.agents/skills/capture-learnings/SKILL.md +89 -0
  72. package/corpus/templates/factory/.agents/skills/create-skill/SKILL.md +221 -0
  73. package/corpus/templates/factory/.agents/skills/customizing-agent-native/SKILL.md +220 -0
  74. package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +263 -0
  75. package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +52 -0
  76. package/corpus/templates/factory/.agents/skills/feature-flags/SKILL.md +169 -0
  77. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +174 -0
  78. package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +232 -0
  79. package/corpus/templates/factory/.agents/skills/security/SKILL.md +324 -0
  80. package/corpus/templates/factory/.agents/skills/self-modifying-code/SKILL.md +119 -0
  81. package/corpus/templates/factory/.agents/skills/shadcn-ui/SKILL.md +123 -0
  82. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +232 -0
  83. package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +178 -0
  84. package/corpus/templates/factory/.agents/skills/upgrade-agent-native/SKILL.md +122 -0
  85. package/corpus/templates/factory/.env.example +24 -0
  86. package/corpus/templates/factory/.ignore +0 -0
  87. package/corpus/templates/factory/.oxfmtrc.json +8 -0
  88. package/corpus/templates/factory/AGENTS.md +90 -0
  89. package/corpus/templates/factory/CHANGELOG.md +10 -0
  90. package/corpus/templates/factory/DEVELOPING.md +185 -0
  91. package/corpus/templates/factory/README.md +64 -0
  92. package/corpus/templates/factory/_gitignore +42 -0
  93. package/corpus/templates/factory/actions/add-factory-comment.ts +55 -0
  94. package/corpus/templates/factory/actions/approve-factory-item.ts +214 -0
  95. package/corpus/templates/factory/actions/babysit-pull-request.ts +126 -0
  96. package/corpus/templates/factory/actions/evaluate-triage-item.ts +172 -0
  97. package/corpus/templates/factory/actions/get-factory-graph.ts +62 -0
  98. package/corpus/templates/factory/actions/get-triage-config.ts +42 -0
  99. package/corpus/templates/factory/actions/get-triage-item.ts +74 -0
  100. package/corpus/templates/factory/actions/hello.ts +13 -0
  101. package/corpus/templates/factory/actions/ingest-github-observation.ts +100 -0
  102. package/corpus/templates/factory/actions/list-factories.ts +40 -0
  103. package/corpus/templates/factory/actions/list-factory-comments.ts +40 -0
  104. package/corpus/templates/factory/actions/list-triage-items.ts +85 -0
  105. package/corpus/templates/factory/actions/list-triage-rules.ts +44 -0
  106. package/corpus/templates/factory/actions/navigate.ts +41 -0
  107. package/corpus/templates/factory/actions/poll-slack-channel.ts +118 -0
  108. package/corpus/templates/factory/actions/reconcile-triage-run.ts +179 -0
  109. package/corpus/templates/factory/actions/record-triage-feedback.ts +58 -0
  110. package/corpus/templates/factory/actions/run.ts +2 -0
  111. package/corpus/templates/factory/actions/save-factory-graph.ts +129 -0
  112. package/corpus/templates/factory/actions/save-triage-config.ts +67 -0
  113. package/corpus/templates/factory/actions/save-triage-rule.ts +89 -0
  114. package/corpus/templates/factory/actions/suggest-factory-rules.ts +70 -0
  115. package/corpus/templates/factory/actions/view-screen.ts +73 -0
  116. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +441 -0
  117. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +388 -0
  118. package/corpus/templates/factory/app/components/layout/Header.tsx +60 -0
  119. package/corpus/templates/factory/app/components/layout/Layout.tsx +190 -0
  120. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +538 -0
  121. package/corpus/templates/factory/app/components/triage/triage-status-pill.tsx +28 -0
  122. package/corpus/templates/factory/app/components/ui/button.tsx +1 -0
  123. package/corpus/templates/factory/app/components/ui/card.tsx +1 -0
  124. package/corpus/templates/factory/app/components/ui/dropdown-menu.tsx +1 -0
  125. package/corpus/templates/factory/app/components/ui/input.tsx +1 -0
  126. package/corpus/templates/factory/app/components/ui/label.tsx +1 -0
  127. package/corpus/templates/factory/app/components/ui/sheet.tsx +1 -0
  128. package/corpus/templates/factory/app/components/ui/textarea.tsx +1 -0
  129. package/corpus/templates/factory/app/components/ui/toolkit-provider.tsx +17 -0
  130. package/corpus/templates/factory/app/components/ui/tooltip.tsx +1 -0
  131. package/corpus/templates/factory/app/design-system.ts +3 -0
  132. package/corpus/templates/factory/app/entry.client.tsx +22 -0
  133. package/corpus/templates/factory/app/entry.server.tsx +10 -0
  134. package/corpus/templates/factory/app/global.css +93 -0
  135. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +113 -0
  136. package/corpus/templates/factory/app/i18n/en-US.ts +211 -0
  137. package/corpus/templates/factory/app/i18n/index.ts +34 -0
  138. package/corpus/templates/factory/app/i18n-data.ts +556 -0
  139. package/corpus/templates/factory/app/lib/agent-page.tsx +49 -0
  140. package/corpus/templates/factory/app/lib/app-config.ts +11 -0
  141. package/corpus/templates/factory/app/lib/tab-id.ts +1 -0
  142. package/corpus/templates/factory/app/lib/utils.ts +1 -0
  143. package/corpus/templates/factory/app/root.tsx +175 -0
  144. package/corpus/templates/factory/app/routes/_index.tsx +94 -0
  145. package/corpus/templates/factory/app/routes/agent.tsx +24 -0
  146. package/corpus/templates/factory/app/routes/chat.$threadId.tsx +1 -0
  147. package/corpus/templates/factory/app/routes/database.tsx +17 -0
  148. package/corpus/templates/factory/app/routes/extensions.$id.$slug.tsx +2 -0
  149. package/corpus/templates/factory/app/routes/extensions.$id.tsx +11 -0
  150. package/corpus/templates/factory/app/routes/extensions._index.tsx +11 -0
  151. package/corpus/templates/factory/app/routes/extensions.tsx +5 -0
  152. package/corpus/templates/factory/app/routes/factory.tsx +1003 -0
  153. package/corpus/templates/factory/app/routes/observability.tsx +19 -0
  154. package/corpus/templates/factory/app/routes/settings.tsx +89 -0
  155. package/corpus/templates/factory/app/routes/team.tsx +11 -0
  156. package/corpus/templates/factory/app/routes.ts +4 -0
  157. package/corpus/templates/factory/app/vite-env.d.ts +6 -0
  158. package/corpus/templates/factory/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
  159. package/corpus/templates/factory/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
  160. package/corpus/templates/factory/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
  161. package/corpus/templates/factory/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  162. package/corpus/templates/factory/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
  163. package/corpus/templates/factory/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
  164. package/corpus/templates/factory/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  165. package/corpus/templates/factory/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  166. package/corpus/templates/factory/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
  167. package/corpus/templates/factory/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
  168. package/corpus/templates/factory/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
  169. package/corpus/templates/factory/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  170. package/corpus/templates/factory/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
  171. package/corpus/templates/factory/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
  172. package/corpus/templates/factory/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
  173. package/corpus/templates/factory/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
  174. package/corpus/templates/factory/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +6 -0
  175. package/corpus/templates/factory/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  176. package/corpus/templates/factory/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  177. package/corpus/templates/factory/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
  178. package/corpus/templates/factory/changelog/2026-07-29-sidebar-footers-now-keep-feedback-search-and-collapse-togeth.md +6 -0
  179. package/corpus/templates/factory/changelog/2026-07-31-added-an-inspectable-observe-only-factory-queue-for-slack-.md +6 -0
  180. package/corpus/templates/factory/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  181. package/corpus/templates/factory/components.json +20 -0
  182. package/corpus/templates/factory/data/sync-config.json +1 -0
  183. package/corpus/templates/factory/learnings.defaults.md +5 -0
  184. package/corpus/templates/factory/netlify.toml +10 -0
  185. package/corpus/templates/factory/package.json +105 -0
  186. package/corpus/templates/factory/public/agent-native-icon-dark.svg +10 -0
  187. package/corpus/templates/factory/public/agent-native-icon-light.svg +10 -0
  188. package/corpus/templates/factory/public/agent-native-logo-dark.svg +21 -0
  189. package/corpus/templates/factory/public/agent-native-logo-light.svg +21 -0
  190. package/corpus/templates/factory/public/favicon.svg +1 -0
  191. package/corpus/templates/factory/public/icon-180.svg +1 -0
  192. package/corpus/templates/factory/public/icon-192.svg +1 -0
  193. package/corpus/templates/factory/public/icon-512.svg +1 -0
  194. package/corpus/templates/factory/public/manifest.json +21 -0
  195. package/corpus/templates/factory/react-router.config.ts +7 -0
  196. package/corpus/templates/factory/server/connectors/credentials.ts +129 -0
  197. package/corpus/templates/factory/server/connectors/slack.ts +129 -0
  198. package/corpus/templates/factory/server/db/index.ts +6 -0
  199. package/corpus/templates/factory/server/db/schema.ts +193 -0
  200. package/corpus/templates/factory/server/factory-graph/contracts.ts +212 -0
  201. package/corpus/templates/factory/server/factory-graph/store.ts +121 -0
  202. package/corpus/templates/factory/server/lib/require-workspace-member.ts +55 -0
  203. package/corpus/templates/factory/server/middleware/auth.ts +15 -0
  204. package/corpus/templates/factory/server/plugins/agent-chat.ts +58 -0
  205. package/corpus/templates/factory/server/plugins/auth.ts +14 -0
  206. package/corpus/templates/factory/server/plugins/factory-migrations.ts +247 -0
  207. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +116 -0
  208. package/corpus/templates/factory/server/plugins/integrations.ts +46 -0
  209. package/corpus/templates/factory/server/routes/[...page].get.ts +5 -0
  210. package/corpus/templates/factory/server/routes/_agent-native/factory/builder-callback.post.ts +116 -0
  211. package/corpus/templates/factory/server/triage/ai-services-git.ts +197 -0
  212. package/corpus/templates/factory/server/triage/builder-executor.ts +118 -0
  213. package/corpus/templates/factory/server/triage/contracts.ts +164 -0
  214. package/corpus/templates/factory/server/triage/github-ingestion.ts +35 -0
  215. package/corpus/templates/factory/server/triage/guards.ts +121 -0
  216. package/corpus/templates/factory/server/triage/ids.ts +27 -0
  217. package/corpus/templates/factory/server/triage/pr-babysit.ts +100 -0
  218. package/corpus/templates/factory/server/triage/pr-monitor.ts +220 -0
  219. package/corpus/templates/factory/server/triage/slack-client.ts +55 -0
  220. package/corpus/templates/factory/server/triage/slack-poller.ts +152 -0
  221. package/corpus/templates/factory/ssr-entry.ts +15 -0
  222. package/corpus/templates/factory/tsconfig.json +21 -0
  223. package/corpus/templates/factory/vite.config.ts +19 -0
  224. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +55 -5
  225. package/corpus/templates/forms/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  226. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +6 -2
  227. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +21 -6
  228. package/corpus/templates/plan/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  229. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +12 -0
  230. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -0
  231. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +11 -0
  232. package/corpus/templates/slides/AGENTS.md +5 -6
  233. package/corpus/templates/slides/actions/_await-fit-check.ts +20 -10
  234. package/corpus/templates/slides/actions/add-slide.ts +17 -4
  235. package/corpus/templates/slides/actions/create-design-system.ts +16 -4
  236. package/corpus/templates/slides/actions/delete-design-system.ts +18 -2
  237. package/corpus/templates/slides/actions/get-layout-overflows.ts +88 -0
  238. package/corpus/templates/slides/actions/import-file.ts +1 -0
  239. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +8 -0
  240. package/corpus/templates/slides/actions/patch-deck.ts +48 -16
  241. package/corpus/templates/slides/actions/set-default-design-system.ts +49 -19
  242. package/corpus/templates/slides/actions/update-slide.ts +13 -3
  243. package/corpus/templates/slides/actions/view-screen.ts +87 -10
  244. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +155 -28
  245. package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +21 -17
  246. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +849 -341
  247. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +102 -2
  248. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +13 -16
  249. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +60 -12
  250. package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +11 -1
  251. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +66 -19
  252. package/corpus/templates/slides/app/i18n/en-US.ts +23 -0
  253. package/corpus/templates/slides/app/lib/normalize-slide-padding.ts +8 -15
  254. package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -3
  255. package/corpus/templates/slides/app/pages/DesignSystems.tsx +4 -3
  256. package/corpus/templates/slides/app/pages/Index.tsx +1 -1
  257. package/corpus/templates/slides/changelog/2026-07-31-design-system-details-now-show-their-source-and-indexing-sta.md +6 -0
  258. package/corpus/templates/slides/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
  259. package/corpus/templates/slides/changelog/2026-07-31-design-system-setup-keeps-focus-rings-visible-and-uses-a-sim.md +6 -0
  260. package/corpus/templates/slides/changelog/2026-07-31-skip-prompt-is-now-available-in-the-new-deck-prompt-header.md +6 -0
  261. package/corpus/templates/slides/changelog/2026-07-31-slides-now-detect-real-text-and-box-overflow-across-the-deck.md +6 -0
  262. package/corpus/templates/slides/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
  263. package/corpus/templates/slides/server/handlers/design-systems.ts +1 -0
  264. package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +1 -0
  265. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +23 -4
  266. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
  267. package/corpus/templates/slides/server/plugins/creative-context.ts +16 -3
  268. package/corpus/templates/slides/server/workspace-defaults.ts +5 -1
  269. package/corpus/templates/slides/shared/slide-fit.ts +26 -0
  270. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +30 -3
  271. package/corpus/templates/tasks/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  272. package/dist/a2a/correlation.d.ts +4 -1
  273. package/dist/a2a/correlation.d.ts.map +1 -1
  274. package/dist/a2a/correlation.js +8 -1
  275. package/dist/a2a/correlation.js.map +1 -1
  276. package/dist/a2a/types.d.ts +11 -3
  277. package/dist/a2a/types.d.ts.map +1 -1
  278. package/dist/a2a/types.js.map +1 -1
  279. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  280. package/dist/agent/engine/ai-sdk-engine.js +27 -41
  281. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  282. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  283. package/dist/agent/engine/builder-engine.js +18 -8
  284. package/dist/agent/engine/builder-engine.js.map +1 -1
  285. package/dist/agent/engine/error-detail.d.ts +61 -0
  286. package/dist/agent/engine/error-detail.d.ts.map +1 -1
  287. package/dist/agent/engine/error-detail.js +145 -3
  288. package/dist/agent/engine/error-detail.js.map +1 -1
  289. package/dist/agent/engine/failure-taxonomy.d.ts +24 -0
  290. package/dist/agent/engine/failure-taxonomy.d.ts.map +1 -0
  291. package/dist/agent/engine/failure-taxonomy.js +88 -0
  292. package/dist/agent/engine/failure-taxonomy.js.map +1 -0
  293. package/dist/agent/engine/index.d.ts +2 -1
  294. package/dist/agent/engine/index.d.ts.map +1 -1
  295. package/dist/agent/engine/index.js +2 -1
  296. package/dist/agent/engine/index.js.map +1 -1
  297. package/dist/agent/engine/registry.d.ts +16 -0
  298. package/dist/agent/engine/registry.d.ts.map +1 -1
  299. package/dist/agent/engine/registry.js +71 -6
  300. package/dist/agent/engine/registry.js.map +1 -1
  301. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  302. package/dist/agent/engine/translate-ai-sdk.js +14 -2
  303. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  304. package/dist/agent/production-agent.d.ts.map +1 -1
  305. package/dist/agent/production-agent.js +13 -24
  306. package/dist/agent/production-agent.js.map +1 -1
  307. package/dist/agent/run-loop-with-resume.js +1 -1
  308. package/dist/agent/run-loop-with-resume.js.map +1 -1
  309. package/dist/agent/run-manager.d.ts.map +1 -1
  310. package/dist/agent/run-manager.js +39 -10
  311. package/dist/agent/run-manager.js.map +1 -1
  312. package/dist/agent/run-store.d.ts +10 -0
  313. package/dist/agent/run-store.d.ts.map +1 -1
  314. package/dist/agent/run-store.js +20 -3
  315. package/dist/agent/run-store.js.map +1 -1
  316. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  317. package/dist/agent/thread-data-builder.js +28 -4
  318. package/dist/agent/thread-data-builder.js.map +1 -1
  319. package/dist/cli/templates-meta.d.ts.map +1 -1
  320. package/dist/cli/templates-meta.js +13 -0
  321. package/dist/cli/templates-meta.js.map +1 -1
  322. package/dist/cli/workspace-dev.d.ts.map +1 -1
  323. package/dist/cli/workspace-dev.js +1 -0
  324. package/dist/cli/workspace-dev.js.map +1 -1
  325. package/dist/client/error-format.d.ts.map +1 -1
  326. package/dist/client/error-format.js +10 -0
  327. package/dist/client/error-format.js.map +1 -1
  328. package/dist/collab/awareness.d.ts +2 -2
  329. package/dist/collab/awareness.d.ts.map +1 -1
  330. package/dist/credentials/index.d.ts +9 -2
  331. package/dist/credentials/index.d.ts.map +1 -1
  332. package/dist/credentials/index.js +50 -8
  333. package/dist/credentials/index.js.map +1 -1
  334. package/dist/extensions/url-safety.d.ts.map +1 -1
  335. package/dist/extensions/url-safety.js +38 -12
  336. package/dist/extensions/url-safety.js.map +1 -1
  337. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  338. package/dist/integrations/adapters/slack.js +25 -8
  339. package/dist/integrations/adapters/slack.js.map +1 -1
  340. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  341. package/dist/integrations/google-docs-poller.js +13 -1
  342. package/dist/integrations/google-docs-poller.js.map +1 -1
  343. package/dist/integrations/installations-store.d.ts +10 -0
  344. package/dist/integrations/installations-store.d.ts.map +1 -1
  345. package/dist/integrations/installations-store.js +24 -0
  346. package/dist/integrations/installations-store.js.map +1 -1
  347. package/dist/integrations/plugin.d.ts.map +1 -1
  348. package/dist/integrations/plugin.js +6 -5
  349. package/dist/integrations/plugin.js.map +1 -1
  350. package/dist/integrations/types.d.ts +7 -0
  351. package/dist/integrations/types.d.ts.map +1 -1
  352. package/dist/integrations/types.js.map +1 -1
  353. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  354. package/dist/integrations/webhook-handler.js +16 -1
  355. package/dist/integrations/webhook-handler.js.map +1 -1
  356. package/dist/jobs/background-automation-runner.d.ts.map +1 -1
  357. package/dist/jobs/background-automation-runner.js +35 -2
  358. package/dist/jobs/background-automation-runner.js.map +1 -1
  359. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  360. package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
  361. package/dist/notifications/routes.d.ts +3 -3
  362. package/dist/observability/routes.d.ts +3 -3
  363. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  364. package/dist/provider-api/actions/provider-api.d.ts +8 -8
  365. package/dist/provider-api/index.js +7 -3
  366. package/dist/provider-api/index.js.map +1 -1
  367. package/dist/scripts/call-agent.d.ts.map +1 -1
  368. package/dist/scripts/call-agent.js +6 -1
  369. package/dist/scripts/call-agent.js.map +1 -1
  370. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  371. package/dist/server/agent-chat-plugin.js +25 -7
  372. package/dist/server/agent-chat-plugin.js.map +1 -1
  373. package/dist/server/agent-discovery.d.ts +2 -0
  374. package/dist/server/agent-discovery.d.ts.map +1 -1
  375. package/dist/server/agent-discovery.js.map +1 -1
  376. package/dist/server/builder-design-systems.d.ts +4 -1
  377. package/dist/server/builder-design-systems.d.ts.map +1 -1
  378. package/dist/server/builder-design-systems.js +11 -1
  379. package/dist/server/builder-design-systems.js.map +1 -1
  380. package/dist/server/credential-provider.d.ts.map +1 -1
  381. package/dist/server/credential-provider.js +49 -12
  382. package/dist/server/credential-provider.js.map +1 -1
  383. package/dist/server/index.d.ts +1 -1
  384. package/dist/server/index.d.ts.map +1 -1
  385. package/dist/server/index.js.map +1 -1
  386. package/dist/server/onboarding-html.d.ts.map +1 -1
  387. package/dist/server/onboarding-html.js +37 -2
  388. package/dist/server/onboarding-html.js.map +1 -1
  389. package/dist/server/transcribe-voice.d.ts +1 -1
  390. package/dist/shared/reasoning-effort.d.ts +1 -0
  391. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  392. package/dist/shared/reasoning-effort.js +1 -1
  393. package/dist/shared/reasoning-effort.js.map +1 -1
  394. package/dist/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  395. package/dist/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  396. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  397. package/package.json +1 -1
  398. package/src/a2a/correlation.ts +11 -1
  399. package/src/a2a/types.ts +11 -3
  400. package/src/agent/engine/ai-sdk-engine.ts +33 -46
  401. package/src/agent/engine/builder-engine.ts +22 -10
  402. package/src/agent/engine/error-detail.ts +184 -3
  403. package/src/agent/engine/failure-taxonomy.ts +123 -0
  404. package/src/agent/engine/index.ts +8 -0
  405. package/src/agent/engine/registry.ts +92 -8
  406. package/src/agent/engine/translate-ai-sdk.ts +17 -2
  407. package/src/agent/production-agent.ts +13 -33
  408. package/src/agent/run-loop-with-resume.ts +1 -1
  409. package/src/agent/run-manager.ts +43 -14
  410. package/src/agent/run-store.ts +30 -3
  411. package/src/agent/thread-data-builder.ts +36 -4
  412. package/src/cli/templates-meta.ts +13 -0
  413. package/src/cli/workspace-dev.ts +1 -0
  414. package/src/client/error-format.ts +12 -0
  415. package/src/credentials/index.ts +51 -12
  416. package/src/extensions/url-safety.ts +46 -12
  417. package/src/integrations/adapters/slack.ts +32 -10
  418. package/src/integrations/google-docs-poller.ts +12 -1
  419. package/src/integrations/installations-store.ts +30 -0
  420. package/src/integrations/plugin.ts +5 -5
  421. package/src/integrations/types.ts +7 -0
  422. package/src/integrations/webhook-handler.ts +24 -1
  423. package/src/jobs/background-automation-runner.ts +38 -1
  424. package/src/provider-api/index.ts +8 -2
  425. package/src/scripts/call-agent.ts +6 -0
  426. package/src/server/agent-chat-plugin.ts +30 -9
  427. package/src/server/agent-discovery.ts +2 -0
  428. package/src/server/builder-design-systems.ts +21 -0
  429. package/src/server/credential-provider.ts +51 -12
  430. package/src/server/index.ts +1 -0
  431. package/src/server/onboarding-html.ts +37 -2
  432. package/src/shared/reasoning-effort.ts +1 -1
  433. package/src/templates/chat/app/components/layout/Sidebar.tsx +30 -3
  434. package/src/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
  435. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
  436. package/corpus/templates/clips/desktop/src/lib/media-device-selection.ts +0 -157
package/corpus/README.md CHANGED
@@ -28,6 +28,6 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
 
29
29
  ## Generated Counts
30
30
 
31
- - core files: 1645
31
+ - core files: 1646
32
32
  - toolkit files: 168
33
- - template files: 7237
33
+ - template files: 7413
@@ -1,5 +1,166 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.133.0
4
+
5
+ ### Minor Changes
6
+
7
+ - eecd3ad: Expose the measured agent failure taxonomy and let thread diagnostics separate interactive runs from scheduled `job-` runs.
8
+
9
+ ### Patch Changes
10
+
11
+ - eecd3ad: Let a delegated A2A run inherit the caller's model when the receiving app never
12
+ picked one. A cross-app turn resolved its model entirely on the receiving side,
13
+ and the stored lookup is scoped to the receiver's own app id — so selecting
14
+ Sonnet in Slides still ran any question Slides delegated to Analytics on
15
+ Analytics' default. Nothing in the request carried the caller's choice.
16
+
17
+ `call-agent` now sends the model it is running on as `callerModel` in the
18
+ existing A2A correlation metadata, and the receiver applies it strictly last
19
+ before its default: explicit config, then its own stored setting, then the
20
+ hint. An app that deliberately pins a model keeps it; the hint only fills the
21
+ gap where the receiver would otherwise take a default it never chose.
22
+
23
+ The hint is a preference, never an authorization. It is bounded to the
24
+ receiver's already-resolved engine catalog by `resolveDelegatedRunModel`, so a
25
+ peer cannot move the run to another provider, an unknown id, or a capability
26
+ tier the engine does not offer; engines that cannot prove membership (empty
27
+ catalog, OpenAI-compatible gateway) take no hint at all. A rejected hint is
28
+ logged and dropped rather than failing the delegated run, and it stays out of
29
+ every identity, org, access, and approval path.
30
+
31
+ - eecd3ad: Classify AI SDK provider failures that arrive as a stream part, not a throw.
32
+ `streamText` does not throw for a failed provider request — it emits an `error`
33
+ part on `fullStream` — so provider HTTP failures had two arrival paths and only
34
+ the thrown one was classified. The stream-part path built a bare stop event from
35
+ the message alone, discarding the `APICallError`'s `statusCode` and
36
+ `isRetryable`. Everything downstream then had nothing structured to read: a 429
37
+ or 503 was retried only if its prose happened to contain "rate_limit" or
38
+ "overloaded", and the run persisted `error_code = 'unknown'`.
39
+
40
+ That is also why a 100%-reproducible config 400 could run for three days across
41
+ five apps without anyone noticing: it was indistinguishable in the outcome
42
+ tables from every other unclassified failure, so it had no signature to alert
43
+ on.
44
+
45
+ Both paths now share one `classifyProviderError` helper — status code →
46
+ `http_<status>`, transport failure → `provider_network_error`, `isRetryable`
47
+ passed through, and a message-based fallback when the provider sent nothing
48
+ structured. Every ai-sdk provider (openai, anthropic, google, openrouter, groq,
49
+ mistral, cohere, ollama) gets correct classification at once.
50
+
51
+ - eecd3ad: Recover chats from transient provider failures instead of ending them. A
52
+ provider transport blip reached persistence with no structured error code and
53
+ was stored as `unknown`, which the client does not list as auto-recoverable —
54
+ so the turn died where the identical failure carrying its real code resumes. In
55
+ production this was measurable: `unknown` runs averaged exactly 1.00 runs per
56
+ turn (no recovery was ever attempted), against 2.0 for `provider_network_error`
57
+ and 1.5 for `http_429` on the same underlying errors.
58
+
59
+ Four divergent copies of the connection-error predicate had drifted apart, and
60
+ they disagreed on the exact string the AI SDK actually throws — `RetryError`
61
+ reports `"Failed after 2 attempts. Last error: Cannot connect to API: …"`, which
62
+ a copy anchored with `startsWith` scored as unclassified while a copy using
63
+ `includes` scored as retryable. They are now one exported classifier in
64
+ `engine/error-detail.ts`, matched against the error's full cause chain, and
65
+ applied both where the error event is built (the code the client reads) and
66
+ where the run's terminal code is persisted. Transport and capacity failures map
67
+ to their real codes; deterministic failures stay unmapped so a broken request
68
+ still stops the chat instead of spiralling.
69
+
70
+ Also stop sending `reasoning_effort` alongside function tools for GPT models on
71
+ the Builder gateway. The gateway routes them to Chat Completions, which rejects
72
+ that combination outright, so every agent turn on a `gpt-5.x` model failed
73
+ deterministically. Omitting the field does not help — only the explicit `"none"`
74
+ clears it, matching the guard the AI SDK engine already had.
75
+
76
+ - eecd3ad: Fail closed instead of silently ignoring a broken cross-isolate Stop check: a rejected abort-state read in the agent run manager no longer gets coerced into "not aborted" forever — sustained read failures now self-abort the run with a distinct, typed error. Also add the same fail-closed handling to two `isTurnAborted` call sites in the background-dispatch path that were missing it, matching the existing sibling call sites.
77
+ - eecd3ad: Stop raw provider error text (a JSON error body, an SSL handshake failure) from
78
+ being persisted as the visible assistant reply. The server-side rebuild of an
79
+ assistant message (`buildAssistantMessage`, used by every background/durable
80
+ run, reconnect-after-disconnect, poller-triggered turn, and webhook-triggered
81
+ turn) appended `event.error` verbatim, unlike the live client which already
82
+ routes it through `normalizeChatError`/`formatChatErrorText` for friendly copy.
83
+ The rebuild now uses that same layer, so persisted text always matches what a
84
+ live client would have shown, and the raw diagnostic is kept only in
85
+ `runError.details`.
86
+ - eecd3ad: Name the two deterministic provider failures that were ending chats as `unknown`: a model rejecting tools alongside `reasoning_effort`, and a missing authentication header. Both now carry a real error code and user-facing copy that says what to change, and both stay non-recoverable so nothing retries a failure a retry cannot fix.
87
+ - eecd3ad: Preserve Builder design-system source provenance on local proxy references.
88
+ - eecd3ad: Keep the signup email visible when an email-verification link opens a new tab, so the follow-up sign-in targets the verified account instead of a browser-autofilled address.
89
+ - eecd3ad: Fix a split-brain in credential resolution: `resolveCredential` (and its diagnostic sibling `describeCredentialScopeGap`) only ever searched the single org on `ctx.orgId`. Interactive requests always populate it, but CLI runs, cron/recurring jobs, and any other caller built from `getCredentialContext()` outside a request event do not — so an org-scoped key that shows "Ready" in Settings silently missed at runtime for those callers. Both functions now fall back to resolving the caller's org from their email when `ctx.orgId` is unset, and a membership lookup that fails to read now throws a retryable error instead of being reported as "not configured". `resolveRequiredCredential` in the provider-api layer now also appends the scope-gap diagnostic to its error, matching `resolveAnyCredential`.
90
+ - eecd3ad: Mark exhausted in-process agent-loop budgets as non-recoverable so the client does not restart the same exhausted run.
91
+ - eecd3ad: Run scheduled jobs, automations, and Google Docs comment replies under the background timeout regime instead of the interactive one. They were inheriting the 40s soft timeout, a 30s no-progress backstop, and 6 continuations meant for a synchronous request, so work that legitimately spends minutes across many tool calls died in the first gap longer than 30s and was recorded as `no_progress`.
92
+ - eecd3ad: Stop scheduled jobs and event automations from being killed mid-run as
93
+ "background_worker_never_started". `runBackgroundAutomation` (shared by
94
+ `jobs/scheduler.ts` and `triggers/dispatcher.ts`) executes entirely
95
+ in-process — there is no HTTP self-dispatch — but still marked its run row
96
+ `dispatch_mode = 'background'` for the wider stale window, without ever
97
+ calling `claimBackgroundRun` the way a genuine HTTP background worker does.
98
+ That left the row parked at the transient `'background'` state for the run's
99
+ entire life, indistinguishable from a lost HTTP handoff: the unclaimed-
100
+ background-run sweep reaps any such row past its 25s grace window, so a
101
+ single tool call running past 25s (routine for a report or analytics job)
102
+ got the still-executing run errored out from under it, discarding whatever
103
+ it later completed with.
104
+
105
+ The runner now self-claims its row into `'background-processing'`
106
+ immediately after inserting it — the same claimed state a real HTTP worker
107
+ reaches — which removes it from the unclaimed-sweep's eligibility (it filters
108
+ on `dispatch_mode = 'background'` exactly) and puts it under the wider,
109
+ heartbeat-driven stale window instead, with the correct `stale_run` code if
110
+ it ever genuinely dies.
111
+
112
+ - eecd3ad: Stop resending a Builder credential the gateway already rejected. Every non-Builder provider already skipped a key marked bad by an auth failure; Builder credential selection (`resolveScopedBuilderCredentials`/`resolveBuilderCredentialsDetailed` in user/org/workspace/solo scope and the deploy-env fallback, plus `hasUsableBuilderConnection` and the env-detection path in the engine registry) now consults that same marker and falls through to the next scope instead of resending the identical known-bad key on every live and scheduled turn.
113
+ - eecd3ad: Fix the Slack bot answering as the wrong app and silently dropping mentions
114
+
115
+ Outbound Slack delivery never passed an app id, so token resolution fell back
116
+ to a team-only lookup that took whichever installation was updated most
117
+ recently. A workspace with two connected Slack apps posted as whichever one
118
+ reconnected last. Outbound targets can now name an installation, and an
119
+ ambiguous tenant is reported instead of resolved to an arbitrary app.
120
+
121
+ Webhook dispatch also discarded a definitive `failed` outcome and answered the
122
+ platform 200 regardless, leaving a queued task nobody was running behind an
123
+ in-progress indicator that never resolved. That failure is now surfaced to the
124
+ user, and stuck-task recovery sweeps every dispatch mode rather than only
125
+ durable scopes — portable dispatch is the mode most likely to strand a task,
126
+ since its self-dispatch dies with the container.
127
+
128
+ - eecd3ad: Stop a retry storm from deleting the answer the user already read. A rebuild
129
+ correctly refuses to apply a _trailing_ `clear` — there is no successor chunk to
130
+ re-emit what it wipes — but it only skipped the clear at the very last index.
131
+ Each failed engine attempt emits its own `clear`, so three failures in a row is
132
+ the ordinary shape, and the rebuild still applied the first two, splicing every
133
+ text and reasoning part out of the run. When the run had made no tool calls this
134
+ emptied the content entirely and the builder returned null, so the user's
135
+ message was persisted with no assistant reply at all. The whole trailing run of
136
+ clears is now skipped; a `clear` with real events after it still applies.
137
+
138
+ Also make `terminal_reason` write-once on an already-terminal row. Three writers
139
+ in three isolates race on that column — the mid-run checkpoint, the run-manager's
140
+ finalization, and the background worker's failure path — with no ordering
141
+ between them, and last-writer-wins let a late checkpoint relabel a run another
142
+ isolate had already finalized. That produced impossible rows (`status='errored'`
143
+ carrying a continuation reason, no `error_code`, no terminal event) and
144
+ misattributed 130 production runs to a failure mode they never hit. A row that
145
+ is still `running` has no honest reason yet and stays writable.
146
+
147
+ - eecd3ad: Stop the unclaimed-background-run sweep from destroying the runs it exists to
148
+ recover. Its redispatch asserted `payloadRef: true` without checking the row
149
+ still carried a `dispatch_payload`, but sweep eligibility never implied one —
150
+ a background row can reach the grace window having never had a payload at all.
151
+ The redispatched worker then could not rehydrate a request body and failed the
152
+ run as `dispatch_payload_missing`, a reason that reads like data loss for what
153
+ is really an un-redispatchable handoff. That path accounted for 98 failed
154
+ production runs, every one of them a scheduled job.
155
+
156
+ `listUnclaimedBackgroundRunRows` now reports payload presence per row (it
157
+ reports rather than filters, so a payload-less row stays visible to the slow
158
+ sweep and cannot be stranded in `running` forever). The fast sweep skips those
159
+ rows, and the slow sweep sends them straight to its existing loud reap instead
160
+ of waiting out the redispatch bound first — the run still fails, because
161
+ nothing can rehydrate it, but with its true cause
162
+ (`background_worker_never_started`, which the client treats as recoverable).
163
+
3
164
  ## 0.132.2
4
165
 
5
166
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.132.2",
3
+ "version": "0.133.0",
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": {
@@ -5,6 +5,8 @@ export const MAX_A2A_DELEGATION_HOPS = 3;
5
5
 
6
6
  const APP_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
7
7
  const CORRELATION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
8
+ // Model ids also carry `/` (provider-prefixed gateway ids).
9
+ const MODEL_HINT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/;
8
10
 
9
11
  function boundedIdentifier(
10
12
  value: unknown,
@@ -29,7 +31,10 @@ export function sanitizeA2ACorrelationId(value: unknown): string | undefined {
29
31
  /**
30
32
  * Keep only bounded, opaque ASCII correlation identifiers. These values
31
33
  * remain telemetry hints; authentication continues to come exclusively from
32
- * the verified A2A token/request context.
34
+ * the verified A2A token/request context. `callerModel` is the one value here
35
+ * a receiver may act on, and only as a preference — it never reaches identity,
36
+ * org, access, or approval resolution, and it can only name a model the
37
+ * receiver's own engine already offers (see `resolveDelegatedRunModel`).
33
38
  */
34
39
  export function sanitizeA2ACorrelationMetadata(
35
40
  value: unknown,
@@ -41,6 +46,10 @@ export function sanitizeA2ACorrelationMetadata(
41
46
  const parentRunId = sanitizeA2ACorrelationId(metadata.parentRunId);
42
47
  const parentTurnId = sanitizeA2ACorrelationId(metadata.parentTurnId);
43
48
  const invocationId = sanitizeA2ACorrelationId(metadata.invocationId);
49
+ const callerModel = boundedIdentifier(
50
+ metadata.callerModel,
51
+ MODEL_HINT_PATTERN,
52
+ );
44
53
  const providedDelegationDepth =
45
54
  typeof metadata.delegationDepth === "number" &&
46
55
  Number.isInteger(metadata.delegationDepth) &&
@@ -77,5 +86,6 @@ export function sanitizeA2ACorrelationMetadata(
77
86
  ...(invocationId ? { invocationId } : {}),
78
87
  ...(delegationDepth !== undefined ? { delegationDepth } : {}),
79
88
  ...(visitedApps.length > 0 ? { visitedApps } : {}),
89
+ ...(callerModel ? { callerModel } : {}),
80
90
  };
81
91
  }
@@ -160,9 +160,11 @@ export interface A2ASourceContextReference {
160
160
  }
161
161
 
162
162
  /**
163
- * Telemetry-only cross-app correlation. Receivers must never use these
164
- * caller-supplied values for identity, ownership, org scoping, access, or
165
- * approval decisions.
163
+ * Telemetry-only cross-app correlation, plus `callerModel` a preference
164
+ * hint. Receivers must never use any caller-supplied value here for identity,
165
+ * ownership, org scoping, access, or approval decisions. `callerModel` widens
166
+ * this channel to a preference, never to an authorization: it may at most pick
167
+ * a model the receiver's already-resolved engine advertises.
166
168
  */
167
169
  export interface A2ACorrelationMetadata {
168
170
  callerApp?: string;
@@ -174,6 +176,12 @@ export interface A2ACorrelationMetadata {
174
176
  delegationDepth?: number;
175
177
  /** Bounded app ids already visited, used only for cycle prevention. */
176
178
  visitedApps?: string[];
179
+ /**
180
+ * Model the caller resolved for its own turn. A hint only: the receiver
181
+ * honours it just when it has no model of its own, and only after bounding
182
+ * it to its own engine's catalog.
183
+ */
184
+ callerModel?: string;
177
185
  }
178
186
 
179
187
  // --- Framework config ---
@@ -23,7 +23,10 @@ import {
23
23
  supportsClaudeAdaptiveThinking,
24
24
  } from "../../shared/reasoning-effort.js";
25
25
  import { AI_SDK_MODEL_CONFIG, type AISDKProvider } from "../model-config.js";
26
- import { describeErrorWithCauses } from "./error-detail.js";
26
+ import {
27
+ classifyProviderError,
28
+ describeErrorWithCauses,
29
+ } from "./error-detail.js";
27
30
  import {
28
31
  createFirstEventAbortController,
29
32
  FIRST_STREAM_EVENT_TIMEOUT_MS,
@@ -440,6 +443,7 @@ class AISDKEngine implements AgentEngine {
440
443
  // before it, regardless of where `finish` arrives in the stream.
441
444
  let bufferedStop: EngineEvent | undefined;
442
445
  let sawFirstEvent = false;
446
+ let credentialFailureRecorded = false;
443
447
 
444
448
  for await (const part of result.fullStream) {
445
449
  // "start" is a synthetic lifecycle marker the AI SDK enqueues
@@ -453,6 +457,21 @@ class AISDKEngine implements AgentEngine {
453
457
  }
454
458
  for (const event of aiSdkPartToEngineEvents(part)) {
455
459
  observeStreamedToolInput(toolInputs, event);
460
+ if (
461
+ event.type === "stop" &&
462
+ event.reason === "error" &&
463
+ event.statusCode === 401
464
+ ) {
465
+ await recordProviderCredentialAuthFailure({
466
+ key: PROVIDER_ENV_VARS[this.provider][0],
467
+ value: this.apiKey,
468
+ status: event.statusCode,
469
+ code: event.errorCode ?? "http_401",
470
+ message:
471
+ event.error || "The model provider rejected the saved API key.",
472
+ });
473
+ credentialFailureRecorded = true;
474
+ }
456
475
  if (event.type === "stop") {
457
476
  bufferedStop = event;
458
477
  } else {
@@ -491,47 +510,25 @@ class AISDKEngine implements AgentEngine {
491
510
  }
492
511
 
493
512
  yield { type: "assistant-content", parts: assistantContent };
494
- await clearProviderCredentialAuthFailure({
495
- key: PROVIDER_ENV_VARS[this.provider][0],
496
- value: this.apiKey,
497
- });
513
+ if (!credentialFailureRecorded) {
514
+ await clearProviderCredentialAuthFailure({
515
+ key: PROVIDER_ENV_VARS[this.provider][0],
516
+ value: this.apiKey,
517
+ });
518
+ }
498
519
  yield bufferedStop ?? { type: "stop", reason: "end_turn" };
499
520
  } catch (err: any) {
500
521
  const timedOut = firstEventAbort.didTimeout();
501
- // AI SDK wraps exhausted retries in RetryError and keeps the final
502
- // APICallError on `lastError`. Read classification fields from that
503
- // provider error so the retry wrapper does not erase transport status.
504
- const providerError =
505
- err?.lastError instanceof Error ? err.lastError : err;
506
- // Surface structured fields from AI SDK's APICallError so
507
- // isRetryableError can check statusCode/providerRetryable directly
508
- // rather than keyword-matching the message string.
509
- const statusCode: number | undefined =
510
- typeof providerError?.statusCode === "number"
511
- ? providerError.statusCode
512
- : undefined;
513
- const rawMessage: string =
514
- providerError?.message ?? String(providerError);
515
- // Classify on the bare message — the recorded `errorMessage` carries the
516
- // cause chain, which is where the real transport failure lives.
517
522
  const errorMessage = describeErrorWithCauses(err);
518
- const normalizedRawMessage = rawMessage.trim().toLowerCase();
519
- const isConnectionError =
520
- !timedOut &&
521
- statusCode === undefined &&
522
- (normalizedRawMessage === "connection error." ||
523
- normalizedRawMessage.startsWith("cannot connect to api:"));
524
- const providerRetryable: boolean | undefined =
525
- typeof providerError?.isRetryable === "boolean"
526
- ? providerError.isRetryable
527
- : isConnectionError || timedOut
528
- ? true
529
- : undefined;
530
- if (statusCode === 401) {
523
+ // Same classifier the stream-part path uses (translate-ai-sdk.ts) — a
524
+ // provider failure must not be classifiable only when it happens to
525
+ // throw.
526
+ const classification = classifyProviderError(err, timedOut);
527
+ if (classification.statusCode === 401) {
531
528
  await recordProviderCredentialAuthFailure({
532
529
  key: PROVIDER_ENV_VARS[this.provider][0],
533
530
  value: this.apiKey,
534
- status: statusCode,
531
+ status: classification.statusCode,
535
532
  code: "http_401",
536
533
  message: errorMessage,
537
534
  });
@@ -540,17 +537,7 @@ class AISDKEngine implements AgentEngine {
540
537
  type: "stop",
541
538
  reason: "error",
542
539
  error: errorMessage,
543
- // Tag every known status with `http_<status>` (not just 401) so a
544
- // rate limit surfaces as `http_429`. The structured statusCode
545
- // already drives turn-level retries, but the run-level continuation
546
- // logic keys off the errorCode, so this lets a rate-limited turn
547
- // auto-resume too — matching the Builder gateway path.
548
- ...(statusCode !== undefined
549
- ? { errorCode: `http_${statusCode}`, statusCode }
550
- : isConnectionError || timedOut
551
- ? { errorCode: "provider_network_error" }
552
- : {}),
553
- ...(providerRetryable !== undefined ? { providerRetryable } : {}),
540
+ ...classification,
554
541
  };
555
542
  throw err;
556
543
  } finally {
@@ -22,6 +22,7 @@ import {
22
22
  } from "../../server/credential-provider.js";
23
23
  import { applyBuilderUtmTrackingParams } from "../../shared/builder-link-tracking.js";
24
24
  import {
25
+ isGPTReasoningModel,
25
26
  normalizeReasoningEffortForModel,
26
27
  type ReasoningEffort,
27
28
  } from "../../shared/reasoning-effort.js";
@@ -32,7 +33,10 @@ import {
32
33
  LLM_MISSING_CREDENTIALS_ERROR_CODE,
33
34
  LLM_MISSING_CREDENTIALS_MESSAGE,
34
35
  } from "./credential-errors.js";
35
- import { describeErrorWithCauses } from "./error-detail.js";
36
+ import {
37
+ describeErrorWithCauses,
38
+ isProviderConnectionErrorMessage,
39
+ } from "./error-detail.js";
36
40
  import { FIRST_STREAM_EVENT_TIMEOUT_MS } from "./first-event-timeout.js";
37
41
  import { resolveMaxOutputTokensForEngine } from "./output-tokens.js";
38
42
  import {
@@ -235,6 +239,8 @@ class BuilderEngine implements AgentEngine {
235
239
  }
236
240
  }
237
241
 
242
+ const gptToolsRequireExplicitNoReasoning =
243
+ cachedTools.length > 0 && isGPTReasoningModel(opts.model);
238
244
  const body: Record<string, unknown> = {
239
245
  model: opts.model,
240
246
  messages: cachedMessages,
@@ -248,7 +254,21 @@ class BuilderEngine implements AgentEngine {
248
254
  ...(typeof opts.temperature === "number"
249
255
  ? { temperature: opts.temperature }
250
256
  : {}),
251
- ...(reasoningEffort ? { reasoning_effort: reasoningEffort } : {}),
257
+ // OpenAI rejects `reasoning_effort` alongside function tools on Chat
258
+ // Completions ("Function tools with reasoning_effort are not supported
259
+ // for <model> in /v1/chat/completions … or set reasoning_effort to
260
+ // 'none'"), and the gateway routes GPT models there. Every chat on a
261
+ // gpt-5.x model failed deterministically because of this. Omitting the
262
+ // field does NOT help — OpenAI then applies the model's own default
263
+ // effort and rejects identically; only the explicit "none" clears it.
264
+ // Same guard as the ai-sdk engine's forced-Chat-Completions path.
265
+ ...(reasoningEffort || gptToolsRequireExplicitNoReasoning
266
+ ? {
267
+ reasoning_effort: gptToolsRequireExplicitNoReasoning
268
+ ? "none"
269
+ : reasoningEffort,
270
+ }
271
+ : {}),
252
272
  };
253
273
 
254
274
  const gatewayBaseUrl = getBuilderGatewayBaseUrl();
@@ -1137,14 +1157,6 @@ function isBuilderGatewayNetworkError(err: unknown): boolean {
1137
1157
  );
1138
1158
  }
1139
1159
 
1140
- function isProviderConnectionErrorMessage(message: string): boolean {
1141
- const normalized = message.trim().toLowerCase();
1142
- return (
1143
- normalized === "connection error." ||
1144
- normalized.includes("cannot connect to api:")
1145
- );
1146
- }
1147
-
1148
1160
  function captureBuilderGatewayTransportError(
1149
1161
  err: unknown,
1150
1162
  context: {
@@ -8,9 +8,6 @@
8
8
  * `.cause`. Recording `err.message` alone makes every one of them
9
9
  * indistinguishable after the fact, which is how a whole class of production
10
10
  * failures becomes undiagnosable.
11
- *
12
- * Classification (`isConnectionError`, `isRetryableError`) must keep matching
13
- * on the bare `err.message` — this is for the RECORDED detail only.
14
11
  */
15
12
  const DEFAULT_MAX_CAUSE_LINKS = 4;
16
13
  const MAX_CAUSE_LINK_CHARS = 200;
@@ -37,3 +34,187 @@ export function describeErrorWithCauses(
37
34
  }
38
35
  return links.length > 0 ? `${head} (cause: ${links.join(" <- ")})` : head;
39
36
  }
37
+
38
+ /**
39
+ * The single provider-transport-failure classifier. Every layer that decides
40
+ * "is this a network blip?" — engine error codes, run-level retry, Sentry
41
+ * suppression — must call THIS, on `describeErrorWithCauses(err)` rather than
42
+ * on a bare `err.message`.
43
+ *
44
+ * Four divergent copies of this predicate existed, and they disagreed on
45
+ * exactly the string production actually throws. The AI SDK's `RetryError`
46
+ * reports `"Failed after 2 attempts. Last error: Cannot connect to API: …"`,
47
+ * so a copy anchored with `startsWith` scored it as unclassified while a copy
48
+ * using `includes` scored it as retryable. The result was a split brain: the
49
+ * agent loop retried the turn, but the run persisted `error_code = 'unknown'`,
50
+ * which the client does not list as auto-recoverable — so a transient TLS
51
+ * reset ended the user's chat with a dead error instead of resuming. That one
52
+ * mismatch accounted for ~150 failed production runs in a week.
53
+ *
54
+ * Substring matching is deliberate: the real message is always a provider SDK
55
+ * wrapper around the transport error, never bare, and the wrapper prefix
56
+ * differs per SDK and per version.
57
+ */
58
+ export function isProviderConnectionErrorMessage(message: string): boolean {
59
+ const normalized = message.toLowerCase();
60
+ return (
61
+ normalized.includes("connection error") ||
62
+ normalized.includes("cannot connect to api")
63
+ );
64
+ }
65
+
66
+ /** `isProviderConnectionErrorMessage` over an error's full cause chain. */
67
+ export function isProviderConnectionError(err: unknown): boolean {
68
+ return isProviderConnectionErrorMessage(describeErrorWithCauses(err));
69
+ }
70
+
71
+ /** Classification fields an AI SDK provider failure carries. */
72
+ export interface ProviderErrorClassification {
73
+ errorCode?: string;
74
+ statusCode?: number;
75
+ providerRetryable?: boolean;
76
+ }
77
+
78
+ /**
79
+ * Classify a provider error from the AI SDK, whichever way it surfaced.
80
+ *
81
+ * `streamText` does not throw for a failed provider request — it emits an
82
+ * `error` part on `fullStream` — so there are two arrival paths, and only the
83
+ * thrown one used to be classified. The stream-part path discarded
84
+ * `statusCode`, `errorCode`, and `isRetryable` entirely, which is why every
85
+ * provider HTTP failure on an ai-sdk engine landed as `unknown`: a 429 was only
86
+ * retried if its prose happened to contain "rate_limit", and a
87
+ * 100%-reproducible config 400 was indistinguishable from any other unclassified
88
+ * failure, so it had no signature to alert on. Both call sites go through here.
89
+ *
90
+ * `timedOut` is the caller's own first-event deadline, which only the streaming
91
+ * path can know.
92
+ */
93
+ export function classifyProviderError(
94
+ err: unknown,
95
+ timedOut = false,
96
+ ): ProviderErrorClassification {
97
+ // The AI SDK wraps exhausted retries in RetryError and keeps the final
98
+ // APICallError on `lastError`.
99
+ const wrapped = err as { lastError?: unknown } | null;
100
+ const providerError = (
101
+ wrapped?.lastError instanceof Error ? wrapped.lastError : err
102
+ ) as {
103
+ statusCode?: unknown;
104
+ isRetryable?: unknown;
105
+ message?: unknown;
106
+ } | null;
107
+
108
+ const statusCode =
109
+ typeof providerError?.statusCode === "number"
110
+ ? providerError.statusCode
111
+ : undefined;
112
+
113
+ // Classify on the cause chain of the ORIGINAL error, not the unwrapped one:
114
+ // when RetryError does not expose `lastError` as an Error the unwrap falls
115
+ // back to the wrapper, whose message ("Failed after 2 attempts. Last error:
116
+ // …") only *embeds* the transport failure. Matching the wrapper is the point.
117
+ const described = describeErrorWithCauses(err);
118
+ const isConnectionError =
119
+ !timedOut &&
120
+ statusCode === undefined &&
121
+ (isProviderConnectionErrorMessage(described) ||
122
+ isProviderConnectionErrorMessage(
123
+ typeof providerError?.message === "string"
124
+ ? providerError.message
125
+ : String(providerError),
126
+ ));
127
+
128
+ const providerRetryable =
129
+ typeof providerError?.isRetryable === "boolean"
130
+ ? providerError.isRetryable
131
+ : isConnectionError || timedOut
132
+ ? true
133
+ : undefined;
134
+
135
+ return {
136
+ // Tag every known status as `http_<status>` (not just 401) so a rate limit
137
+ // surfaces as `http_429`: the structured statusCode drives turn-level
138
+ // retries, but run-level continuation keys off the errorCode.
139
+ ...(statusCode !== undefined
140
+ ? { errorCode: `http_${statusCode}`, statusCode }
141
+ : isConnectionError || timedOut
142
+ ? { errorCode: "provider_network_error" }
143
+ : // Nothing structured — fall back to reading the message, so a
144
+ // stream-part 529/timeout is not silently unclassified.
145
+ (() => {
146
+ const code = classifyTerminalErrorCode(described);
147
+ return code ? { errorCode: code } : {};
148
+ })()),
149
+ ...(providerRetryable !== undefined ? { providerRetryable } : {}),
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Last-resort error code for a terminal error that reached persistence with no
155
+ * structured code. Persisting `"unknown"` is not a neutral default: the client
156
+ * auto-recovers a fixed list of transport codes, so an unclassified transient
157
+ * blip ends the user's chat while the identical failure carrying its real code
158
+ * resumes. Over four days that gap was 28% of ALL production chat turns.
159
+ *
160
+ * The invariant is NOT "only transport failures may be named". It is: a code
161
+ * returned here must be absent from the client's recoverable list unless a
162
+ * fresh attempt genuinely helps. Naming a deterministic failure is what stops
163
+ * it from reaching the user as raw provider text and hiding inside `unknown`;
164
+ * naming it *recoverable* is what buys a retry spiral. Those are different
165
+ * decisions, and `error-detail.spec.ts` asserts the deterministic codes below
166
+ * stay non-recoverable.
167
+ */
168
+ export function classifyTerminalErrorCode(
169
+ message: string | undefined,
170
+ ): string | undefined {
171
+ if (!message) return undefined;
172
+ const msg = message.toLowerCase();
173
+ if (isProviderConnectionErrorMessage(msg)) return "provider_network_error";
174
+ // Word-bounded: request ids and hashes routinely contain a bare "529".
175
+ if (msg.includes("overloaded") || /\b529\b/.test(msg)) {
176
+ return "overloaded_error";
177
+ }
178
+ if (msg.includes("too many requests") || /\b429\b/.test(msg)) {
179
+ return "http_429";
180
+ }
181
+ if (
182
+ msg.includes("timed out") ||
183
+ msg.includes("timeout") ||
184
+ msg.includes("too much time has passed without sending any data")
185
+ ) {
186
+ return "timeout";
187
+ }
188
+ if (msg.includes("stream ended without a stop event")) {
189
+ return "builder_gateway_network_error";
190
+ }
191
+ // Deterministic below this line — named so they stop landing in `unknown`,
192
+ // never retried. Both were measured against the 13 prod app DBs over
193
+ // 2026-07-24..31: 27 turns/week and 14 turns/week respectively, each with
194
+ // exactly 1.00 runs/turn, i.e. the chat died on the first attempt showing
195
+ // the raw provider sentence.
196
+ //
197
+ // The request side already avoids emitting reasoning_effort alongside tools
198
+ // (see ai-sdk-engine.ts). This classifies the failure for the paths that
199
+ // still reach the provider — another gateway, a stale deploy — so it reads
200
+ // as a configuration problem rather than a mystery.
201
+ if (
202
+ msg.includes("reasoning_effort are not supported") ||
203
+ msg.includes("reasoning_effort to 'none'") ||
204
+ (msg.includes("reasoning_effort") &&
205
+ (msg.includes("tools") || msg.includes("function")))
206
+ ) {
207
+ return "provider_config_error";
208
+ }
209
+ if (msg.includes("missing authentication header") || msg === "unauthorized") {
210
+ return "authentication_error";
211
+ }
212
+ if (
213
+ /(?:err_)?ssl|tlsv?\d|tls handshake|ssl routines|econnreset|econnrefused|und_err_socket|socket hang up/i.test(
214
+ message,
215
+ )
216
+ ) {
217
+ return "provider_network_error";
218
+ }
219
+ return undefined;
220
+ }