mixdog 1.2.0 → 1.2.2
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/README.md +7 -5
- package/package.json +1 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
- package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/pg/process.mjs +34 -24
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/err-text.mjs +25 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -52
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-changes.mjs +447 -219
- package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
- package/src/runtime/shared/turn-snapshot.mjs +170 -48
- package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/runtime/shared/worktrees/contract.mjs +0 -24
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +61 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +35 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/connect.mjs +83 -16
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
- package/src/session-runtime/mcp-glue.mjs +25 -2
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +83 -15
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +24 -5
- package/src/session-runtime/resource-mcp-api.mjs +198 -78
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/runtime-review-api.mjs +13 -0
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon-telemetry.mjs +55 -0
- package/src/standalone/daemon.mjs +44 -11
- package/src/standalone/session-protocol.mjs +12 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
- package/src/standalone/session-service-api.mjs +5 -0
- package/src/standalone/session-service.mjs +1 -0
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +7 -0
- package/src/tui/app/create-app-pickers.mjs +4 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +13 -16
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-commands.mjs +7 -2
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +1323 -214
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +33 -24
- package/src/tui/session/session-api/extensions.mjs +26 -2
- package/src/tui/session/session-api/integrations.mjs +7 -0
- package/src/tui/session/session-api/lifecycle.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +12 -14
- package/src/tui/session/session-flow/drain.mjs +21 -5
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +55 -15
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -2,9 +2,23 @@
|
|
|
2
2
|
// sampled: a 429 becomes a typed quota error and a transient status a
|
|
3
3
|
// retryable error; both drain the response and release its abort wiring so
|
|
4
4
|
// re-issuing the POST is safe.
|
|
5
|
-
import { noteFastModeCapacityError } from '../anthropic-fast-mode.mjs';
|
|
5
|
+
import { fastModeDowngraded, noteFastModeCapacityError } from '../anthropic-fast-mode.mjs';
|
|
6
|
+
import { applyAnthropicErrorContract, retryAfterMsFromHeaders } from '../anthropic-error-contract.mjs';
|
|
6
7
|
import { headerValue } from '../retry-classification.mjs';
|
|
7
|
-
import { classifyError
|
|
8
|
+
import { classifyError } from '../retry-classifier.mjs';
|
|
9
|
+
|
|
10
|
+
// Anthropic's exact official revoked-token 403 body; any other 403 is an
|
|
11
|
+
// ordinary permission/policy refusal and stays terminal.
|
|
12
|
+
const REVOKED_TOKEN_MARKER = 'OAuth token has been revoked';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* True when a rejected initial response is one a forced credential refresh can
|
|
16
|
+
* fix: every 401, and only the exact revoked-token 403 signature. Shared by
|
|
17
|
+
* the streaming request and the non-streaming fallback.
|
|
18
|
+
*/
|
|
19
|
+
export function isRefreshableAuthRejection(status, bodyText) {
|
|
20
|
+
return status === 401 || (status === 403 && String(bodyText ?? '').includes(REVOKED_TOKEN_MARKER));
|
|
21
|
+
}
|
|
8
22
|
|
|
9
23
|
// A subscription-window refusal carries these unified quota headers. A 429
|
|
10
24
|
// without them is an entitlement/routing refusal or a capacity blip — the
|
|
@@ -31,16 +45,13 @@ function formatRetryAfter(ms) {
|
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
export function anthropicQuotaError(status, headers, bodyText = '') {
|
|
34
|
-
const retryAfterMs =
|
|
48
|
+
const retryAfterMs = retryAfterMsFromHeaders(headers);
|
|
35
49
|
const retryAfter = formatRetryAfter(retryAfterMs);
|
|
36
50
|
const detail = bodyText ? `: ${String(bodyText).slice(0, 200)}` : '';
|
|
37
51
|
const retry = retryAfter ? ` retryAfter=${retryAfter}` : '';
|
|
38
52
|
const quota = hasQuotaHeaders(headers);
|
|
39
53
|
const err = new Error(`Anthropic OAuth API ${status} ${quota ? 'quota/rate limit' : 'request rejected'}${retry}${detail}`);
|
|
40
54
|
err.name = quota ? 'ProviderQuotaError' : 'ProviderRequestRejectedError';
|
|
41
|
-
err.code = quota ? 'PROVIDER_QUOTA' : 'PROVIDER_REQUEST_REJECTED';
|
|
42
|
-
err.httpStatus = status;
|
|
43
|
-
err.status = status;
|
|
44
55
|
err.headers = headers;
|
|
45
56
|
err.response = { status, headers };
|
|
46
57
|
err.retryAfterMs = retryAfterMs;
|
|
@@ -50,7 +61,7 @@ export function anthropicQuotaError(status, headers, bodyText = '') {
|
|
|
50
61
|
// SSE parsing can expose text or a tool call. It is therefore safe for the
|
|
51
62
|
// request-local withRetry loop. Mid-stream paths stamp unsafeToRetry when
|
|
52
63
|
// output/tool exposure actually occurs.
|
|
53
|
-
return err;
|
|
64
|
+
return applyAnthropicErrorContract(err, { status, headers, bodyText });
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
export async function judgeInitialStatus(result, requestBody, { provider, cleanupCancelHandler }) {
|
|
@@ -71,26 +82,41 @@ export async function judgeInitialStatus(result, requestBody, { provider, cleanu
|
|
|
71
82
|
// in-loop; a drained or unavailable fast pool says nothing about
|
|
72
83
|
// standard-speed capacity, so `speed` is dropped and the error is
|
|
73
84
|
// flagged for a single standard-speed replay by the caller.
|
|
74
|
-
const
|
|
75
|
-
{ httpStatus: status, headers: result?.response?.headers, message: quotaText },
|
|
76
|
-
{ fast: requestBody?.speed === 'fast' }
|
|
77
|
-
);
|
|
78
|
-
const fastDowngraded = fastDecision === 'downgrade' || fastDecision === 'disabled';
|
|
79
|
-
if (fastDowngraded) delete requestBody.speed;
|
|
85
|
+
const fastDowngraded = dropFastSpeed(requestBody, status, result?.response?.headers, quotaText);
|
|
80
86
|
throw Object.assign(anthropicQuotaError(status, result?.response?.headers, provider.scrubTokens(quotaText)), {
|
|
81
87
|
initialResponseError: true,
|
|
82
88
|
fastDowngraded,
|
|
83
89
|
});
|
|
84
90
|
}
|
|
91
|
+
let overloadText = '';
|
|
92
|
+
try {
|
|
93
|
+
overloadText = await result.response.text();
|
|
94
|
+
} catch {}
|
|
95
|
+
release();
|
|
96
|
+
// A drained fast pool (529) is replayed at standard speed within the same
|
|
97
|
+
// attempt, exactly like a fast-pool 429, instead of waiting out its window.
|
|
98
|
+
const fastDowngraded = dropFastSpeed(requestBody, status, result?.response?.headers, overloadText);
|
|
85
99
|
const err = new Error(`Anthropic OAuth API ${status}`);
|
|
86
|
-
err.httpStatus = status;
|
|
87
|
-
err.status = status;
|
|
88
100
|
err.headers = result?.response?.headers;
|
|
89
101
|
err.response = { status, headers: result?.response?.headers };
|
|
90
102
|
err.initialResponseError = true;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
err.fastDowngraded = fastDowngraded;
|
|
104
|
+
throw applyAnthropicErrorContract(err, {
|
|
105
|
+
status,
|
|
106
|
+
headers: result?.response?.headers,
|
|
107
|
+
bodyText: provider.scrubTokens(overloadText),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Records a fast-pool capacity refusal; on an explicit downgrade/disable the
|
|
112
|
+
// request drops `speed` and the caller replays once at standard speed. Any
|
|
113
|
+
// other verdict ('ignored', 'retry-fast') leaves the request untouched.
|
|
114
|
+
function dropFastSpeed(requestBody, status, headers, text) {
|
|
115
|
+
const decision = noteFastModeCapacityError(
|
|
116
|
+
{ httpStatus: status, headers, message: text },
|
|
117
|
+
{ fast: requestBody?.speed === 'fast' }
|
|
118
|
+
);
|
|
119
|
+
if (!fastModeDowngraded(decision)) return false;
|
|
120
|
+
delete requestBody.speed;
|
|
121
|
+
return true;
|
|
96
122
|
}
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
import { traceAgentFetch } from '../agent-trace.mjs';
|
|
12
12
|
import { createAbortController } from '../../../shared/abort-controller.mjs';
|
|
13
13
|
import { notifyCurrentAnthropicRateLimit } from './admission-scheduler.mjs';
|
|
14
|
-
import { noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
|
|
15
14
|
import { noteRequestServiceTier } from '../../../shared/llm/usage-context.mjs';
|
|
16
15
|
import {
|
|
17
16
|
ANTHROPIC_RETRY_BACKOFF_MS,
|
|
@@ -21,6 +20,7 @@ import {
|
|
|
21
20
|
emitProviderRetryStage,
|
|
22
21
|
withRetry,
|
|
23
22
|
} from './retry-classifier.mjs';
|
|
23
|
+
import { ANTHROPIC_MAX_CONSECUTIVE_529 } from './retry-backoff.mjs';
|
|
24
24
|
import { postMessages } from './anthropic-oauth-request/gzip-post.mjs';
|
|
25
25
|
import { removeAbortListener, wireRequestAbort } from './anthropic-oauth-request/abort-wiring.mjs';
|
|
26
26
|
import { judgeInitialStatus } from './anthropic-oauth-request/initial-status.mjs';
|
|
@@ -38,6 +38,7 @@ export { anthropicQuotaError } from './anthropic-oauth-request/initial-status.mj
|
|
|
38
38
|
* @param {AbortSignal|null} deps.totalSignal session-lifetime pass-through
|
|
39
39
|
* @param {(requestBody: object) => string} deps.betaHeadersFor
|
|
40
40
|
* @param {((stage: string) => void)|null} deps.onStageChange
|
|
41
|
+
* @param {{ state: { consecutive529Errors: number } }|null} [deps.overload] the send's shared overload counter
|
|
41
42
|
*/
|
|
42
43
|
export function createAnthropicOAuthRequest({
|
|
43
44
|
provider,
|
|
@@ -48,8 +49,10 @@ export function createAnthropicOAuthRequest({
|
|
|
48
49
|
totalSignal,
|
|
49
50
|
betaHeadersFor,
|
|
50
51
|
onStageChange,
|
|
52
|
+
overload = null,
|
|
51
53
|
}) {
|
|
52
54
|
const requestTimeoutMs = anthropicRequestTimeoutMs();
|
|
55
|
+
const isEnterprise = String(provider?.credentials?.subscriptionType || '').toLowerCase() === 'enterprise';
|
|
53
56
|
const cleanupCancelHandler = (handler) => removeAbortListener(totalSignal, handler);
|
|
54
57
|
|
|
55
58
|
const doRequest = async (accessToken, requestSignal = null, requestBody = body) => {
|
|
@@ -100,7 +103,7 @@ export function createAnthropicOAuthRequest({
|
|
|
100
103
|
try {
|
|
101
104
|
await judgeInitialStatus(result, requestBody, { provider, cleanupCancelHandler });
|
|
102
105
|
} catch (err) {
|
|
103
|
-
// Fast-pool 429 before any byte was sampled: `speed` is already
|
|
106
|
+
// Fast-pool 429/529 before any byte was sampled: `speed` is already
|
|
104
107
|
// dropped, so replay once at standard speed within this attempt.
|
|
105
108
|
if (err?.fastDowngraded !== true) throw err;
|
|
106
109
|
const replay = await doRequestImpl(accessToken, attemptSignal, requestBody);
|
|
@@ -118,23 +121,25 @@ export function createAnthropicOAuthRequest({
|
|
|
118
121
|
// Max/Pro OAuth sessions use subscription quota windows. Claude
|
|
119
122
|
// Code fails their 429s immediately rather than waiting through
|
|
120
123
|
// the API-key/PAYG retry budget (which may carry hours-long
|
|
121
|
-
// Retry-After values).
|
|
122
|
-
|
|
124
|
+
// Retry-After values). Enterprise bills PAYG-style, so its 429s
|
|
125
|
+
// are retried like an API key's.
|
|
126
|
+
retry429: isEnterprise,
|
|
123
127
|
retry529: opts.retry529,
|
|
124
128
|
perAttemptTimeoutMs: requestTimeoutMs,
|
|
125
129
|
perAttemptLabel: 'Anthropic OAuth initial response',
|
|
126
130
|
provider: 'anthropic',
|
|
131
|
+
// This transport honors the positive x-should-retry override.
|
|
132
|
+
honorShouldRetryTrue: true,
|
|
127
133
|
model: useModel,
|
|
128
134
|
fallbackModel: opts._fallbackTriggered ? undefined : opts.fallbackModel,
|
|
135
|
+
// One overload counter for the send: SSE overloads count toward the
|
|
136
|
+
// same limit as request-loop 529s.
|
|
137
|
+
overloadState: overload?.state,
|
|
138
|
+
overloadFallbackAfter: ANTHROPIC_MAX_CONSECUTIVE_529,
|
|
129
139
|
onRetry: ({ attempt, maxAttempts, lastErr, delayMs, delayReason }) => {
|
|
130
140
|
emitProviderRetryStage(onStageChange, { attempt: attempt + 1, maxAttempts, lastErr, delayMs });
|
|
131
141
|
const status = Number(lastErr?.httpStatus || lastErr?.status || lastErr?.response?.status || 0) || null;
|
|
132
142
|
if (status === 429) notifyCurrentAnthropicRateLimit(lastErr);
|
|
133
|
-
// Fast capacity exhausted: drop `speed` so the replay runs at
|
|
134
|
-
// standard speed instead of re-hitting the drained pool.
|
|
135
|
-
if (requestBody?.speed === 'fast' && noteFastModeCapacityError(lastErr, { fast: true }) !== 'retry-fast') {
|
|
136
|
-
delete requestBody.speed;
|
|
137
|
-
}
|
|
138
143
|
const reason = status || lastErr?.code || lastErr?.message || 'network error';
|
|
139
144
|
const suffix = delayReason ? ` (${delayReason})` : '';
|
|
140
145
|
try {
|
|
@@ -42,8 +42,12 @@ import { AnthropicFallbackTriggeredError } from './retry-classifier.mjs';
|
|
|
42
42
|
import { ANTHROPIC_MAX_MIDSTREAM_RETRIES, parseSSEStream, _classifyMidstreamError } from './anthropic-sse.mjs';
|
|
43
43
|
import { buildAnthropicBetaHeaders, supportsAnthropicFastMode } from './anthropic-betas.mjs';
|
|
44
44
|
import { applyAnthropicServerFallback } from './anthropic-server-fallback.mjs';
|
|
45
|
-
import { fastModeAvailable } from './anthropic-fast-mode.mjs';
|
|
45
|
+
import { fastModeAvailable, fastModeDowngraded, noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
|
|
46
46
|
import { ANTHROPIC_VERSION, anthropicQuotaError, createAnthropicOAuthRequest } from './anthropic-oauth-request.mjs';
|
|
47
|
+
import { isRefreshableAuthRejection } from './anthropic-oauth-request/initial-status.mjs';
|
|
48
|
+
import { applyAnthropicErrorContract } from './anthropic-error-contract.mjs';
|
|
49
|
+
import { adjustMaxTokensForContextOverflow } from './anthropic-max-tokens-recovery.mjs';
|
|
50
|
+
import { announceAnthropicModelFallback, createAnthropicOverloadTracker } from './anthropic-overload-fallback.mjs';
|
|
47
51
|
import { createAnthropicOAuthRecovery } from './anthropic-oauth-recovery.mjs';
|
|
48
52
|
import { createMidState, createMidstreamRecovery } from './anthropic-oauth-midstream.mjs';
|
|
49
53
|
import { assertAnthropicStreamNotEmpty } from './anthropic-midstream-recovery.mjs';
|
|
@@ -91,12 +95,6 @@ function logQuiet(line) {
|
|
|
91
95
|
if (!process.env.MIXDOG_QUIET_PROVIDER_LOG) process.stderr.write(`[anthropic-oauth] ${line}\n`);
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
function requiresSystemPrefix(model) {
|
|
95
|
-
// Every Claude OAuth model needs the first-party system prefix for OAuth
|
|
96
|
-
// pool routing; without it the server answers 429 rate_limit_error "Error".
|
|
97
|
-
return /^claude-/.test(String(model || '').toLowerCase());
|
|
98
|
-
}
|
|
99
|
-
|
|
100
98
|
function buildOAuthBetaHeaders(body, { fastMode = false, toolSearch = false, model, opts = {} } = {}) {
|
|
101
99
|
return buildAnthropicBetaHeaders({
|
|
102
100
|
base: usesAnthropicEffortBody(body) ? `${OAUTH_BETA_HEADERS},${EFFORT_CONFIGURATION_BETA}` : OAUTH_BETA_HEADERS,
|
|
@@ -114,23 +112,21 @@ function buildOAuthBetaHeaders(body, { fastMode = false, toolSearch = false, mod
|
|
|
114
112
|
// content (even the prefix concatenated with extra text in the same block)
|
|
115
113
|
// falls into the standard pool and Opus/Sonnet return 429. Splitting into
|
|
116
114
|
// two blocks — [prefix, rest] — keeps both routing and user instructions.
|
|
117
|
-
function buildSystemBlocks(systemMsgs,
|
|
115
|
+
function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
|
|
118
116
|
// systemMsgs is an array of { content, cacheTier } — each non-empty element
|
|
119
117
|
// becomes its own Anthropic content block with its own cache_control
|
|
120
118
|
// breakpoint. Blocks tagged cacheTier:'tier3' (BP3 sessionMarker) take the
|
|
121
119
|
// tier3 TTL; every other block (BP1 baseRules / BP2 stableSystem) takes the
|
|
122
120
|
// system TTL. Invariant: callers must pass an array.
|
|
123
121
|
const items = systemBlockItems(systemMsgs);
|
|
124
|
-
const gated = requiresSystemPrefix(model);
|
|
125
122
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
123
|
+
// Every model on the OAuth route is routed by this prefix block, so it is
|
|
124
|
+
// sent unconditionally rather than keyed on the model id.
|
|
125
|
+
const blocks = [{ type: 'text', text: CLAUDE_CODE_SYSTEM_PREFIX }];
|
|
130
126
|
for (let i = 0; i < items.length; i++) {
|
|
131
127
|
let body = items[i].text;
|
|
132
128
|
// Strip a duplicated OAuth system prefix from the first block if present.
|
|
133
|
-
if (
|
|
129
|
+
if (i === 0 && body.startsWith(CLAUDE_CODE_SYSTEM_PREFIX)) {
|
|
134
130
|
body = body.slice(CLAUDE_CODE_SYSTEM_PREFIX.length).trim();
|
|
135
131
|
if (!body) continue;
|
|
136
132
|
}
|
|
@@ -170,8 +166,8 @@ function buildSystemBlocks(systemMsgs, model, systemTtl, tier3Ttl) {
|
|
|
170
166
|
// 1. MIXDOG_ANTHROPIC_MAX_OUTPUT_TOKENS env override, if set, wins outright.
|
|
171
167
|
// 2. Catalog outputTokens (trusted over hardcoded heuristics when present),
|
|
172
168
|
// clamped to [MAX_TOKENS_FLOOR, safetyCap].
|
|
173
|
-
// 3.
|
|
174
|
-
// has no entry for this model
|
|
169
|
+
// 3. Shared model catalog outputTokens, then the floor, when the live
|
|
170
|
+
// roster has no entry for this model.
|
|
175
171
|
function resolveMaxTokens(model) {
|
|
176
172
|
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokens });
|
|
177
173
|
}
|
|
@@ -202,7 +198,7 @@ function buildRequestBody(messages, model, tools, sendOpts) {
|
|
|
202
198
|
// Each system message becomes its own Anthropic content block with its own
|
|
203
199
|
// breakpoint: BP1 baseRules + BP2 stableSystem at ttls.system, BP3
|
|
204
200
|
// sessionMarker (cacheTier:'tier3') at ttls.tier3.
|
|
205
|
-
const systemBlocks = buildSystemBlocks(systemMsgs,
|
|
201
|
+
const systemBlocks = buildSystemBlocks(systemMsgs, ttls?.system, ttls?.tier3);
|
|
206
202
|
|
|
207
203
|
// Message-tail cache budget (4-BP layout + ANTHROPIC_MSG_SLOTS) is shared
|
|
208
204
|
// with anthropic.mjs — see resolveAnthropicMessageCacheSlots.
|
|
@@ -480,6 +476,12 @@ export class AnthropicOAuthProvider {
|
|
|
480
476
|
// totalSignal is therefore a pure pass-through of externalSignal with no timer.
|
|
481
477
|
const totalTimeout = createPassthroughSignal(externalSignal);
|
|
482
478
|
const totalSignal = totalTimeout.signal;
|
|
479
|
+
// Request-loop 529s and SSE overload events share one counter; at the
|
|
480
|
+
// limit the configured fallback model takes over the whole send.
|
|
481
|
+
const overload = createAnthropicOverloadTracker({
|
|
482
|
+
model: useModel,
|
|
483
|
+
fallbackModel: opts._fallbackTriggered ? undefined : opts.fallbackModel,
|
|
484
|
+
});
|
|
483
485
|
const { requestWithRetry, cleanupCancelHandler } = createAnthropicOAuthRequest({
|
|
484
486
|
provider: this,
|
|
485
487
|
opts,
|
|
@@ -487,6 +489,7 @@ export class AnthropicOAuthProvider {
|
|
|
487
489
|
useModel,
|
|
488
490
|
sessionId,
|
|
489
491
|
totalSignal,
|
|
492
|
+
overload,
|
|
490
493
|
betaHeadersFor: (requestBody) =>
|
|
491
494
|
buildOAuthBetaHeaders(requestBody, {
|
|
492
495
|
fastMode: this.fastModeBetaHeaderLatched,
|
|
@@ -516,24 +519,14 @@ export class AnthropicOAuthProvider {
|
|
|
516
519
|
recovery,
|
|
517
520
|
onStageChange,
|
|
518
521
|
retry529: opts.retry529 !== false,
|
|
522
|
+
overload,
|
|
519
523
|
});
|
|
520
524
|
|
|
525
|
+
let maxTokensAdjusted = false;
|
|
521
526
|
try {
|
|
522
527
|
for (let attemptIndex = 0; attemptIndex <= ANTHROPIC_MAX_MIDSTREAM_RETRIES; attemptIndex++) {
|
|
523
528
|
let response, controller, cancelHandler;
|
|
524
|
-
|
|
525
|
-
({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
|
|
526
|
-
} catch (err) {
|
|
527
|
-
if (err instanceof AnthropicFallbackTriggeredError) {
|
|
528
|
-
process.stderr.write(`[anthropic-oauth] ${err.message}\n`);
|
|
529
|
-
return this.send(messages, err.fallbackModel, tools, {
|
|
530
|
-
...opts,
|
|
531
|
-
fallbackModel: undefined,
|
|
532
|
-
_fallbackTriggered: true,
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
throw err;
|
|
536
|
-
}
|
|
529
|
+
({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
|
|
537
530
|
|
|
538
531
|
// Refresh on 401, and only Anthropic's exact official revoked-token
|
|
539
532
|
// 403 signature. Ordinary permission/policy 403s are terminal.
|
|
@@ -541,8 +534,7 @@ export class AnthropicOAuthProvider {
|
|
|
541
534
|
if (response.status === 401 || response.status === 403) {
|
|
542
535
|
rejectedAuthBody = await response.text().catch(() => '');
|
|
543
536
|
}
|
|
544
|
-
|
|
545
|
-
if (response.status === 401 || revoked403) {
|
|
537
|
+
if (isRefreshableAuthRejection(response.status, rejectedAuthBody)) {
|
|
546
538
|
process.stderr.write(`[anthropic-oauth] ${response.status} — forcing refresh and retrying once\n`);
|
|
547
539
|
cleanupCancelHandler(cancelHandler);
|
|
548
540
|
// Body was drained above; abort closes any remaining transport
|
|
@@ -555,6 +547,20 @@ export class AnthropicOAuthProvider {
|
|
|
555
547
|
rejectedAuthBody = null;
|
|
556
548
|
}
|
|
557
549
|
|
|
550
|
+
// "input length and max_tokens exceed context limit": shrink max_tokens
|
|
551
|
+
// to what the context has room for and replay once.
|
|
552
|
+
if (response.status === 400 && !maxTokensAdjusted) {
|
|
553
|
+
rejectedAuthBody = await response.text().catch(() => '');
|
|
554
|
+
if (adjustMaxTokensForContextOverflow(body, 400, rejectedAuthBody)) {
|
|
555
|
+
maxTokensAdjusted = true;
|
|
556
|
+
cleanupCancelHandler(cancelHandler);
|
|
557
|
+
try {
|
|
558
|
+
controller?.abort?.();
|
|
559
|
+
} catch {}
|
|
560
|
+
({ response, controller, cancelHandler } = await requestWithRetry(auth.creds.accessToken));
|
|
561
|
+
rejectedAuthBody = null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
558
564
|
if (!response.ok) {
|
|
559
565
|
cleanupCancelHandler(cancelHandler);
|
|
560
566
|
return await this._resendAfterRejection({
|
|
@@ -615,6 +621,18 @@ export class AnthropicOAuthProvider {
|
|
|
615
621
|
}
|
|
616
622
|
}
|
|
617
623
|
throw midstream.exhaustedError();
|
|
624
|
+
} catch (err) {
|
|
625
|
+
// The fallback trigger can surface from the request loop, a mid-stream
|
|
626
|
+
// overload, or the non-streaming recovery: handle it around the whole
|
|
627
|
+
// operation, not just the first request.
|
|
628
|
+
if (!(err instanceof AnthropicFallbackTriggeredError)) throw err;
|
|
629
|
+
process.stderr.write(`[anthropic-oauth] ${err.message}\n`);
|
|
630
|
+
announceAnthropicModelFallback(onStageChange, _displayModel(useModel), _displayModel(err.fallbackModel));
|
|
631
|
+
return await this.send(messages, err.fallbackModel, tools, {
|
|
632
|
+
...opts,
|
|
633
|
+
fallbackModel: undefined,
|
|
634
|
+
_fallbackTriggered: true,
|
|
635
|
+
});
|
|
618
636
|
} finally {
|
|
619
637
|
totalTimeout.cleanup();
|
|
620
638
|
}
|
|
@@ -632,6 +650,21 @@ export class AnthropicOAuthProvider {
|
|
|
632
650
|
throw anthropicQuotaError(response.status, response.headers, safeText);
|
|
633
651
|
}
|
|
634
652
|
|
|
653
|
+
// An account that cannot use fast mode answers the speed field with a
|
|
654
|
+
// 400. Fast mode is now off for this process, so replaying the turn once
|
|
655
|
+
// builds a standard-speed request.
|
|
656
|
+
if (
|
|
657
|
+
response.status === 400 &&
|
|
658
|
+
opts.fast === true &&
|
|
659
|
+
!opts._fastModeRetry &&
|
|
660
|
+
fastModeDowngraded(
|
|
661
|
+
noteFastModeCapacityError({ httpStatus: 400, message: scrubbedText }, { fast: true })
|
|
662
|
+
)
|
|
663
|
+
) {
|
|
664
|
+
process.stderr.write(`[anthropic-oauth] fast mode is not enabled for this account; retrying at standard speed\n`);
|
|
665
|
+
return this.send(messages, useModel, tools, { ...opts, _fastModeRetry: true });
|
|
666
|
+
}
|
|
667
|
+
|
|
635
668
|
// A newer model that rejects the mid-conversation effort update: switch
|
|
636
669
|
// the updates off for it in this process and replay the turn once
|
|
637
670
|
// without them (the request keeps its turn effort).
|
|
@@ -694,9 +727,14 @@ export class AnthropicOAuthProvider {
|
|
|
694
727
|
return this.send(messages, fallbackModel || model, tools, { ...opts, _modelRetry: true });
|
|
695
728
|
}
|
|
696
729
|
const err = new Error(`Anthropic OAuth API ${response.status}: ${safeText}`);
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
730
|
+
// 413 stays `request_too_large` (a byte/media size refusal) and a 400
|
|
731
|
+
// "prompt is too long" stays `invalid_request_error`, so the core can tell
|
|
732
|
+
// a payload it must shrink from a context it can compact.
|
|
733
|
+
throw applyAnthropicErrorContract(err, {
|
|
734
|
+
status: response.status,
|
|
735
|
+
headers: response.headers,
|
|
736
|
+
bodyText: scrubbedText,
|
|
737
|
+
});
|
|
700
738
|
}
|
|
701
739
|
|
|
702
740
|
// Traces + catalog upkeep for a streamed turn, then the empty-stream guard.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* anthropic-overload-fallback.mjs — one overload counter per logical send,
|
|
3
|
+
* shared by the request loop (HTTP 529 before a stream exists) and the SSE
|
|
4
|
+
* parser (`overloaded_error` event after one started). Both reach it through
|
|
5
|
+
* the same error fields — `status: 529` / `code: 'overloaded_error'` — so a
|
|
6
|
+
* mix of the two trips the configured fallback model after the same number of
|
|
7
|
+
* consecutive overloads, instead of each path counting only its own.
|
|
8
|
+
*
|
|
9
|
+
* The request loop's counter is withRetry's `overloadState`; this tracker owns
|
|
10
|
+
* that object, so the SSE path increments the very counter the loop reads.
|
|
11
|
+
*/
|
|
12
|
+
import { ANTHROPIC_MAX_CONSECUTIVE_529 } from './retry-backoff.mjs';
|
|
13
|
+
import { AnthropicFallbackTriggeredError } from './retry-classifier.mjs';
|
|
14
|
+
|
|
15
|
+
export const OVERLOADED_ERROR_CODE = 'overloaded_error';
|
|
16
|
+
|
|
17
|
+
/** Consecutive 529s end the request only for API-key (non-subscriber) first-party Opus. */
|
|
18
|
+
export function isTerminalOverloadModel(model) {
|
|
19
|
+
return /^claude-opus-/.test(String(model || '').trim().toLowerCase());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isAnthropicOverloadError(err) {
|
|
23
|
+
const status = Number(err?.httpStatus || err?.status || err?.response?.status || 0);
|
|
24
|
+
return status === 529 || String(err?.code || '').toLowerCase() === OVERLOADED_ERROR_CODE;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {{ model: string, fallbackModel?: string|null, terminalAtLimit?: boolean }} deps fallbackModel is
|
|
29
|
+
* already undefined when this send IS the fallback (no second hop).
|
|
30
|
+
*/
|
|
31
|
+
export function createAnthropicOverloadTracker({ model, fallbackModel, terminalAtLimit = false }) {
|
|
32
|
+
const canFallback = Boolean(fallbackModel) && fallbackModel !== model;
|
|
33
|
+
// Handed to every withRetry of the send as `overloadState`: the request
|
|
34
|
+
// loop increments this same object on each 529.
|
|
35
|
+
const state = { consecutive529Errors: 0 };
|
|
36
|
+
return {
|
|
37
|
+
state,
|
|
38
|
+
// Repeated-overload stop, handed to withRetry as `stopAfterRepeated529`: with no
|
|
39
|
+
// fallback model, API-key Opus stops after repeated 529s. A configured
|
|
40
|
+
// fallback always wins (the executor checks it first).
|
|
41
|
+
stopAfterRepeated529: terminalAtLimit && !canFallback,
|
|
42
|
+
/**
|
|
43
|
+
* An overload SSE error. Returns the fallback trigger to throw once the
|
|
44
|
+
* consecutive limit is reached and a fallback model is configured.
|
|
45
|
+
*/
|
|
46
|
+
noteStreamOverload(err) {
|
|
47
|
+
state.consecutive529Errors += 1;
|
|
48
|
+
if (state.consecutive529Errors < ANTHROPIC_MAX_CONSECUTIVE_529) return null;
|
|
49
|
+
if (canFallback) return new AnthropicFallbackTriggeredError(model, fallbackModel, err);
|
|
50
|
+
// No fallback model: API-key Opus stops here ("Repeated 529 Overloaded
|
|
51
|
+
// errors") instead of spending the full budget.
|
|
52
|
+
if (!terminalAtLimit) return null;
|
|
53
|
+
err.repeated529 = true;
|
|
54
|
+
return err;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Visible model-switch notice on the existing display-only stage channel. */
|
|
60
|
+
export function announceAnthropicModelFallback(onStageChange, fromLabel, toLabel) {
|
|
61
|
+
if (typeof onStageChange !== 'function') return;
|
|
62
|
+
try {
|
|
63
|
+
onStageChange('reconnecting', {
|
|
64
|
+
message: `${fromLabel} is overloaded — continuing on ${toLabel}`,
|
|
65
|
+
});
|
|
66
|
+
} catch {
|
|
67
|
+
/* display-only */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -6,6 +6,10 @@ function normalizedModelId(value) {
|
|
|
6
6
|
return typeof raw === 'string' ? raw.trim() : '';
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
// Kept as an id pattern: no catalog field declares server-side fallback, and
|
|
10
|
+
// `fallbacks` is a beta-gated body field other models reject (a wrong "yes" is
|
|
11
|
+
// a 400, a wrong "no" only skips an optional refusal fallback), so unknown ids
|
|
12
|
+
// stay off.
|
|
9
13
|
export function supportsAnthropicServerFallback(model) {
|
|
10
14
|
const id = normalizeClaudeModelId(normalizedModelId(model));
|
|
11
15
|
return /^claude-(?:opus|fable)-5(?:$|[-@])/.test(id);
|
|
@@ -109,6 +109,13 @@ function _anthropicSseError(event, labels) {
|
|
|
109
109
|
err.httpStatus = status;
|
|
110
110
|
err.status = status;
|
|
111
111
|
}
|
|
112
|
+
// Provider-boundary contract: `code` is the lowercased Anthropic error type
|
|
113
|
+
// (an overload carries `overloaded_error` + 529, which the overload counter
|
|
114
|
+
// reads); an untyped `error` frame keeps the generic SSE code. A 413 is a
|
|
115
|
+
// byte-size refusal, never a prompt-token one.
|
|
116
|
+
const wireType = typeof type === 'string' ? type.trim().toLowerCase() : '';
|
|
117
|
+
if (status === 413) err.code = 'request_too_large';
|
|
118
|
+
else if (wireType && wireType !== 'error') err.code = wireType;
|
|
112
119
|
// Wire-error marker: an error type OUTSIDE the documented enumeration
|
|
113
120
|
// (no status resolved above) default-retries under the shared wire-error
|
|
114
121
|
// contract instead of failing the turn as 'unknown'. Typed statuses and
|
|
@@ -162,7 +169,7 @@ function applyAnthropicSseEvent(framedEvent, { turn, watchdogs, state, progress,
|
|
|
162
169
|
return false;
|
|
163
170
|
}
|
|
164
171
|
} catch (err) {
|
|
165
|
-
if (err?.
|
|
172
|
+
if (err?.name === 'AnthropicSseError') throw err;
|
|
166
173
|
/* skip malformed events */
|
|
167
174
|
return false;
|
|
168
175
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { reloadProviderApiKey, resolveProviderApiKey } from '../../../shared/provider-api-key.mjs';
|
|
2
2
|
import { sanitizeToolPairs } from '../session/context-utils.mjs';
|
|
3
3
|
import { AnthropicFallbackTriggeredError } from './retry-classifier.mjs';
|
|
4
|
+
import {
|
|
5
|
+
announceAnthropicModelFallback,
|
|
6
|
+
createAnthropicOverloadTracker,
|
|
7
|
+
isTerminalOverloadModel,
|
|
8
|
+
} from './anthropic-overload-fallback.mjs';
|
|
4
9
|
import { readStreamOutcome } from './lib/stream-outcome.mjs';
|
|
5
10
|
import { createPassthroughSignal } from '../stall-policy.mjs';
|
|
6
11
|
import { createAbortController } from '../../../shared/abort-controller.mjs';
|
|
@@ -42,9 +47,19 @@ export class AnthropicProvider {
|
|
|
42
47
|
constructor(config) {
|
|
43
48
|
this.config = config || {};
|
|
44
49
|
this.name = this.config.name || 'anthropic';
|
|
45
|
-
this.apiKey =
|
|
50
|
+
this.apiKey = resolveProviderApiKey(this.name, this.config) || null;
|
|
46
51
|
this.client = this._createClient(this.apiKey);
|
|
47
52
|
}
|
|
53
|
+
// Client for the currently resolved key; rebuilt when the key changed since
|
|
54
|
+
// it was built (e.g. a keyless-constructed instance).
|
|
55
|
+
_currentClient() {
|
|
56
|
+
const key = resolveProviderApiKey(this.name, this.config) || null;
|
|
57
|
+
if (key && key !== this.apiKey) {
|
|
58
|
+
this.apiKey = key;
|
|
59
|
+
this.client = this._createClient(key);
|
|
60
|
+
}
|
|
61
|
+
return this.client;
|
|
62
|
+
}
|
|
48
63
|
// Tool-search is a request capability, not an account capability. Keep it
|
|
49
64
|
// off the client defaults and add it only on turns that actually serialize
|
|
50
65
|
// defer_loading tools.
|
|
@@ -55,8 +70,10 @@ export class AnthropicProvider {
|
|
|
55
70
|
const custom = isCustomProviderName(this.name);
|
|
56
71
|
const keyless = custom && this.config.keyless === true;
|
|
57
72
|
const betaHeaders = this.config.disableBetaHeaders || custom ? null : buildAnthropicBetaHeaders();
|
|
73
|
+
let credentials = { apiKey };
|
|
74
|
+
if (custom) credentials = { apiKey: keyless ? '' : apiKey || '', authToken: null };
|
|
58
75
|
return new (loadAnthropic())({
|
|
59
|
-
...
|
|
76
|
+
...credentials,
|
|
60
77
|
...(this.config.baseURL ? { baseURL: this.config.baseURL } : {}),
|
|
61
78
|
defaultHeaders: {
|
|
62
79
|
...(betaHeaders ? { 'anthropic-beta': betaHeaders } : {}),
|
|
@@ -68,10 +85,7 @@ export class AnthropicProvider {
|
|
|
68
85
|
}
|
|
69
86
|
reloadApiKey() {
|
|
70
87
|
try {
|
|
71
|
-
const newKey =
|
|
72
|
-
getAgentApiKey(this.name) ||
|
|
73
|
-
this.config.apiKey ||
|
|
74
|
-
(this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
|
|
88
|
+
const newKey = reloadProviderApiKey(this.name, this.config);
|
|
75
89
|
if (newKey) {
|
|
76
90
|
this.config = { ...(this.config || {}), apiKey: newKey };
|
|
77
91
|
this.apiKey = newKey;
|
|
@@ -157,16 +171,24 @@ export class AnthropicProvider {
|
|
|
157
171
|
} catch {}
|
|
158
172
|
};
|
|
159
173
|
|
|
174
|
+
// Request-loop 529s and SSE overload events share one counter; at the
|
|
175
|
+
// limit the configured fallback model takes over the whole send.
|
|
176
|
+
const overload = createAnthropicOverloadTracker({
|
|
177
|
+
model: useModel,
|
|
178
|
+
fallbackModel: opts._fallbackTriggered ? undefined : opts.fallbackModel,
|
|
179
|
+
terminalAtLimit: !isCustomProviderName(this.name) && isTerminalOverloadModel(useModel),
|
|
180
|
+
});
|
|
160
181
|
// The SDK calls and their initial-response retry policy
|
|
161
182
|
// (anthropic-api-transport.mjs).
|
|
162
183
|
const transport = createAnthropicApiTransport({
|
|
163
|
-
client: this.
|
|
184
|
+
client: this._currentClient(),
|
|
164
185
|
label: this.name,
|
|
165
186
|
opts,
|
|
166
187
|
useModel,
|
|
167
188
|
params,
|
|
168
189
|
requestHeaders,
|
|
169
190
|
totalSignal,
|
|
191
|
+
overload,
|
|
170
192
|
});
|
|
171
193
|
// Usage accounting + caller-visible projection, shared by the streaming
|
|
172
194
|
// success path and the non-streaming fallback (anthropic-turn-result.mjs).
|
|
@@ -204,8 +226,10 @@ export class AnthropicProvider {
|
|
|
204
226
|
recovery,
|
|
205
227
|
onStageChange,
|
|
206
228
|
retry529: opts.retry529 !== false,
|
|
229
|
+
overload,
|
|
207
230
|
});
|
|
208
231
|
|
|
232
|
+
let streamingFallbackTried = false;
|
|
209
233
|
try {
|
|
210
234
|
for (let attemptIndex = 0; attemptIndex <= ANTHROPIC_MAX_MIDSTREAM_RETRIES; attemptIndex++) {
|
|
211
235
|
const streamController = createAbortController();
|
|
@@ -265,13 +289,13 @@ export class AnthropicProvider {
|
|
|
265
289
|
|
|
266
290
|
return buildTurnResult(parseResult);
|
|
267
291
|
} catch (err) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
292
|
+
// The fallback trigger is handled around the whole send below.
|
|
293
|
+
if (err instanceof AnthropicFallbackTriggeredError) throw err;
|
|
294
|
+
// Gateways that 404 the streaming endpoint but serve non-streaming:
|
|
295
|
+
// one non-streaming replay (nothing was streamed yet).
|
|
296
|
+
if (err?.initialResponseError === true && Number(err.status) === 404 && !streamingFallbackTried) {
|
|
297
|
+
streamingFallbackTried = true;
|
|
298
|
+
return await recovery.issueNonStreamingFallback(streamController, err);
|
|
275
299
|
}
|
|
276
300
|
// Ordered recovery ladder: canonical outcome stamp, acknowledged
|
|
277
301
|
// non-streaming replay for exposed output, bounded streaming
|
|
@@ -291,13 +315,24 @@ export class AnthropicProvider {
|
|
|
291
315
|
}
|
|
292
316
|
}
|
|
293
317
|
throw midstream.exhaustedError();
|
|
318
|
+
} catch (err) {
|
|
319
|
+
// The fallback trigger can surface from the request loop, a mid-stream
|
|
320
|
+
// overload, or the non-streaming recovery: handle it around the whole
|
|
321
|
+
// operation, not just the first request.
|
|
322
|
+
if (!(err instanceof AnthropicFallbackTriggeredError)) throw err;
|
|
323
|
+
process.stderr.write(`[${this.name}] ${err.message}\n`);
|
|
324
|
+
announceAnthropicModelFallback(onStageChange, useModel, err.fallbackModel);
|
|
325
|
+
return await this._doSend(messages, err.fallbackModel, tools, {
|
|
326
|
+
...opts,
|
|
327
|
+
fallbackModel: undefined,
|
|
328
|
+
_fallbackTriggered: true,
|
|
329
|
+
});
|
|
294
330
|
} finally {
|
|
295
331
|
totalTimeout.cleanup();
|
|
296
332
|
}
|
|
297
333
|
}
|
|
298
334
|
async listModels() {
|
|
299
|
-
const apiKey =
|
|
300
|
-
this.apiKey || this.config?.apiKey || (this.name === 'anthropic' ? process.env.ANTHROPIC_API_KEY : null);
|
|
335
|
+
const apiKey = resolveProviderApiKey(this.name, this.config);
|
|
301
336
|
if (!apiKey) return MODELS;
|
|
302
337
|
try {
|
|
303
338
|
const base = String(this.config?.baseURL || 'https://api.anthropic.com').replace(/\/+$/, '');
|
|
@@ -329,6 +364,6 @@ export class AnthropicProvider {
|
|
|
329
364
|
async isAvailable() {
|
|
330
365
|
// Availability probes must not spend tokens or depend on a live
|
|
331
366
|
// network. Dispatch owns authentication validation and 401 reload.
|
|
332
|
-
return !!(this.
|
|
367
|
+
return !!resolveProviderApiKey(this.name, this.config);
|
|
333
368
|
}
|
|
334
369
|
}
|