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
|
@@ -3,23 +3,68 @@ import {
|
|
|
3
3
|
accountScopedSessionId,
|
|
4
4
|
readProviderAccountPool,
|
|
5
5
|
chooseProviderAccount,
|
|
6
|
-
|
|
6
|
+
selectProviderAccountIf,
|
|
7
7
|
blockProviderAccount,
|
|
8
8
|
providerAccountExhausted,
|
|
9
|
+
providerAccountExhaustedForModelOnly,
|
|
10
|
+
providerAccountPolicy,
|
|
9
11
|
providerAccountsResetAt,
|
|
10
12
|
} from '../../../shared/provider-accounts.mjs';
|
|
11
13
|
import { withProviderAccount, hasExplicitProviderAuthBinding } from '../../../shared/provider-auth-binding.mjs';
|
|
12
|
-
import {
|
|
14
|
+
import { isExplicitUserAbortError, markProviderRecoveryExhausted } from './retry-classifier.mjs';
|
|
15
|
+
import { sleepWithAbort } from './retry-backoff.mjs';
|
|
16
|
+
import { QUOTA_KINDS, providerErrorKind } from './provider-error-kind.mjs';
|
|
13
17
|
import { fetchOAuthUsageSnapshot, readCachedOAuthUsageSnapshot } from './oauth-usage.mjs';
|
|
14
18
|
|
|
15
|
-
// Only an explicit quota refusal advances the roster
|
|
16
|
-
// refusal, policy denial or transport
|
|
19
|
+
// Only an explicit quota / plan / billing refusal advances the roster as
|
|
20
|
+
// quota; a generic 429, overload, auth refusal, policy denial or transport
|
|
21
|
+
// failure retains its existing recovery.
|
|
17
22
|
export function isAccountQuotaError(error) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
if (isExplicitUserAbortError(error)) return false;
|
|
24
|
+
const { kind, status } = providerErrorKind(error);
|
|
25
|
+
if (status === 401 || status === 403) return false;
|
|
26
|
+
return QUOTA_KINDS.has(kind);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Kinds that say nothing about the account: the server (or the network) is
|
|
30
|
+
// temporarily unable to serve (or has no capacity in the requested service
|
|
31
|
+
// tier). They never block or rotate an account.
|
|
32
|
+
const SERVER_SIDE_KINDS = new Set(['overloaded', 'transient', 'service_tier_unavailable']);
|
|
33
|
+
|
|
34
|
+
// Provider-supplied roster cooldowns (`accountCooldownPolicy` on the provider
|
|
35
|
+
// object), used when the server named no delay:
|
|
36
|
+
// { floorMs, rateLimitedMs, quotaStepsMs, unknownMs, rotateOnRateLimit,
|
|
37
|
+
// waitForCooldownMs, blockedMs }
|
|
38
|
+
// blockedMs: cooldown for an `accountBlocked` refusal, which then rotates.
|
|
39
|
+
// quotaStepsMs escalates per consecutive quota refusal of one account (reset
|
|
40
|
+
// by a served answer). Absent → the inferred five minutes.
|
|
41
|
+
// rotateOnRateLimit rotates on a plain 429 rate limit; its advice, when
|
|
42
|
+
// present, becomes that account's cooldown.
|
|
43
|
+
// waitForCooldownMs: when every eligible account is only cooling down (no
|
|
44
|
+
// quota evidence), the send waits — cancellable, reported as reconnect
|
|
45
|
+
// progress — for the earliest cooldown while the send's total wait stays
|
|
46
|
+
// within this bound; beyond it the cooldown error surfaces. Absent → no wait.
|
|
47
|
+
const INFERRED_COOLDOWN_MS = 5 * 60_000;
|
|
48
|
+
const quotaStrikes = new Map();
|
|
49
|
+
|
|
50
|
+
function cooldownPolicyOf(instance) {
|
|
51
|
+
const policy = instance?.accountCooldownPolicy;
|
|
52
|
+
return policy && typeof policy === 'object' ? policy : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function finiteMs(value, fallback) {
|
|
56
|
+
const n = Number(value);
|
|
57
|
+
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function policyCooldownMs(policy, strikeKey, reason) {
|
|
61
|
+
if (reason === 'rate_limited') return finiteMs(policy.rateLimitedMs, INFERRED_COOLDOWN_MS);
|
|
62
|
+
if (reason === 'quota' && Array.isArray(policy.quotaStepsMs) && policy.quotaStepsMs.length) {
|
|
63
|
+
const strikes = quotaStrikes.get(strikeKey) || 0;
|
|
64
|
+
quotaStrikes.set(strikeKey, strikes + 1);
|
|
65
|
+
return finiteMs(policy.quotaStepsMs[Math.min(strikes, policy.quotaStepsMs.length - 1)], INFERRED_COOLDOWN_MS);
|
|
66
|
+
}
|
|
67
|
+
return finiteMs(policy.unknownMs, INFERRED_COOLDOWN_MS);
|
|
23
68
|
}
|
|
24
69
|
|
|
25
70
|
// Burst throttles reopen within seconds. A 429 whose Retry-After points
|
|
@@ -75,6 +120,23 @@ function accountsExhaustedError(useCredits) {
|
|
|
75
120
|
return error;
|
|
76
121
|
}
|
|
77
122
|
|
|
123
|
+
// Every eligible account is only cooling down after a rate limit (no quota
|
|
124
|
+
// evidence): a rate limit, advising the earliest cooldown end as the wait.
|
|
125
|
+
// The pool already spent its cooldown wait, so this is a terminal verdict for
|
|
126
|
+
// the loop, not an unclassified failure.
|
|
127
|
+
function earliestCooldownMs(rows, now) {
|
|
128
|
+
const ends = rows.map((row) => Number(row.blockedUntil)).filter((until) => Number.isFinite(until) && until > now);
|
|
129
|
+
return ends.length ? Math.min(...ends) - now : null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function accountsCoolingDownError(rows, now) {
|
|
133
|
+
const error = new Error('Every connected account is cooling down after a rate limit. Try again shortly.');
|
|
134
|
+
error.code = 'rate_limited';
|
|
135
|
+
const wait = earliestCooldownMs(rows, now);
|
|
136
|
+
if (wait != null) error.retryAfterMs = wait;
|
|
137
|
+
return markProviderRecoveryExhausted(error, { owner: 'account-pool', terminal: true });
|
|
138
|
+
}
|
|
139
|
+
|
|
78
140
|
// Structured proof that the send ended because no account can serve `model`
|
|
79
141
|
// (not merely because a generic 429 or a stopped loop surfaced an error).
|
|
80
142
|
function quotaExhausted(error, providerName, model, rows, options = {}) {
|
|
@@ -116,28 +178,135 @@ function boundAccountSend(providerName, row, messages, options) {
|
|
|
116
178
|
return { opts, history, emitted: () => emitted };
|
|
117
179
|
}
|
|
118
180
|
|
|
119
|
-
// Commit only a successful fallback, without overwriting a newer selection
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
181
|
+
// Commit only a successful fallback, without overwriting a newer selection:
|
|
182
|
+
// the selection is compared under the write's lock, not before it. A fallback
|
|
183
|
+
// forced by a model-scoped limit ("7D Fable" full, or a block attributed to
|
|
184
|
+
// one family) serves this request only: the selected account still serves
|
|
185
|
+
// every other model, so it stays the provider's account of record.
|
|
186
|
+
async function commitFallbackAccount(providerName, pool, row, model, refusalScoped, policy) {
|
|
187
|
+
if (row.id === pool.selectedId || refusalScoped) return null;
|
|
188
|
+
if (accountExhaustedForModelOnly(providerName, pool.selectedId, model)) return null;
|
|
189
|
+
return selectProviderAccountIf(providerName, pool.selectedId, row.id, policy);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// The account each session runs on under the headroom policy. Every answer
|
|
193
|
+
// records its provider and account in the assistant message's
|
|
194
|
+
// `providerMetadata` (and in provider state when the adapter keeps one), so
|
|
195
|
+
// the binding survives a restart and eviction from this map, which only
|
|
196
|
+
// spares the history walk. Bounded, oldest binding first out.
|
|
197
|
+
const SESSION_ACCOUNT_LIMIT = 1000;
|
|
198
|
+
const ROUTING_METADATA_KEY = 'accountRouting';
|
|
199
|
+
const sessionAccounts = new Map();
|
|
200
|
+
|
|
201
|
+
// Forget every in-memory binding, as a restart does (tests).
|
|
202
|
+
export function resetSessionAccountBindings() {
|
|
203
|
+
sessionAccounts.clear();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function rememberSessionAccount(key, id) {
|
|
207
|
+
sessionAccounts.delete(key);
|
|
208
|
+
sessionAccounts.set(key, id);
|
|
209
|
+
if (sessionAccounts.size > SESSION_ACCOUNT_LIMIT) sessionAccounts.delete(sessionAccounts.keys().next().value);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function accountExhaustedForModelOnly(providerName, id, model) {
|
|
213
|
+
const pool = readProviderAccountPool(providerName);
|
|
214
|
+
const row = pool.accounts.find((entry) => entry.id === id);
|
|
215
|
+
return (
|
|
216
|
+
Boolean(row) &&
|
|
217
|
+
providerAccountExhaustedForModelOnly(row, Date.now(), model, { useCredits: pool.useCredits === true })
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Only a binding recorded for THIS provider counts: a session that switched
|
|
222
|
+
// providers carries another roster's account ids (every roster has a `default`).
|
|
223
|
+
// The session's binding is read before the serving account, which differs
|
|
224
|
+
// when a model-scoped limit lent this one answer to another account.
|
|
225
|
+
function sessionAccountId(providerName, key, messages, options) {
|
|
226
|
+
if (key && sessionAccounts.has(key)) return sessionAccounts.get(key);
|
|
227
|
+
const state = options.providerState;
|
|
228
|
+
if (state?.providerAccountId && state.providerAccountProvider === providerName) {
|
|
229
|
+
return state.providerSessionAccountId || state.providerAccountId;
|
|
125
230
|
}
|
|
231
|
+
for (let index = (messages?.length || 0) - 1; index >= 0; index -= 1) {
|
|
232
|
+
const routing = messages[index]?.providerMetadata?.[ROUTING_METADATA_KEY];
|
|
233
|
+
if (routing?.accountId && routing.provider === providerName) return routing.sessionAccountId || routing.accountId;
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Stamp the serving account on the answer, independent of transport state,
|
|
239
|
+
// with the account the session stays bound to (`bindingId`).
|
|
240
|
+
function recordServingAccount(providerName, result, id, bindingId) {
|
|
241
|
+
if (!result || typeof result !== 'object') return;
|
|
242
|
+
if (result.providerReplay) result.providerReplay = { ...result.providerReplay, accountId: id };
|
|
243
|
+
if (result.providerState) {
|
|
244
|
+
result.providerState = {
|
|
245
|
+
...result.providerState,
|
|
246
|
+
providerAccountId: id,
|
|
247
|
+
providerSessionAccountId: bindingId,
|
|
248
|
+
providerAccountProvider: providerName,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const metadata =
|
|
252
|
+
result.providerMetadata && typeof result.providerMetadata === 'object' ? result.providerMetadata : {};
|
|
253
|
+
result.providerMetadata = {
|
|
254
|
+
...metadata,
|
|
255
|
+
[ROUTING_METADATA_KEY]: { provider: providerName, accountId: id, sessionAccountId: bindingId },
|
|
256
|
+
};
|
|
126
257
|
}
|
|
127
258
|
|
|
128
259
|
// Whether the failed account's quota window is exhausted, plus the server's
|
|
129
260
|
// retry delay. Anthropic and other subscriptions may use the same 429 code
|
|
130
261
|
// for burst throttling and exhausted subscription windows, so the native
|
|
131
262
|
// usage endpoint decides rather than a human-readable message.
|
|
263
|
+
// `until` is when the block lifts: the real quota reset when the provider
|
|
264
|
+
// named one, else the advised delay, else an inferred five minutes. A long
|
|
265
|
+
// Retry-After without quota evidence is a rate-limit cooldown: it rotates
|
|
266
|
+
// this send, blocks no longer than advised and is never quota evidence.
|
|
132
267
|
async function accountQuotaExhausted(providerName, row, model, error, account) {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
268
|
+
const { kind, status, retryAfterMs: delay, resetAt } = providerErrorKind(error);
|
|
269
|
+
const now = Date.now();
|
|
270
|
+
const policy = cooldownPolicyOf(account(row.id));
|
|
271
|
+
const floorMs = policy ? finiteMs(policy.floorMs, 0) : 0;
|
|
272
|
+
const blockUntil = (withReset, reason = 'unknown') => {
|
|
273
|
+
if (withReset && resetAt > now) return { until: resetAt, source: 'retry-after' };
|
|
274
|
+
if (delay > 0) return { until: now + Math.max(delay, floorMs), source: 'retry-after' };
|
|
275
|
+
if (policy) {
|
|
276
|
+
const ms = policyCooldownMs(policy, `${providerName}:${row.id}`, reason);
|
|
277
|
+
return { until: now + Math.max(ms, floorMs), source: 'inferred' };
|
|
278
|
+
}
|
|
279
|
+
return { until: now + INFERRED_COOLDOWN_MS, source: 'inferred' };
|
|
280
|
+
};
|
|
281
|
+
if (SERVER_SIDE_KINDS.has(kind) || isExplicitUserAbortError(error)) {
|
|
282
|
+
return { exhausted: false, delay, evidence: false, ...blockUntil(false) };
|
|
283
|
+
}
|
|
284
|
+
// An account-level block (`accountBlocked`, e.g. the account needs
|
|
285
|
+
// verification): with a policy `blockedMs` that account cools for it and the
|
|
286
|
+
// roster rotates; never quota evidence. Without one it surfaces as before.
|
|
287
|
+
const blockedMs = policy ? finiteMs(policy.blockedMs, 0) : 0;
|
|
288
|
+
if (error?.accountBlocked === true && blockedMs > 0) {
|
|
289
|
+
return {
|
|
290
|
+
exhausted: true,
|
|
291
|
+
accountBlocked: true,
|
|
292
|
+
delay,
|
|
293
|
+
evidence: false,
|
|
294
|
+
until: now + Math.max(blockedMs, floorMs),
|
|
295
|
+
source: 'inferred',
|
|
296
|
+
};
|
|
297
|
+
}
|
|
135
298
|
const typed = isAccountQuotaError(error);
|
|
136
|
-
|
|
299
|
+
if (typed) return { exhausted: true, delay, evidence: true, ...blockUntil(true, 'quota') };
|
|
300
|
+
// A policy with rotateOnRateLimit rotates on a plain rate limit too (the
|
|
301
|
+
// advice as its cooldown, else rateLimitedMs); never quota evidence.
|
|
302
|
+
if (policy?.rotateOnRateLimit === true && kind === 'rate_limited' && status === 429) {
|
|
303
|
+
return { exhausted: true, delay, evidence: false, ...blockUntil(false, 'rate_limited') };
|
|
304
|
+
}
|
|
305
|
+
let exhausted = status === 429 && delay > QUOTA_WINDOW_RETRY_AFTER_MS;
|
|
137
306
|
// Proof of a spent quota: a typed quota refusal or an exhausted usage window
|
|
138
307
|
// (a long Retry-After alone only rotates the roster, it proves nothing).
|
|
139
|
-
let evidence =
|
|
140
|
-
if (
|
|
308
|
+
let evidence = false;
|
|
309
|
+
if (status === 429) {
|
|
141
310
|
await fetchOAuthUsageSnapshot({ provider: providerName, accountId: row.id }, account(row.id), () => {}, {
|
|
142
311
|
force: true,
|
|
143
312
|
});
|
|
@@ -147,7 +316,7 @@ async function accountQuotaExhausted(providerName, row, model, error, account) {
|
|
|
147
316
|
evidence = providerAccountExhausted({ ...entry, blockedUntil: 0 }, Date.now(), model, options);
|
|
148
317
|
exhausted = exhausted || evidence || providerAccountExhausted(entry, Date.now(), model, options);
|
|
149
318
|
}
|
|
150
|
-
return { exhausted, delay, evidence };
|
|
319
|
+
return { exhausted, delay, evidence, ...(exhausted ? blockUntil(evidence, evidence ? 'quota' : 'unknown') : {}) };
|
|
151
320
|
}
|
|
152
321
|
|
|
153
322
|
// The pool's send: walks the eligible accounts until one answers, blocking
|
|
@@ -158,12 +327,20 @@ function poolSend(providerName, account) {
|
|
|
158
327
|
let lastError;
|
|
159
328
|
let probed = false;
|
|
160
329
|
const evidenced = new Set();
|
|
330
|
+
const sessionKey = options.sessionId ? `${providerName}:${options.sessionId}` : null;
|
|
331
|
+
const boundId = sessionAccountId(providerName, sessionKey, messages, options);
|
|
332
|
+
// Whether this send already left an account, and whether the latest quota
|
|
333
|
+
// refusal held only for this model's family.
|
|
334
|
+
let switched = false;
|
|
335
|
+
let refusalScoped = false;
|
|
161
336
|
// Mark `error` only when every account in `ids` (default: the roster) is
|
|
162
337
|
// exhausted with quota evidence: observed in this send, or a full window.
|
|
163
|
-
|
|
338
|
+
// Without an error of its own, the send reports quota exhaustion only on
|
|
339
|
+
// that evidence, and a rate-limit cooldown otherwise.
|
|
340
|
+
const exhaustion = (ids) => {
|
|
164
341
|
const pool = readProviderAccountPool(providerName);
|
|
165
|
-
//
|
|
166
|
-
const scope = ids || (pool
|
|
342
|
+
// Manual policy: the eligible set is the selected account alone.
|
|
343
|
+
const scope = ids || (providerAccountPolicy(pool) === 'manual' ? [pool.selectedId] : null);
|
|
167
344
|
const rows = scope ? pool.accounts.filter((entry) => scope.includes(entry.id)) : pool.accounts;
|
|
168
345
|
const opts = { useCredits: pool.useCredits === true };
|
|
169
346
|
const now = Date.now();
|
|
@@ -177,9 +354,47 @@ function poolSend(providerName, account) {
|
|
|
177
354
|
opts
|
|
178
355
|
)
|
|
179
356
|
);
|
|
180
|
-
return
|
|
357
|
+
return { rows, opts, now, all };
|
|
358
|
+
};
|
|
359
|
+
const markExhausted = (error, ids) => {
|
|
360
|
+
const { rows, opts, now, all } = exhaustion(ids);
|
|
361
|
+
if (all) {
|
|
362
|
+
return quotaExhausted(error || accountsExhaustedError(opts.useCredits), providerName, model, rows, opts);
|
|
363
|
+
}
|
|
364
|
+
return error || accountsCoolingDownError(rows, now);
|
|
365
|
+
};
|
|
366
|
+
// Accounts this send blocked on a rate-limit cooldown, the time it spent
|
|
367
|
+
// waiting for cooldowns, and the provider's wait bound.
|
|
368
|
+
const cooled = new Set();
|
|
369
|
+
let waitedMs = 0;
|
|
370
|
+
let sends = 0;
|
|
371
|
+
const waitBoundMs = (ids) => {
|
|
372
|
+
const id = ids?.[0] || readProviderAccountPool(providerName).selectedId || 'default';
|
|
373
|
+
return finiteMs(cooldownPolicyOf(account(id))?.waitForCooldownMs, 0);
|
|
181
374
|
};
|
|
182
|
-
|
|
375
|
+
// A cooldown-only eligible set whose earliest cooldown ends inside the
|
|
376
|
+
// remaining wait budget is waited out; otherwise the send fails as before.
|
|
377
|
+
const waitOrThrow = async (error, ids) => {
|
|
378
|
+
const { rows, now, all } = exhaustion(ids);
|
|
379
|
+
const wait = all ? null : earliestCooldownMs(rows, now);
|
|
380
|
+
if (wait == null || waitedMs + wait > waitBoundMs(ids)) throw markExhausted(error, ids);
|
|
381
|
+
options.onStageChange?.('reconnecting', {
|
|
382
|
+
message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
|
|
383
|
+
reason: 'rate_limited',
|
|
384
|
+
waitMs: wait,
|
|
385
|
+
retryAt: now + wait,
|
|
386
|
+
});
|
|
387
|
+
await sleepWithAbort(wait, options.signal);
|
|
388
|
+
waitedMs += wait;
|
|
389
|
+
const lifted = Date.now();
|
|
390
|
+
for (const row of readProviderAccountPool(providerName).accounts) {
|
|
391
|
+
if (cooled.has(row.id) && !(Number(row.blockedUntil) > lifted)) {
|
|
392
|
+
cooled.delete(row.id);
|
|
393
|
+
attempted.delete(row.id);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
while (attempted.size < 20 && sends < 20) {
|
|
183
398
|
options.signal?.throwIfAborted();
|
|
184
399
|
const pool = readProviderAccountPool(providerName);
|
|
185
400
|
if (!pool.accounts.length) {
|
|
@@ -194,7 +409,8 @@ function poolSend(providerName, account) {
|
|
|
194
409
|
}
|
|
195
410
|
return account('default').send(messages, model, tools, options);
|
|
196
411
|
}
|
|
197
|
-
const
|
|
412
|
+
const policy = providerAccountPolicy(pool);
|
|
413
|
+
const row = chooseProviderAccount(pool, attempted, Date.now(), model, { sessionAccountId: boundId });
|
|
198
414
|
if (!row) {
|
|
199
415
|
// Once per send: a refusal built on a stale meter must not outlive the
|
|
200
416
|
// meter. Re-measuring can only widen the roster, so it is tried before
|
|
@@ -203,15 +419,27 @@ function poolSend(providerName, account) {
|
|
|
203
419
|
probed = true;
|
|
204
420
|
if (await probeRefusedAccounts(providerName, pool, model, account)) continue;
|
|
205
421
|
}
|
|
206
|
-
|
|
422
|
+
await waitOrThrow(lastError);
|
|
423
|
+
continue;
|
|
207
424
|
}
|
|
208
425
|
attempted.add(row.id);
|
|
426
|
+
sends += 1;
|
|
209
427
|
const bound = boundAccountSend(providerName, row, messages, options);
|
|
210
428
|
try {
|
|
211
429
|
const result = await account(row.id).send(bound.history, model, tools, bound.opts);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
430
|
+
quotaStrikes.delete(`${providerName}:${row.id}`);
|
|
431
|
+
// Headroom policy: a session's first pick, or its move off its account
|
|
432
|
+
// on a limit, becomes the selection; continuing on its account does
|
|
433
|
+
// not, so concurrent sessions never flip the selection back and forth.
|
|
434
|
+
// A move forced by a model-scoped limit serves this request only.
|
|
435
|
+
const leftBound = Boolean(boundId) && row.id !== boundId;
|
|
436
|
+
const scoped = switched
|
|
437
|
+
? refusalScoped
|
|
438
|
+
: policy === 'headroom' && leftBound && accountExhaustedForModelOnly(providerName, boundId, model);
|
|
439
|
+
recordServingAccount(providerName, result, row.id, scoped && boundId ? boundId : row.id);
|
|
440
|
+
if (sessionKey && policy === 'headroom' && !scoped) rememberSessionAccount(sessionKey, row.id);
|
|
441
|
+
const commit = policy !== 'headroom' || !boundId || leftBound;
|
|
442
|
+
if (commit && (await commitFallbackAccount(providerName, pool, row, model, scoped, policy))) {
|
|
215
443
|
// Publish only a committed selection, never a speculative retry or
|
|
216
444
|
// one superseded by a manual switch. The existing progress channel
|
|
217
445
|
// carries this across runtime shards to the attached UI.
|
|
@@ -230,7 +458,7 @@ function poolSend(providerName, account) {
|
|
|
230
458
|
if (options.signal?.aborted) throw error;
|
|
231
459
|
if (error?.reauthRequired === true) {
|
|
232
460
|
if (
|
|
233
|
-
|
|
461
|
+
policy === 'manual' ||
|
|
234
462
|
bound.emitted() ||
|
|
235
463
|
error.unsafeToRetry ||
|
|
236
464
|
error.liveTextEmitted ||
|
|
@@ -238,25 +466,47 @@ function poolSend(providerName, account) {
|
|
|
238
466
|
)
|
|
239
467
|
throw error;
|
|
240
468
|
lastError = error;
|
|
469
|
+
switched = true;
|
|
470
|
+
refusalScoped = false;
|
|
241
471
|
options.onStageChange?.('reconnecting', { message: 'Sign-in expired — switching to the next account' });
|
|
242
472
|
continue;
|
|
243
473
|
}
|
|
244
|
-
const { exhausted,
|
|
245
|
-
if (options.signal?.aborted || !exhausted) throw error;
|
|
246
|
-
if (evidence) evidenced.add(row.id);
|
|
247
|
-
blockProviderAccount(
|
|
474
|
+
const { exhausted, evidence, until, source, accountBlocked } = await accountQuotaExhausted(
|
|
248
475
|
providerName,
|
|
249
|
-
row
|
|
250
|
-
Date.now() + (delay > 0 ? delay : 5 * 60_000),
|
|
476
|
+
row,
|
|
251
477
|
model,
|
|
252
|
-
|
|
253
|
-
|
|
478
|
+
error,
|
|
479
|
+
account
|
|
254
480
|
);
|
|
255
|
-
if (
|
|
256
|
-
|
|
257
|
-
|
|
481
|
+
if (options.signal?.aborted || !exhausted) throw error;
|
|
482
|
+
if (evidence) evidenced.add(row.id);
|
|
483
|
+
else cooled.add(row.id);
|
|
484
|
+
await blockProviderAccount(providerName, row.id, until, model, source, { quota: evidence === true });
|
|
485
|
+
// An account block is unsafe to re-issue on THAT account only; with no
|
|
486
|
+
// output emitted, the next account may serve the same request.
|
|
487
|
+
if (
|
|
488
|
+
bound.emitted() ||
|
|
489
|
+
(error.unsafeToRetry && accountBlocked !== true) ||
|
|
490
|
+
error.liveTextEmitted ||
|
|
491
|
+
error.emittedToolCall
|
|
492
|
+
)
|
|
493
|
+
throw error;
|
|
494
|
+
// Manual policy: the eligible set is the selected account alone.
|
|
495
|
+
if (policy === 'manual') {
|
|
496
|
+
await waitOrThrow(error, [row.id]);
|
|
497
|
+
lastError = error;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
258
500
|
lastError = error;
|
|
259
|
-
|
|
501
|
+
switched = true;
|
|
502
|
+
refusalScoped = accountExhaustedForModelOnly(providerName, row.id, model);
|
|
503
|
+
options.onStageChange?.('reconnecting', {
|
|
504
|
+
message: evidence
|
|
505
|
+
? 'Quota exhausted — switching to the next account'
|
|
506
|
+
: accountBlocked
|
|
507
|
+
? 'Account blocked — switching to the next account'
|
|
508
|
+
: 'Rate limited (cooldown) — switching to the next account',
|
|
509
|
+
});
|
|
260
510
|
}
|
|
261
511
|
}
|
|
262
512
|
throw markExhausted(lastError || new Error('Provider account attempts exhausted.'));
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { PROVIDER_NONSTREAM_TOTAL_TIMEOUT_MS, createTimeoutSignal } from '../stall-policy.mjs';
|
|
10
10
|
import { AnthropicFallbackTriggeredError, markProviderRecoveryExhausted } from './retry-classifier.mjs';
|
|
11
11
|
import { normalizeAnthropicNonStreamingResponse } from './lib/anthropic-request-utils.mjs';
|
|
12
|
+
import { capForNonStreaming } from './anthropic-max-tokens-recovery.mjs';
|
|
12
13
|
import { createAnthropicRecoveryGuards } from './anthropic-recovery-guards.mjs';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -44,7 +45,7 @@ export function createAnthropicApiRecovery({
|
|
|
44
45
|
try {
|
|
45
46
|
onStageChange?.('requesting', { transport: 'non-streaming-fallback' });
|
|
46
47
|
} catch {}
|
|
47
|
-
const nonStreamingParams = { ...params, stream: false };
|
|
48
|
+
const nonStreamingParams = capForNonStreaming({ ...params, stream: false });
|
|
48
49
|
const timeoutMs =
|
|
49
50
|
Number(opts._nonStreamingTimeoutMs) > 0
|
|
50
51
|
? Number(opts._nonStreamingTimeoutMs)
|
|
@@ -14,13 +14,16 @@ import {
|
|
|
14
14
|
ANTHROPIC_RETRY_JITTER_RATIO,
|
|
15
15
|
anthropicMaxAttempts,
|
|
16
16
|
anthropicRequestTimeoutMs,
|
|
17
|
+
AnthropicFallbackTriggeredError,
|
|
17
18
|
emitProviderRetryStage,
|
|
18
19
|
withRetry,
|
|
19
|
-
retryAfterMsFromError,
|
|
20
20
|
retryDelayLabel,
|
|
21
21
|
} from './retry-classifier.mjs';
|
|
22
|
+
import { ANTHROPIC_MAX_CONSECUTIVE_529 } from './retry-backoff.mjs';
|
|
22
23
|
import { PROVIDER_FIRST_BYTE_TIMEOUT_MS, createTimeoutSignal } from '../stall-policy.mjs';
|
|
23
|
-
import { noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
|
|
24
|
+
import { fastModeDowngraded, noteFastModeCapacityError } from './anthropic-fast-mode.mjs';
|
|
25
|
+
import { adjustMaxTokensForContextOverflow } from './anthropic-max-tokens-recovery.mjs';
|
|
26
|
+
import { applyAnthropicErrorContract, retryAfterMsFromHeaders } from './anthropic-error-contract.mjs';
|
|
24
27
|
import { noteRequestServiceTier } from '../../../shared/llm/usage-context.mjs';
|
|
25
28
|
import { notifyCurrentAnthropicRateLimit } from './admission-scheduler.mjs';
|
|
26
29
|
|
|
@@ -78,12 +81,61 @@ export function armFirstByteWatchdog(streamController, midState) {
|
|
|
78
81
|
* @param {object} deps.params the streaming request body (mutated on fast-pool de-latch)
|
|
79
82
|
* @param {object|null} deps.requestHeaders per-call beta/extra headers
|
|
80
83
|
* @param {AbortSignal|null} deps.totalSignal session-lifetime pass-through
|
|
84
|
+
* @param {{ state: { consecutive529Errors: number } }|null} [deps.overload] the send's shared overload counter
|
|
81
85
|
*/
|
|
82
|
-
export function createAnthropicApiTransport({
|
|
86
|
+
export function createAnthropicApiTransport({
|
|
87
|
+
client,
|
|
88
|
+
label,
|
|
89
|
+
opts,
|
|
90
|
+
useModel,
|
|
91
|
+
params,
|
|
92
|
+
requestHeaders,
|
|
93
|
+
totalSignal,
|
|
94
|
+
overload = null,
|
|
95
|
+
}) {
|
|
83
96
|
const requestOptions = (attemptSignal) => ({
|
|
84
97
|
signal: attemptSignal,
|
|
85
98
|
...(requestHeaders ? { headers: requestHeaders } : {}),
|
|
86
99
|
});
|
|
100
|
+
// The SDK throws a non-2xx before `.asResponse()` resolves, so an HTTP
|
|
101
|
+
// failure arrives as an APIError rather than a Response. Stamp the
|
|
102
|
+
// provider-boundary error contract on it (status, lowercased error type as
|
|
103
|
+
// `code`, preserved headers, uncapped retryAfterMs / resetAt).
|
|
104
|
+
const annotateHttpFailure = (err) => {
|
|
105
|
+
if (err && typeof err === 'object' && Number(err.status || err.httpStatus || 0) > 0) {
|
|
106
|
+
applyAnthropicErrorContract(err, { status: err.status || err.httpStatus, headers: err.headers });
|
|
107
|
+
}
|
|
108
|
+
return err;
|
|
109
|
+
};
|
|
110
|
+
// A fast-pool refusal (or a "Fast mode is not enabled" 400) says nothing
|
|
111
|
+
// about standard-speed capacity: drop `speed` and let the caller replay at
|
|
112
|
+
// once instead of waiting out a window that only the fast pool owns.
|
|
113
|
+
const dropFastSpeedAfter = (body, err) => {
|
|
114
|
+
if (body.speed !== 'fast') return false;
|
|
115
|
+
if (!fastModeDowngraded(noteFastModeCapacityError(err, { fast: true }))) return false;
|
|
116
|
+
delete body.speed;
|
|
117
|
+
return true;
|
|
118
|
+
};
|
|
119
|
+
// In-attempt body repairs, each replayed once: drop speed after a fast-pool
|
|
120
|
+
// refusal, and shrink max_tokens after the "input length and max_tokens
|
|
121
|
+
// exceed context limit" 400.
|
|
122
|
+
const withBodyRecovery = (body, attempt) => async (ctx) => {
|
|
123
|
+
let speedDropped = false;
|
|
124
|
+
let tokensAdjusted = false;
|
|
125
|
+
for (;;) {
|
|
126
|
+
try {
|
|
127
|
+
return await attempt(ctx);
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (!speedDropped && dropFastSpeedAfter(body, err)) {
|
|
130
|
+
speedDropped = true;
|
|
131
|
+
} else if (!tokensAdjusted && adjustMaxTokensForContextOverflow(body, err?.status, err?.message)) {
|
|
132
|
+
tokensAdjusted = true;
|
|
133
|
+
} else {
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
87
139
|
// Initial-response retry policy shared by the streaming request and the
|
|
88
140
|
// non-streaming fallback.
|
|
89
141
|
const retryPolicy = (signal, perAttemptLabel, recoveryOwner) => ({
|
|
@@ -95,23 +147,27 @@ export function createAnthropicApiTransport({ client, label, opts, useModel, par
|
|
|
95
147
|
perAttemptTimeoutMs: anthropicRequestTimeoutMs(),
|
|
96
148
|
perAttemptLabel,
|
|
97
149
|
provider: 'anthropic',
|
|
150
|
+
// This transport honors the positive x-should-retry override.
|
|
151
|
+
honorShouldRetryTrue: true,
|
|
98
152
|
recoveryOwner,
|
|
99
153
|
retry529: opts.retry529,
|
|
100
154
|
model: useModel,
|
|
101
155
|
fallbackModel: opts._fallbackTriggered ? undefined : opts.fallbackModel,
|
|
156
|
+
// One overload counter for the send: SSE overloads count toward the same
|
|
157
|
+
// limit as request-loop 529s.
|
|
158
|
+
overloadState: overload?.state,
|
|
159
|
+
overloadFallbackAfter: ANTHROPIC_MAX_CONSECUTIVE_529,
|
|
160
|
+
stopAfterRepeated529: overload?.stopAfterRepeated529 === true,
|
|
102
161
|
});
|
|
103
162
|
|
|
104
|
-
const requestStreamingResponse = () =>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
163
|
+
const requestStreamingResponse = async () => {
|
|
164
|
+
const attempt = async ({ signal: attemptSignal }) => {
|
|
165
|
+
noteRequestServiceTier(params.speed);
|
|
166
|
+
try {
|
|
108
167
|
const res = await client.messages.create(params, requestOptions(attemptSignal)).asResponse();
|
|
109
168
|
if (!res.ok) {
|
|
110
169
|
const text = await res.text().catch(() => '');
|
|
111
170
|
const err = new Error(`Anthropic API ${res.status}: ${text.slice(0, 200)}`);
|
|
112
|
-
err.status = res.status;
|
|
113
|
-
err.httpStatus = res.status;
|
|
114
|
-
err.initialResponseError = true;
|
|
115
171
|
// Carry response headers so withRetry can honor a
|
|
116
172
|
// short Retry-After and upstream can read quota hints.
|
|
117
173
|
err.headers = res.headers;
|
|
@@ -120,48 +176,55 @@ export function createAnthropicApiTransport({ client, label, opts, useModel, par
|
|
|
120
176
|
// output/tool exposure, so the request-local
|
|
121
177
|
// withRetry loop may retry it with jitter.
|
|
122
178
|
if (res.status === 429) {
|
|
123
|
-
const retryAfterMs = retryAfterMsFromError({
|
|
124
|
-
headers: res.headers,
|
|
125
|
-
response: { headers: res.headers },
|
|
126
|
-
});
|
|
127
179
|
err.name = 'ProviderQuotaError';
|
|
128
|
-
err.
|
|
129
|
-
err.retryAfterMs = retryAfterMs;
|
|
180
|
+
err.retryAfterMs = retryAfterMsFromHeaders(res.headers);
|
|
130
181
|
err.providerQuota = true;
|
|
131
182
|
err.quotaExceeded = true;
|
|
132
183
|
}
|
|
133
|
-
throw err;
|
|
184
|
+
throw applyAnthropicErrorContract(err, { status: res.status, headers: res.headers, bodyText: text });
|
|
134
185
|
}
|
|
135
186
|
if (!res.body) {
|
|
136
187
|
throw new Error('Anthropic streaming response has no body');
|
|
137
188
|
}
|
|
138
189
|
return res;
|
|
139
|
-
}
|
|
140
|
-
|
|
190
|
+
} catch (err) {
|
|
191
|
+
throw annotateHttpFailure(err);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
try {
|
|
195
|
+
return await withRetry(withBodyRecovery(params, attempt), {
|
|
141
196
|
...retryPolicy(totalSignal, `${label} Anthropic streaming response`, `${label}-initial-response`),
|
|
142
|
-
onRetry: ({ attempt, maxAttempts, lastErr, delayMs, delayReason }) => {
|
|
143
|
-
emitProviderRetryStage(opts.onStageChange, { attempt:
|
|
144
|
-
// Long/unknown fast-pool window: replay at
|
|
145
|
-
// standard speed rather than waiting it out.
|
|
146
|
-
if (params?.speed === 'fast' && noteFastModeCapacityError(lastErr, { fast: true }) !== 'retry-fast') {
|
|
147
|
-
delete params.speed;
|
|
148
|
-
}
|
|
197
|
+
onRetry: ({ attempt: retryNo, maxAttempts, lastErr, delayMs, delayReason }) => {
|
|
198
|
+
emitProviderRetryStage(opts.onStageChange, { attempt: retryNo + 1, maxAttempts, lastErr, delayMs });
|
|
149
199
|
const status = Number(lastErr?.httpStatus || lastErr?.status || lastErr?.response?.status || 0);
|
|
150
200
|
if (status === 429) notifyCurrentAnthropicRateLimit(lastErr);
|
|
151
201
|
const delayLabel = retryDelayLabel(delayMs, delayReason);
|
|
152
202
|
process.stderr.write(
|
|
153
|
-
`[${label}] retry attempt ${
|
|
203
|
+
`[${label}] retry attempt ${retryNo + 1} after ${lastErr?.message || lastErr?.code || 'transient error'}${delayLabel}\n`
|
|
154
204
|
);
|
|
155
205
|
},
|
|
206
|
+
});
|
|
207
|
+
} catch (err) {
|
|
208
|
+
// Whatever escapes withRetry failed before any stream existed and has
|
|
209
|
+
// already spent the request-level budget: mark it so mid-stream
|
|
210
|
+
// recovery never grants it a second, SSE-sized retry budget.
|
|
211
|
+
if (err && typeof err === 'object' && !(err instanceof AnthropicFallbackTriggeredError)) {
|
|
212
|
+
err.initialResponseError = true;
|
|
156
213
|
}
|
|
157
|
-
|
|
214
|
+
throw err;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
158
217
|
|
|
159
218
|
const requestNonStreamingMessage = (nonStreamingParams, signal) =>
|
|
160
219
|
withRetry(
|
|
161
|
-
async ({ signal: attemptSignal }) => {
|
|
220
|
+
withBodyRecovery(nonStreamingParams, async ({ signal: attemptSignal }) => {
|
|
162
221
|
noteRequestServiceTier(nonStreamingParams.speed);
|
|
163
|
-
|
|
164
|
-
|
|
222
|
+
try {
|
|
223
|
+
return await client.messages.create(nonStreamingParams, requestOptions(attemptSignal));
|
|
224
|
+
} catch (err) {
|
|
225
|
+
throw annotateHttpFailure(err);
|
|
226
|
+
}
|
|
227
|
+
}),
|
|
165
228
|
{
|
|
166
229
|
...retryPolicy(signal, `${label} Anthropic non-streaming fallback`, `${label}-nonstreaming-request`),
|
|
167
230
|
onRetry: ({ attempt, maxAttempts, lastErr, delayMs }) =>
|