@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.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +161 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/correlation.ts +11 -1
- package/corpus/core/src/a2a/types.ts +11 -3
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +33 -46
- package/corpus/core/src/agent/engine/builder-engine.ts +22 -10
- package/corpus/core/src/agent/engine/error-detail.ts +184 -3
- package/corpus/core/src/agent/engine/failure-taxonomy.ts +123 -0
- package/corpus/core/src/agent/engine/index.ts +8 -0
- package/corpus/core/src/agent/engine/registry.ts +92 -8
- package/corpus/core/src/agent/engine/translate-ai-sdk.ts +17 -2
- package/corpus/core/src/agent/production-agent.ts +13 -33
- package/corpus/core/src/agent/run-loop-with-resume.ts +1 -1
- package/corpus/core/src/agent/run-manager.ts +43 -14
- package/corpus/core/src/agent/run-store.ts +30 -3
- package/corpus/core/src/agent/thread-data-builder.ts +36 -4
- package/corpus/core/src/cli/templates-meta.ts +13 -0
- package/corpus/core/src/cli/workspace-dev.ts +1 -0
- package/corpus/core/src/client/error-format.ts +12 -0
- package/corpus/core/src/credentials/index.ts +51 -12
- package/corpus/core/src/extensions/url-safety.ts +46 -12
- package/corpus/core/src/integrations/adapters/slack.ts +32 -10
- package/corpus/core/src/integrations/google-docs-poller.ts +12 -1
- package/corpus/core/src/integrations/installations-store.ts +30 -0
- package/corpus/core/src/integrations/plugin.ts +5 -5
- package/corpus/core/src/integrations/types.ts +7 -0
- package/corpus/core/src/integrations/webhook-handler.ts +24 -1
- package/corpus/core/src/jobs/background-automation-runner.ts +38 -1
- package/corpus/core/src/provider-api/index.ts +8 -2
- package/corpus/core/src/scripts/call-agent.ts +6 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +30 -9
- package/corpus/core/src/server/agent-discovery.ts +2 -0
- package/corpus/core/src/server/builder-design-systems.ts +21 -0
- package/corpus/core/src/server/credential-provider.ts +51 -12
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/server/onboarding-html.ts +37 -2
- package/corpus/core/src/shared/reasoning-effort.ts +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +6 -2
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +39 -19
- package/corpus/templates/assets/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +30 -3
- package/corpus/templates/brain/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +54 -25
- package/corpus/templates/calendar/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +30 -3
- package/corpus/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +37 -21
- package/corpus/templates/clips/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +1 -1
- package/corpus/templates/clips/desktop/src/lib/media-capture-constraints.ts +1 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +34 -17
- package/corpus/templates/content/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -2
- package/corpus/templates/design/actions/create-design-system.ts +1 -0
- package/corpus/templates/design/actions/set-default-design-system.ts +34 -26
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +21 -4
- package/corpus/templates/design/app/i18n-data.ts +39 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +229 -12
- package/corpus/templates/design/app/pages/DesignSystems.tsx +10 -4
- package/corpus/templates/design/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/corpus/templates/design/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +19 -4
- package/corpus/templates/dispatch/AGENTS.md +4 -0
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +562 -0
- package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +198 -0
- package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +115 -0
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +182 -0
- package/corpus/templates/factory/.agents/skills/capture-learnings/SKILL.md +89 -0
- package/corpus/templates/factory/.agents/skills/create-skill/SKILL.md +221 -0
- package/corpus/templates/factory/.agents/skills/customizing-agent-native/SKILL.md +220 -0
- package/corpus/templates/factory/.agents/skills/delegate-to-agent/SKILL.md +263 -0
- package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +52 -0
- package/corpus/templates/factory/.agents/skills/feature-flags/SKILL.md +169 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +174 -0
- package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +232 -0
- package/corpus/templates/factory/.agents/skills/security/SKILL.md +324 -0
- package/corpus/templates/factory/.agents/skills/self-modifying-code/SKILL.md +119 -0
- package/corpus/templates/factory/.agents/skills/shadcn-ui/SKILL.md +123 -0
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +232 -0
- package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +178 -0
- package/corpus/templates/factory/.agents/skills/upgrade-agent-native/SKILL.md +122 -0
- package/corpus/templates/factory/.env.example +24 -0
- package/corpus/templates/factory/.ignore +0 -0
- package/corpus/templates/factory/.oxfmtrc.json +8 -0
- package/corpus/templates/factory/AGENTS.md +90 -0
- package/corpus/templates/factory/CHANGELOG.md +10 -0
- package/corpus/templates/factory/DEVELOPING.md +185 -0
- package/corpus/templates/factory/README.md +64 -0
- package/corpus/templates/factory/_gitignore +42 -0
- package/corpus/templates/factory/actions/add-factory-comment.ts +55 -0
- package/corpus/templates/factory/actions/approve-factory-item.ts +214 -0
- package/corpus/templates/factory/actions/babysit-pull-request.ts +126 -0
- package/corpus/templates/factory/actions/evaluate-triage-item.ts +172 -0
- package/corpus/templates/factory/actions/get-factory-graph.ts +62 -0
- package/corpus/templates/factory/actions/get-triage-config.ts +42 -0
- package/corpus/templates/factory/actions/get-triage-item.ts +74 -0
- package/corpus/templates/factory/actions/hello.ts +13 -0
- package/corpus/templates/factory/actions/ingest-github-observation.ts +100 -0
- package/corpus/templates/factory/actions/list-factories.ts +40 -0
- package/corpus/templates/factory/actions/list-factory-comments.ts +40 -0
- package/corpus/templates/factory/actions/list-triage-items.ts +85 -0
- package/corpus/templates/factory/actions/list-triage-rules.ts +44 -0
- package/corpus/templates/factory/actions/navigate.ts +41 -0
- package/corpus/templates/factory/actions/poll-slack-channel.ts +118 -0
- package/corpus/templates/factory/actions/reconcile-triage-run.ts +179 -0
- package/corpus/templates/factory/actions/record-triage-feedback.ts +58 -0
- package/corpus/templates/factory/actions/run.ts +2 -0
- package/corpus/templates/factory/actions/save-factory-graph.ts +129 -0
- package/corpus/templates/factory/actions/save-triage-config.ts +67 -0
- package/corpus/templates/factory/actions/save-triage-rule.ts +89 -0
- package/corpus/templates/factory/actions/suggest-factory-rules.ts +70 -0
- package/corpus/templates/factory/actions/view-screen.ts +73 -0
- package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +441 -0
- package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +388 -0
- package/corpus/templates/factory/app/components/layout/Header.tsx +60 -0
- package/corpus/templates/factory/app/components/layout/Layout.tsx +190 -0
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +538 -0
- package/corpus/templates/factory/app/components/triage/triage-status-pill.tsx +28 -0
- package/corpus/templates/factory/app/components/ui/button.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/card.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/dropdown-menu.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/input.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/label.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/sheet.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/textarea.tsx +1 -0
- package/corpus/templates/factory/app/components/ui/toolkit-provider.tsx +17 -0
- package/corpus/templates/factory/app/components/ui/tooltip.tsx +1 -0
- package/corpus/templates/factory/app/design-system.ts +3 -0
- package/corpus/templates/factory/app/entry.client.tsx +22 -0
- package/corpus/templates/factory/app/entry.server.tsx +10 -0
- package/corpus/templates/factory/app/global.css +93 -0
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +113 -0
- package/corpus/templates/factory/app/i18n/en-US.ts +211 -0
- package/corpus/templates/factory/app/i18n/index.ts +34 -0
- package/corpus/templates/factory/app/i18n-data.ts +556 -0
- package/corpus/templates/factory/app/lib/agent-page.tsx +49 -0
- package/corpus/templates/factory/app/lib/app-config.ts +11 -0
- package/corpus/templates/factory/app/lib/tab-id.ts +1 -0
- package/corpus/templates/factory/app/lib/utils.ts +1 -0
- package/corpus/templates/factory/app/root.tsx +175 -0
- package/corpus/templates/factory/app/routes/_index.tsx +94 -0
- package/corpus/templates/factory/app/routes/agent.tsx +24 -0
- package/corpus/templates/factory/app/routes/chat.$threadId.tsx +1 -0
- package/corpus/templates/factory/app/routes/database.tsx +17 -0
- package/corpus/templates/factory/app/routes/extensions.$id.$slug.tsx +2 -0
- package/corpus/templates/factory/app/routes/extensions.$id.tsx +11 -0
- package/corpus/templates/factory/app/routes/extensions._index.tsx +11 -0
- package/corpus/templates/factory/app/routes/extensions.tsx +5 -0
- package/corpus/templates/factory/app/routes/factory.tsx +1003 -0
- package/corpus/templates/factory/app/routes/observability.tsx +19 -0
- package/corpus/templates/factory/app/routes/settings.tsx +89 -0
- package/corpus/templates/factory/app/routes/team.tsx +11 -0
- package/corpus/templates/factory/app/routes.ts +4 -0
- package/corpus/templates/factory/app/vite-env.d.ts +6 -0
- package/corpus/templates/factory/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +6 -0
- package/corpus/templates/factory/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +6 -0
- package/corpus/templates/factory/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +6 -0
- package/corpus/templates/factory/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/factory/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +5 -0
- package/corpus/templates/factory/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-29-sidebar-footers-now-keep-feedback-search-and-collapse-togeth.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-31-added-an-inspectable-observe-only-factory-queue-for-slack-.md +6 -0
- package/corpus/templates/factory/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/corpus/templates/factory/components.json +20 -0
- package/corpus/templates/factory/data/sync-config.json +1 -0
- package/corpus/templates/factory/learnings.defaults.md +5 -0
- package/corpus/templates/factory/netlify.toml +10 -0
- package/corpus/templates/factory/package.json +105 -0
- package/corpus/templates/factory/public/agent-native-icon-dark.svg +10 -0
- package/corpus/templates/factory/public/agent-native-icon-light.svg +10 -0
- package/corpus/templates/factory/public/agent-native-logo-dark.svg +21 -0
- package/corpus/templates/factory/public/agent-native-logo-light.svg +21 -0
- package/corpus/templates/factory/public/favicon.svg +1 -0
- package/corpus/templates/factory/public/icon-180.svg +1 -0
- package/corpus/templates/factory/public/icon-192.svg +1 -0
- package/corpus/templates/factory/public/icon-512.svg +1 -0
- package/corpus/templates/factory/public/manifest.json +21 -0
- package/corpus/templates/factory/react-router.config.ts +7 -0
- package/corpus/templates/factory/server/connectors/credentials.ts +129 -0
- package/corpus/templates/factory/server/connectors/slack.ts +129 -0
- package/corpus/templates/factory/server/db/index.ts +6 -0
- package/corpus/templates/factory/server/db/schema.ts +193 -0
- package/corpus/templates/factory/server/factory-graph/contracts.ts +212 -0
- package/corpus/templates/factory/server/factory-graph/store.ts +121 -0
- package/corpus/templates/factory/server/lib/require-workspace-member.ts +55 -0
- package/corpus/templates/factory/server/middleware/auth.ts +15 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +58 -0
- package/corpus/templates/factory/server/plugins/auth.ts +14 -0
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +247 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +116 -0
- package/corpus/templates/factory/server/plugins/integrations.ts +46 -0
- package/corpus/templates/factory/server/routes/[...page].get.ts +5 -0
- package/corpus/templates/factory/server/routes/_agent-native/factory/builder-callback.post.ts +116 -0
- package/corpus/templates/factory/server/triage/ai-services-git.ts +197 -0
- package/corpus/templates/factory/server/triage/builder-executor.ts +118 -0
- package/corpus/templates/factory/server/triage/contracts.ts +164 -0
- package/corpus/templates/factory/server/triage/github-ingestion.ts +35 -0
- package/corpus/templates/factory/server/triage/guards.ts +121 -0
- package/corpus/templates/factory/server/triage/ids.ts +27 -0
- package/corpus/templates/factory/server/triage/pr-babysit.ts +100 -0
- package/corpus/templates/factory/server/triage/pr-monitor.ts +220 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +55 -0
- package/corpus/templates/factory/server/triage/slack-poller.ts +152 -0
- package/corpus/templates/factory/ssr-entry.ts +15 -0
- package/corpus/templates/factory/tsconfig.json +21 -0
- package/corpus/templates/factory/vite.config.ts +19 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +55 -5
- package/corpus/templates/forms/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +6 -2
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +21 -6
- package/corpus/templates/plan/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +12 -0
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -0
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +11 -0
- package/corpus/templates/slides/AGENTS.md +5 -6
- package/corpus/templates/slides/actions/_await-fit-check.ts +20 -10
- package/corpus/templates/slides/actions/add-slide.ts +17 -4
- package/corpus/templates/slides/actions/create-design-system.ts +16 -4
- package/corpus/templates/slides/actions/delete-design-system.ts +18 -2
- package/corpus/templates/slides/actions/get-layout-overflows.ts +88 -0
- package/corpus/templates/slides/actions/import-file.ts +1 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +8 -0
- package/corpus/templates/slides/actions/patch-deck.ts +48 -16
- package/corpus/templates/slides/actions/set-default-design-system.ts +49 -19
- package/corpus/templates/slides/actions/update-slide.ts +13 -3
- package/corpus/templates/slides/actions/view-screen.ts +87 -10
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +155 -28
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +21 -17
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +849 -341
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +102 -2
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +13 -16
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +60 -12
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +11 -1
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +66 -19
- package/corpus/templates/slides/app/i18n/en-US.ts +23 -0
- package/corpus/templates/slides/app/lib/normalize-slide-padding.ts +8 -15
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +4 -3
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +4 -3
- package/corpus/templates/slides/app/pages/Index.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-07-31-design-system-details-now-show-their-source-and-indexing-sta.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-31-design-system-indexing-keeps-your-chosen-name-when-you-uploa.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-31-design-system-setup-keeps-focus-rings-visible-and-uses-a-sim.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-31-skip-prompt-is-now-available-in-the-new-deck-prompt-header.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-31-slides-now-detect-real-text-and-box-overflow-across-the-deck.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-31-the-agent-native-logo-stays-visible-when-the-sidebar-is-coll.md +6 -0
- package/corpus/templates/slides/server/handlers/design-systems.ts +1 -0
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +1 -0
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +23 -4
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/slides/server/plugins/creative-context.ts +16 -3
- package/corpus/templates/slides/server/workspace-defaults.ts +5 -1
- package/corpus/templates/slides/shared/slide-fit.ts +26 -0
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +30 -3
- package/corpus/templates/tasks/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/dist/a2a/correlation.d.ts +4 -1
- package/dist/a2a/correlation.d.ts.map +1 -1
- package/dist/a2a/correlation.js +8 -1
- package/dist/a2a/correlation.js.map +1 -1
- package/dist/a2a/types.d.ts +11 -3
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +27 -41
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +18 -8
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/engine/error-detail.d.ts +61 -0
- package/dist/agent/engine/error-detail.d.ts.map +1 -1
- package/dist/agent/engine/error-detail.js +145 -3
- package/dist/agent/engine/error-detail.js.map +1 -1
- package/dist/agent/engine/failure-taxonomy.d.ts +24 -0
- package/dist/agent/engine/failure-taxonomy.d.ts.map +1 -0
- package/dist/agent/engine/failure-taxonomy.js +88 -0
- package/dist/agent/engine/failure-taxonomy.js.map +1 -0
- package/dist/agent/engine/index.d.ts +2 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +2 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +16 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +71 -6
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
- package/dist/agent/engine/translate-ai-sdk.js +14 -2
- package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -24
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.js +1 -1
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +39 -10
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +10 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +20 -3
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +28 -4
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +13 -0
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +1 -0
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +10 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/credentials/index.d.ts +9 -2
- package/dist/credentials/index.d.ts.map +1 -1
- package/dist/credentials/index.js +50 -8
- package/dist/credentials/index.js.map +1 -1
- package/dist/extensions/url-safety.d.ts.map +1 -1
- package/dist/extensions/url-safety.js +38 -12
- package/dist/extensions/url-safety.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +25 -8
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/google-docs-poller.d.ts.map +1 -1
- package/dist/integrations/google-docs-poller.js +13 -1
- package/dist/integrations/google-docs-poller.js.map +1 -1
- package/dist/integrations/installations-store.d.ts +10 -0
- package/dist/integrations/installations-store.d.ts.map +1 -1
- package/dist/integrations/installations-store.js +24 -0
- package/dist/integrations/installations-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +6 -5
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/types.d.ts +7 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +16 -1
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/jobs/background-automation-runner.d.ts.map +1 -1
- package/dist/jobs/background-automation-runner.js +35 -2
- package/dist/jobs/background-automation-runner.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/provider-api/index.js +7 -3
- package/dist/provider-api/index.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +6 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +25 -7
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-discovery.d.ts +2 -0
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +4 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +11 -1
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +49 -12
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +37 -2
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/reasoning-effort.d.ts +1 -0
- package/dist/shared/reasoning-effort.d.ts.map +1 -1
- package/dist/shared/reasoning-effort.js +1 -1
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +30 -3
- package/dist/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
- package/package.json +1 -1
- package/src/a2a/correlation.ts +11 -1
- package/src/a2a/types.ts +11 -3
- package/src/agent/engine/ai-sdk-engine.ts +33 -46
- package/src/agent/engine/builder-engine.ts +22 -10
- package/src/agent/engine/error-detail.ts +184 -3
- package/src/agent/engine/failure-taxonomy.ts +123 -0
- package/src/agent/engine/index.ts +8 -0
- package/src/agent/engine/registry.ts +92 -8
- package/src/agent/engine/translate-ai-sdk.ts +17 -2
- package/src/agent/production-agent.ts +13 -33
- package/src/agent/run-loop-with-resume.ts +1 -1
- package/src/agent/run-manager.ts +43 -14
- package/src/agent/run-store.ts +30 -3
- package/src/agent/thread-data-builder.ts +36 -4
- package/src/cli/templates-meta.ts +13 -0
- package/src/cli/workspace-dev.ts +1 -0
- package/src/client/error-format.ts +12 -0
- package/src/credentials/index.ts +51 -12
- package/src/extensions/url-safety.ts +46 -12
- package/src/integrations/adapters/slack.ts +32 -10
- package/src/integrations/google-docs-poller.ts +12 -1
- package/src/integrations/installations-store.ts +30 -0
- package/src/integrations/plugin.ts +5 -5
- package/src/integrations/types.ts +7 -0
- package/src/integrations/webhook-handler.ts +24 -1
- package/src/jobs/background-automation-runner.ts +38 -1
- package/src/provider-api/index.ts +8 -2
- package/src/scripts/call-agent.ts +6 -0
- package/src/server/agent-chat-plugin.ts +30 -9
- package/src/server/agent-discovery.ts +2 -0
- package/src/server/builder-design-systems.ts +21 -0
- package/src/server/credential-provider.ts +51 -12
- package/src/server/index.ts +1 -0
- package/src/server/onboarding-html.ts +37 -2
- package/src/shared/reasoning-effort.ts +1 -1
- package/src/templates/chat/app/components/layout/Sidebar.tsx +30 -3
- package/src/templates/chat/changelog/2026-07-31-clicking-the-agent-native-logo-now-toggles-the-app-sidebar.md +6 -0
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +11 -0
- package/corpus/templates/clips/desktop/src/lib/media-device-selection.ts +0 -157
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -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
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
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
|
|
164
|
-
* caller-supplied
|
|
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 {
|
|
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
|
-
|
|
495
|
-
|
|
496
|
-
|
|
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
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
+
}
|