@bitkyc08/opencodex 2.80.0 → 2.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/bin/ocx.mjs +166 -73
- package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
- package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
- package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
- package/gui/dist/assets/index-D3FBCNiP.js +94 -0
- package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/claude-green.svg +1 -0
- package/package.json +3 -2
- package/src/adapters/anthropic-model-contract.ts +8 -2
- package/src/adapters/anthropic.ts +8 -3
- package/src/adapters/codebuddy/mcp-server.ts +2 -25
- package/src/adapters/codebuddy/tool-bridge.ts +1 -7
- package/src/adapters/coding-agent/mcp-server.ts +33 -0
- package/src/adapters/coding-agent/protocol.ts +122 -17
- package/src/adapters/coding-agent/tool-catalog.ts +75 -0
- package/src/adapters/coding-agent/turn.ts +101 -44
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +2 -0
- package/src/adapters/devin/live-models.ts +2 -0
- package/src/adapters/kiro-retry.ts +9 -4
- package/src/adapters/openai-chat/messages.ts +7 -6
- package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
- package/src/adapters/openai-responses/passthrough.ts +9 -4
- package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
- package/src/adapters/physical-send.ts +8 -5
- package/src/adapters/qoder/adapter.ts +41 -6
- package/src/adapters/qoder/scaffold-guard.ts +2 -3
- package/src/adapters/zed.ts +16 -1
- package/src/claude/agents-inject.ts +14 -3
- package/src/claude/context-windows.ts +19 -17
- package/src/claude/desktop-3p.ts +88 -12
- package/src/claude/desktop-profile.ts +2 -1
- package/src/claude/gateway-cache.ts +18 -1
- package/src/claude/inbound-cache-stabilize.ts +4 -9
- package/src/claude/inbound.ts +78 -3
- package/src/claude/intercept/cli-catalog.ts +3 -0
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/claude/intercept/picker-ca-persistence.ts +7 -6
- package/src/claude/intercept/picker-listener.ts +71 -4
- package/src/claude/intercept/picker-models.ts +14 -6
- package/src/claude/intercept/settings.ts +3 -0
- package/src/claude/long-context.ts +66 -0
- package/src/claude/model-info.ts +19 -16
- package/src/claude/outbound.ts +94 -9
- package/src/claude/subagent-model.ts +40 -11
- package/src/cli/account-anthropic-threshold.ts +14 -5
- package/src/cli/account-api.ts +3 -1
- package/src/cli/account-extended.ts +13 -9
- package/src/cli/account-policy-dto.ts +1 -1
- package/src/cli/account-policy.ts +13 -4
- package/src/cli/account.ts +3 -3
- package/src/cli/agent.ts +9 -5
- package/src/cli/aside-profile-recovery.ts +33 -0
- package/src/cli/capabilities-accounts.ts +2 -2
- package/src/cli/capabilities-agents-routing.ts +24 -0
- package/src/cli/capabilities-base.ts +5 -5
- package/src/cli/capabilities-integrations.ts +18 -2
- package/src/cli/cli-path-diagnostics.ts +132 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/desktop-runtime-guidance.ts +65 -0
- package/src/cli/dispatch.ts +15 -1
- package/src/cli/doctor.ts +16 -3
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +25 -14
- package/src/cli/integration-aside-sync.ts +2 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/integration-preview.ts +8 -1
- package/src/cli/integrations.ts +48 -6
- package/src/cli/message-args.ts +34 -0
- package/src/cli/message-command.ts +43 -0
- package/src/cli/message-runtime.ts +6 -0
- package/src/cli/observe.ts +3 -1
- package/src/cli/provider.ts +29 -6
- package/src/cli/registry.ts +24 -2
- package/src/cli/resolve.ts +25 -2
- package/src/cli/root.ts +4 -2
- package/src/cli/status.ts +64 -12
- package/src/cli/update-restart-child.ts +4 -2
- package/src/cli/update-restart-home.ts +28 -10
- package/src/cli/update-restart-service-record.ts +116 -0
- package/src/cli/update-restart-supervision.ts +96 -0
- package/src/cli/update-restart.ts +59 -13
- package/src/cli/v2.ts +27 -20
- package/src/cli/version-skew-notice.ts +77 -0
- package/src/clients/config-export/commandcode.ts +131 -0
- package/src/clients/config-export/contracts.ts +12 -0
- package/src/clients/config-export.ts +64 -1
- package/src/clients/lazycodex.ts +1 -1
- package/src/clients/omo-role-models.ts +32 -7
- package/src/codex/auth-api/account-list.ts +11 -3
- package/src/codex/auth-api/account-selection.ts +107 -0
- package/src/codex/auth-api/main-account-probe.ts +25 -8
- package/src/codex/auth-api/pool-mode-gate.ts +33 -9
- package/src/codex/auth-api/pool-quota-probe.ts +15 -1
- package/src/codex/auth-api/routes.ts +11 -49
- package/src/codex/auth-context.ts +20 -1
- package/src/codex/autostart-health.ts +12 -3
- package/src/codex/catalog/auto-review.ts +13 -6
- package/src/codex/catalog/build-entries.ts +33 -7
- package/src/codex/catalog/bundled.ts +155 -26
- package/src/codex/catalog/combo-member.ts +3 -2
- package/src/codex/catalog/control-plane.ts +45 -0
- package/src/codex/catalog/effort.ts +37 -6
- package/src/codex/catalog/gather-capture.ts +10 -3
- package/src/codex/catalog/model-hints.ts +15 -8
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/operator-tiers.ts +38 -0
- package/src/codex/catalog/parsing.ts +2 -1
- package/src/codex/catalog/provider-models.ts +58 -44
- package/src/codex/catalog/retained-sync.ts +7 -5
- package/src/codex/catalog/routed-gather.ts +15 -1
- package/src/codex/catalog-auto-refresh-sources.ts +3 -4
- package/src/codex/catalog-auto-refresh.ts +19 -0
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-home-owner.ts +3 -0
- package/src/codex/config-write-lock.ts +333 -0
- package/src/codex/control-plane-models.ts +6 -0
- package/src/codex/convergence.ts +2 -1
- package/src/codex/features.ts +257 -200
- package/src/codex/inject/config-write-section.ts +34 -0
- package/src/codex/inject/multi-agent-v2.ts +14 -6
- package/src/codex/inject/remove.ts +36 -11
- package/src/codex/inject/restore.ts +85 -20
- package/src/codex/inject-coordination.ts +15 -6
- package/src/codex/inject.ts +62 -20
- package/src/codex/journal.ts +62 -17
- package/src/codex/main-account-cache.ts +43 -0
- package/src/codex/paths.ts +2 -0
- package/src/codex/prepared-home.ts +18 -0
- package/src/codex/prompt-journal.ts +25 -12
- package/src/codex/prompt-layers.ts +49 -26
- package/src/codex/prompt-lock-claim.ts +134 -0
- package/src/codex/prompt-lock-evidence.ts +26 -0
- package/src/codex/prompt-lock-io.ts +16 -0
- package/src/codex/prompt-lock-owner.ts +130 -0
- package/src/codex/prompt-lock.ts +84 -53
- package/src/codex/routing/failure-window.ts +146 -0
- package/src/codex/routing/selection.ts +4 -1
- package/src/codex/routing.ts +13 -17
- package/src/codex/runtime.ts +106 -18
- package/src/codex/shim.ts +45 -19
- package/src/combos/jev-decision-contract.ts +25 -2
- package/src/combos/jev-service-exchange.ts +281 -0
- package/src/combos/jev.ts +34 -219
- package/src/combos/types.ts +1 -1
- package/src/config/atomic-write.ts +1 -1
- package/src/config/codex-ws-reuse-setting.ts +10 -0
- package/src/config/diagnostics.ts +27 -16
- package/src/config/live-reconcile.ts +17 -0
- package/src/config/load-degrade.ts +42 -0
- package/src/config/rebase-provenance.ts +11 -0
- package/src/config/schema/anthropic-account-pool.ts +143 -0
- package/src/config/schema/config-schema.ts +11 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +566 -298
- package/src/generated/model-metadata.ts +7 -6
- package/src/grok/inject.ts +50 -4
- package/src/grok/sync.ts +2 -1
- package/src/images/loop.ts +30 -11
- package/src/integrations/aside-profiles.ts +10 -3
- package/src/integrations/catalog-refresh.ts +19 -3
- package/src/integrations/mutation-plan.ts +7 -0
- package/src/integrations/registry.ts +8 -0
- package/src/integrations/state.ts +9 -2
- package/src/integrations/writer.ts +17 -5
- package/src/lib/bun-path-runtime.d.mts +32 -0
- package/src/lib/bun-path-runtime.mjs +95 -0
- package/src/lib/bun-runtime-preflight.ts +140 -0
- package/src/lib/desktop-cli-handoff.d.mts +20 -0
- package/src/lib/desktop-cli-handoff.mjs +92 -0
- package/src/lib/desktop-cli-record.d.mts +29 -0
- package/src/lib/desktop-cli-record.mjs +102 -0
- package/src/lib/lab-live-route-production.ts +9 -1
- package/src/lib/request-execution-budget.ts +244 -58
- package/src/lib/spend-pool-alias-validation.ts +79 -0
- package/src/lib/spend-pool-continuity.ts +34 -0
- package/src/lib/spend-reservation-ledger.ts +412 -50
- package/src/lib/state-store-registrations.ts +20 -3
- package/src/lib/synced-state-location.ts +46 -6
- package/src/lib/test-home-guard.ts +87 -1
- package/src/lib/translator-budget.ts +17 -4
- package/src/lib/upstream-retry.ts +17 -5
- package/src/lib/windows-atomic-replace.ts +38 -16
- package/src/lib/windows-elevation.ts +6 -0
- package/src/lib/windows-secret-acl.ts +92 -25
- package/src/lib/winsw.ts +2 -3
- package/src/lib/workflow-budget.ts +53 -11
- package/src/messaging/budget.ts +45 -0
- package/src/messaging/discovery.ts +57 -0
- package/src/messaging/envelope.ts +49 -0
- package/src/messaging/input.ts +37 -0
- package/src/messaging/rpc.ts +196 -0
- package/src/messaging/send.ts +58 -0
- package/src/messaging/socket.ts +72 -0
- package/src/messaging/types.ts +29 -0
- package/src/oauth/anthropic-account-refusal.ts +90 -18
- package/src/oauth/anthropic-account-threshold.ts +8 -2
- package/src/oauth/anthropic-continuity.ts +15 -1
- package/src/oauth/anthropic-model-quota.ts +120 -48
- package/src/oauth/anthropic-model-routes.ts +11 -3
- package/src/oauth/anthropic-oauth-definitions.ts +98 -0
- package/src/oauth/anthropic-pool-config.ts +30 -0
- package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
- package/src/oauth/anthropic-routing.ts +1202 -866
- package/src/oauth/anthropic-send-ownership.ts +41 -0
- package/src/oauth/anthropic.ts +4 -1
- package/src/oauth/chatgpt.ts +113 -41
- package/src/oauth/generic-account-failover.ts +3 -1
- package/src/oauth/health.ts +8 -6
- package/src/oauth/index.ts +96 -175
- package/src/oauth/kiro.ts +22 -9
- package/src/oauth/login-cli.ts +2 -0
- package/src/oauth/model-discovery-auth.ts +43 -0
- package/src/oauth/pool-kernel.ts +11 -5
- package/src/oauth/pool-settings-capability.ts +5 -3
- package/src/oauth/store-anthropic-instance.ts +87 -0
- package/src/oauth/store.ts +68 -10
- package/src/oauth/token-guardian.ts +2 -0
- package/src/oauth/types.ts +2 -0
- package/src/protocols/plan-snapshot.ts +5 -0
- package/src/protocols/settings.ts +20 -5
- package/src/providers/anthropic-instance-id.ts +47 -0
- package/src/providers/anthropic-instance.ts +48 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
- package/src/providers/azure-model-metadata.ts +115 -0
- package/src/providers/derive.ts +23 -0
- package/src/providers/kiro-models.ts +3 -0
- package/src/providers/label.ts +1 -1
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/quota/account-cache.ts +37 -11
- package/src/providers/quota/anthropic-account-quota.ts +93 -0
- package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
- package/src/providers/quota/report-cache.ts +24 -1
- package/src/providers/quota/vendor-probes-key.ts +127 -17
- package/src/providers/quota/vendor-probes-oauth.ts +46 -14
- package/src/providers/quota.ts +23 -33
- package/src/providers/registry/entries-core.ts +35 -30
- package/src/providers/registry/model-ids.ts +1 -0
- package/src/providers/registry/model-seeds.ts +7 -4
- package/src/providers/registry/types.ts +3 -0
- package/src/providers/registry.ts +3 -3
- package/src/responses/reasoning-envelope.ts +29 -1
- package/src/responses/reasoning-replay-cache.ts +17 -1
- package/src/responses/spill-store.ts +20 -3
- package/src/responses/state/metrics.ts +95 -0
- package/src/responses/state/snapshot-codec.ts +6 -0
- package/src/responses/state/spill-failure.ts +12 -0
- package/src/responses/state/spill-queue.ts +13 -5
- package/src/responses/state/unforced-store-false.ts +55 -0
- package/src/responses/state.ts +68 -76
- package/src/responses/task-input.ts +17 -0
- package/src/router.ts +28 -4
- package/src/routing/compatibility/assemble.ts +1 -1
- package/src/routing/quota.ts +7 -3
- package/src/server/auth-cors.ts +5 -0
- package/src/server/background-lifecycle.ts +27 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native.ts +64 -28
- package/src/server/claude-messages.ts +59 -8
- package/src/server/gui-static.ts +38 -4
- package/src/server/inbound-body-admission.ts +1 -0
- package/src/server/index/claude-intercept-lifecycle.ts +3 -1
- package/src/server/index/serve-options.ts +10 -2
- package/src/server/index/spend-ledger-lifecycle.ts +12 -5
- package/src/server/index/startup-warnings.ts +19 -0
- package/src/server/index.ts +5 -2
- package/src/server/inference/context.ts +1 -1
- package/src/server/lifecycle.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +123 -38
- package/src/server/management/anthropic-account-threshold.ts +12 -9
- package/src/server/management/anthropic-pool-settings.ts +72 -0
- package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
- package/src/server/management/codex-agent-role-routes.ts +4 -2
- package/src/server/management/codex-prompt-routes.ts +1 -0
- package/src/server/management/codex-role-auto-assign.ts +13 -2
- package/src/server/management/config-routes.ts +85 -14
- package/src/server/management/context.ts +2 -2
- package/src/server/management/decision-routes.ts +2 -1
- package/src/server/management/integration-routes.ts +25 -2
- package/src/server/management/oauth-account-routes.ts +79 -98
- package/src/server/management/provider-instance-ownership.ts +44 -0
- package/src/server/management/provider-routes.ts +21 -28
- package/src/server/management/route-registry.ts +3 -1
- package/src/server/management/routing-profile-routes.ts +4 -4
- package/src/server/management/shared.ts +3 -3
- package/src/server/management/system-restart.ts +44 -14
- package/src/server/management/system-routes.ts +24 -2
- package/src/server/management/vision-sidecar-options.ts +9 -6
- package/src/server/management/web-search-sidecar-options.ts +51 -2
- package/src/server/management-auth.ts +6 -0
- package/src/server/messages-native-eligibility.ts +3 -2
- package/src/server/messages-native-oauth.ts +91 -45
- package/src/server/messages-native-selector.ts +39 -0
- package/src/server/messages-native.ts +133 -38
- package/src/server/messages-response-headers.ts +14 -0
- package/src/server/request-log-conversation.ts +48 -5
- package/src/server/request-log.ts +36 -2
- package/src/server/responses/adapter-continuation.ts +31 -19
- package/src/server/responses/adapter-dispatch.ts +75 -24
- package/src/server/responses/antigravity-validation-refusal.ts +20 -6
- package/src/server/responses/codex-ws-exchange.ts +17 -2
- package/src/server/responses/codex-ws-pool.ts +100 -13
- package/src/server/responses/codex-ws-wire.ts +9 -0
- package/src/server/responses/combo-requested-effort.ts +3 -1
- package/src/server/responses/compact.ts +25 -8
- package/src/server/responses/compaction-recovery.ts +1 -1
- package/src/server/responses/core-codex-account.ts +22 -1
- package/src/server/responses/core-combo-native.ts +24 -4
- package/src/server/responses/core-combo.ts +38 -25
- package/src/server/responses/core-lifetime.ts +3 -36
- package/src/server/responses/core-normalize.ts +1 -0
- package/src/server/responses/core-options.ts +8 -1
- package/src/server/responses/core-replay.ts +78 -0
- package/src/server/responses/core.ts +3 -3
- package/src/server/responses/fetch-helpers.ts +26 -3
- package/src/server/responses/passthrough-delivery.ts +30 -4
- package/src/server/responses/passthrough-dispatch.ts +39 -9
- package/src/server/responses/request-prepare.ts +41 -5
- package/src/server/responses/request-send-budget.ts +150 -50
- package/src/server/responses/request-spend.ts +325 -33
- package/src/server/responses/request-transport.ts +132 -52
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +13 -3
- package/src/server/responses/sidecar-execution.ts +113 -22
- package/src/server/responses/sidecar-send-budget.ts +58 -0
- package/src/server/responses/ws-upstream.ts +19 -6
- package/src/server/responses-undeclared-tool-guard.ts +5 -1
- package/src/server/startup-health-cache.ts +2 -1
- package/src/server/workflow-refusal.ts +33 -0
- package/src/service/cli.ts +20 -4
- package/src/service/desktop-command-guard.ts +32 -0
- package/src/service/desktop-startup.ts +66 -40
- package/src/service/desktop-supervision.d.mts +26 -0
- package/src/service/desktop-supervision.mjs +140 -0
- package/src/service/managing-cli.ts +1 -0
- package/src/service/orchestration.ts +46 -20
- package/src/service/ownership-mutation-lease.d.mts +1 -1
- package/src/service/ownership-mutation-lease.mjs +5 -7
- package/src/service/repair.ts +25 -9
- package/src/service/state.ts +4 -3
- package/src/service/systemd.ts +17 -8
- package/src/service/windows-ops.ts +61 -22
- package/src/sidecar/anthropic-binding.ts +79 -0
- package/src/sidecar/auth.ts +76 -2
- package/src/storage/policy-job.ts +5 -1
- package/src/storage/policy-worker.ts +3 -1
- package/src/storage/policy.ts +9 -0
- package/src/types/anthropic-account-pool.ts +33 -0
- package/src/types/config.ts +33 -28
- package/src/types/provider.ts +5 -0
- package/src/types/request.ts +5 -0
- package/src/types/tools.ts +7 -0
- package/src/types/wire.ts +1 -0
- package/src/types.ts +4 -0
- package/src/update/index.ts +57 -9
- package/src/update/restart-ownership.ts +10 -3
- package/src/update/runtime-ownership.d.mts +6 -0
- package/src/update/runtime-ownership.mjs +23 -7
- package/src/usage/cost.ts +3 -2
- package/src/usage/expected-prices.ts +66 -14
- package/src/vision/anthropic-describe.ts +16 -3
- package/src/vision/index.ts +3 -0
- package/src/vision/plan.ts +19 -6
- package/src/web-search/alpha-search.ts +7 -1
- package/src/web-search/anthropic-executor.ts +16 -4
- package/src/web-search/index.ts +7 -3
- package/src/web-search/loop.ts +32 -7
- package/src/web-search/passthrough-bridge.ts +4 -1
- package/src/web-search/sidecar-providers.ts +4 -3
- package/gui/dist/assets/App-MbDVfUeC.js +0 -54
- package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
- package/gui/dist/assets/index-UJt6npXk.js +0 -94
- package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { SendBudgetExhaustedError } from "../../lib/upstream-retry";
|
|
2
|
+
import { rebindPhysicalSend } from "../../lib/request-execution-budget";
|
|
3
|
+
import { anthropicModelQuotaFor } from "../../oauth/anthropic-model-quota";
|
|
4
|
+
import { anthropicRatePolicyFor } from "../../oauth/anthropic-rate-limit-policy";
|
|
5
|
+
import { configuredAnthropicInstance } from "../../providers/anthropic-instance";
|
|
6
|
+
import { resolveAnthropicMessagesUrl } from "../../adapters/anthropic";
|
|
7
|
+
import { bindAnthropicRefusalCredentialForSend } from "../../oauth/anthropic-account-refusal";
|
|
8
|
+
import { captureAnthropicPhysicalSendOwnership, anthropicPhysicalSendOwnershipIsCurrent, type AnthropicPhysicalSendOwnership } from "../../oauth/anthropic-send-ownership";
|
|
4
9
|
import type { ResponsesRequestContext, ResponsesAdmissionState } from "./core-options";
|
|
5
10
|
import type { PreparedResponsesRequest } from "./request-prepare";
|
|
6
11
|
import type { OAuthAccessSnapshot } from "../../oauth";
|
|
@@ -16,20 +21,12 @@ import type { ProviderAdapter, AdapterRequest } from "../../adapters/base";
|
|
|
16
21
|
import { releaseProviderRequestSlot, waitForProviderRequestSlot, type ProviderRequestSlot } from "../../providers/request-pacing";
|
|
17
22
|
import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig, OcxUsage } from "../../types";
|
|
18
23
|
import type { AnthropicAccountSelectionReason } from "../../oauth/anthropic-routing";
|
|
19
|
-
import {
|
|
24
|
+
import { resolveAnthropicModelRouteForInstance, routeCandidates, type AnthropicRouteDecision } from "../../oauth/anthropic-model-routes";
|
|
20
25
|
import {
|
|
21
|
-
|
|
22
|
-
isAnthropicAccountPoolEnabled,
|
|
23
|
-
getAnthropicPoolAccessSnapshot,
|
|
24
|
-
getAnthropicAccountHealthSnapshot,
|
|
26
|
+
anthropicRoutingFor,
|
|
25
27
|
AnthropicAccountCooldownError,
|
|
26
|
-
getEligibleAnthropicAccounts,
|
|
27
|
-
commitAnthropicSelectionRouting,
|
|
28
28
|
formatAnthropicProviderForLog,
|
|
29
29
|
anthropicSessionKeyFromParts,
|
|
30
|
-
resolveAnthropicAccountForSession,
|
|
31
|
-
getAnthropicPoolRetryAfterSeconds,
|
|
32
|
-
hasAnthropicFailoverQuorum,
|
|
33
30
|
} from "../../oauth/anthropic-routing";
|
|
34
31
|
import {
|
|
35
32
|
OAuthAccountPausedError,
|
|
@@ -65,7 +62,7 @@ import { resolveAdapter, resolveWireProtocolOverride } from "../adapter-resolve"
|
|
|
65
62
|
import { providerFetch, sendWithConnectionPolicy } from "./fetch-helpers";
|
|
66
63
|
import type { ProviderFetchOptions } from "./fetch-helpers";
|
|
67
64
|
import { captureConfigGeneration } from "../../lib/state-store-sweeper";
|
|
68
|
-
import {
|
|
65
|
+
import { recordAnthropicAccountQuotaFromHeadersForInstance, hasPassiveAccountQuota } from "../../providers/quota";
|
|
69
66
|
import { checkOutboundBodySize, describeOutboundBodyRefusal } from "./outbound-body-guard";
|
|
70
67
|
import { formatErrorResponse } from "../../bridge";
|
|
71
68
|
import { bindRouteReasoningReplayScope } from "./core-replay";
|
|
@@ -105,6 +102,39 @@ export async function prepareResponsesTransport(
|
|
|
105
102
|
) {
|
|
106
103
|
const { config, logCtx, options, req } = requestContext;
|
|
107
104
|
const { route, parsed, inboundWire, translatorBudget } = requestState;
|
|
105
|
+
const anthropicInstance = route.provider.authMode === "oauth"
|
|
106
|
+
? configuredAnthropicInstance(config, route.providerName) : undefined;
|
|
107
|
+
// Refuse custom/orphan B OAuth before any generic resolver can observe its auth row.
|
|
108
|
+
if (route.providerName === "anthropic2" && route.provider.authMode === "oauth" && !anthropicInstance) {
|
|
109
|
+
return formatErrorResponse(401, "authentication_error", "Anthropic Pool 2 requires an enabled builtin OAuth provider");
|
|
110
|
+
}
|
|
111
|
+
const anthropicRouting = anthropicInstance ? anthropicRoutingFor(anthropicInstance) : undefined;
|
|
112
|
+
const anthropicQuota = anthropicInstance ? anthropicModelQuotaFor(anthropicInstance) : undefined;
|
|
113
|
+
const anthropicRatePolicy = anthropicInstance ? anthropicRatePolicyFor(anthropicInstance) : undefined;
|
|
114
|
+
const authorizedAnthropicTarget = anthropicInstance === "anthropic2"
|
|
115
|
+
? resolveAnthropicMessagesUrl(route.provider) : undefined;
|
|
116
|
+
const anthropicAdmissionIsCurrent = (): boolean => {
|
|
117
|
+
if (!anthropicInstance) return true;
|
|
118
|
+
if (configuredAnthropicInstance(config, route.providerName) !== anthropicInstance || route.provider.authMode !== "oauth") return false;
|
|
119
|
+
if (anthropicInstance !== "anthropic2") return true;
|
|
120
|
+
try {
|
|
121
|
+
return resolveAnthropicMessagesUrl(config.providers[anthropicInstance]!) === authorizedAnthropicTarget
|
|
122
|
+
&& resolveAnthropicMessagesUrl(route.provider) === authorizedAnthropicTarget;
|
|
123
|
+
} catch { return false; }
|
|
124
|
+
};
|
|
125
|
+
if (!anthropicAdmissionIsCurrent()) {
|
|
126
|
+
return formatErrorResponse(401, "authentication_error", "Anthropic Pool 2 provider target changed; retry the request");
|
|
127
|
+
}
|
|
128
|
+
const requireAnthropicAdmission = (): void => {
|
|
129
|
+
if (!anthropicAdmissionIsCurrent()) throw new OAuthLoginRequiredError(anthropicInstance!);
|
|
130
|
+
};
|
|
131
|
+
const currentAnthropicRouteDecision = (): AnthropicRouteDecision | null => {
|
|
132
|
+
requireAnthropicAdmission();
|
|
133
|
+
if (!anthropicInstance || !anthropicRouting?.isAnthropicAccountPoolEnabled(config)) return null;
|
|
134
|
+
const result = resolveAnthropicModelRouteForInstance(anthropicInstance, config, route.modelId);
|
|
135
|
+
if (result.error) throw new Error("Invalid Anthropic model route configuration");
|
|
136
|
+
return result.decision;
|
|
137
|
+
};
|
|
108
138
|
const rawKiroCap = route.providerName === "kiro" && route.provider.authMode === "oauth"
|
|
109
139
|
? config.providers.kiro?.oauthAccountFailover?.maxConcurrentPerAccount : undefined;
|
|
110
140
|
const kiroCap = typeof rawKiroCap === "number" && Number.isInteger(rawKiroCap)
|
|
@@ -165,31 +195,40 @@ export async function prepareResponsesTransport(
|
|
|
165
195
|
): Promise<OAuthAccessSnapshot | null> => {
|
|
166
196
|
const maxSelectionAttempts = 3;
|
|
167
197
|
for (let attempt = 0; attempt < maxSelectionAttempts; attempt++) {
|
|
198
|
+
requireAnthropicAdmission();
|
|
199
|
+
if (candidate.provider !== route.providerName) return null;
|
|
200
|
+
if (anthropicInstance) anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
168
201
|
if (!oauthSelection) return null;
|
|
169
|
-
const proactiveEnabled =
|
|
170
|
-
? isAnthropicAccountPoolEnabled(config)
|
|
202
|
+
const proactiveEnabled = anthropicInstance !== undefined
|
|
203
|
+
? anthropicRouting!.isAnthropicAccountPoolEnabled(config)
|
|
171
204
|
: (config.providers[route.providerName]?.oauthAccountFailover?.enabled
|
|
172
205
|
?? config.oauthAccountFailover?.enabled) === true;
|
|
173
206
|
if (proactive && candidate.accountId !== oauthSelection.accountId && !proactiveEnabled) {
|
|
174
207
|
oauthSelection = captureOAuthAccountSelection(route.providerName);
|
|
175
208
|
if (!oauthSelection) return null;
|
|
176
|
-
candidate =
|
|
177
|
-
? await getAnthropicPoolAccessSnapshot(oauthSelection.accountId)
|
|
209
|
+
candidate = anthropicInstance !== undefined
|
|
210
|
+
? await anthropicRouting!.getAnthropicPoolAccessSnapshot(oauthSelection.accountId)
|
|
178
211
|
: await getValidAccessSnapshotForAccount(route.providerName, oauthSelection.accountId, { requireUsableAccount: true });
|
|
179
212
|
}
|
|
180
|
-
|
|
213
|
+
requireAnthropicAdmission();
|
|
214
|
+
if (candidate.provider !== route.providerName) return null;
|
|
215
|
+
if (anthropicInstance) anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
216
|
+
if (anthropicRouteDecision && !routeCandidates(anthropicRouting!.getEligibleAnthropicAccounts(Date.now(), route.modelId), anthropicRouteDecision).includes(candidate.accountId)) return null;
|
|
181
217
|
const committed = await commitOAuthAccountSelection(route.providerName, candidate.accountId, {
|
|
182
218
|
expectedSelection: oauthSelection,
|
|
183
219
|
expectedCredentialGeneration: candidate.generation,
|
|
184
220
|
requireUsableAccount: true,
|
|
185
221
|
});
|
|
222
|
+
requireAnthropicAdmission();
|
|
186
223
|
if (committed) {
|
|
187
|
-
if (
|
|
224
|
+
if (anthropicInstance) anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
225
|
+
if (anthropicInstance !== undefined && !anthropicRouting!.commitAnthropicSelectionRouting(
|
|
188
226
|
candidate.accountId, oauthSelection, committed,
|
|
189
227
|
{ config, sessionKey: anthropicSessionKey, reason: anthropicReason, expectedCredentialGeneration: candidate.generation, routeDecision: anthropicRouteDecision, model: route.modelId },
|
|
190
228
|
)) return null;
|
|
191
229
|
oauthSelection = committed;
|
|
192
230
|
servingOAuthSnapshot = candidate;
|
|
231
|
+
if (anthropicInstance) replayOAuthCredentialSnapshot = { accountId: candidate.accountId, generation: candidate.generation };
|
|
193
232
|
forgetGenericFailoverRoster(route.providerName);
|
|
194
233
|
return candidate;
|
|
195
234
|
}
|
|
@@ -199,13 +238,13 @@ export async function prepareResponsesTransport(
|
|
|
199
238
|
if (!oauthSelection) return null;
|
|
200
239
|
// A revision also changes on per-account policy edits. Re-evaluate the selector
|
|
201
240
|
// after credential waits even without a model route, rather than reusing stale active.
|
|
202
|
-
const revisedAnthropic =
|
|
203
|
-
? resolveAnthropicAccountForSession(anthropicSessionKey, config, Date.now(), anthropicRouteDecision, route.modelId) : null;
|
|
241
|
+
const revisedAnthropic = anthropicInstance !== undefined
|
|
242
|
+
? anthropicRouting!.resolveAnthropicAccountForSession(anthropicSessionKey, config, Date.now(), anthropicRouteDecision, route.modelId) : null;
|
|
204
243
|
const revisedAnthropicId = revisedAnthropic?.accountId;
|
|
205
|
-
if (
|
|
244
|
+
if (anthropicInstance !== undefined && !revisedAnthropicId) return null;
|
|
206
245
|
if (revisedAnthropic) anthropicReason = revisedAnthropic.reason;
|
|
207
|
-
candidate =
|
|
208
|
-
? await getAnthropicPoolAccessSnapshot(revisedAnthropicId ?? oauthSelection.accountId)
|
|
246
|
+
candidate = anthropicInstance !== undefined
|
|
247
|
+
? await anthropicRouting!.getAnthropicPoolAccessSnapshot(revisedAnthropicId ?? oauthSelection.accountId)
|
|
209
248
|
: await getValidAccessSnapshotForAccount(route.providerName, oauthSelection.accountId, { requireUsableAccount: true });
|
|
210
249
|
if (route.provider.googleMode === "cloud-code-assist" && !candidate.projectId) return null;
|
|
211
250
|
}
|
|
@@ -268,6 +307,8 @@ export async function prepareResponsesTransport(
|
|
|
268
307
|
snapshot: OAuthAccessSnapshot,
|
|
269
308
|
retryParsed: OcxParsedRequest = parsed,
|
|
270
309
|
): Promise<OAuthAccessSnapshot | null> => {
|
|
310
|
+
requireAnthropicAdmission();
|
|
311
|
+
if (snapshot.provider !== route.providerName) return null;
|
|
271
312
|
if (route.provider.googleMode === "cloud-code-assist" && !snapshot.projectId) return null;
|
|
272
313
|
const signal = options.abortSignal ?? req.signal;
|
|
273
314
|
let speculative = kiroLoadEnabled && options.accountLoad?.lease?.accountId !== snapshot.accountId
|
|
@@ -319,9 +360,9 @@ export async function prepareResponsesTransport(
|
|
|
319
360
|
// served it. All three rotation sites funnel through here, so this is the only re-stamp
|
|
320
361
|
// needed -- and putting it anywhere else would let one of the three drift.
|
|
321
362
|
stampOAuthAccountLabel(logCtx, route.providerName, route.provider, snapshot.accountId);
|
|
322
|
-
if (
|
|
363
|
+
if (anthropicInstance !== undefined) {
|
|
323
364
|
anthropicPoolAccountId = snapshot.accountId;
|
|
324
|
-
logCtx.provider = formatAnthropicProviderForLog(
|
|
365
|
+
logCtx.provider = formatAnthropicProviderForLog(anthropicInstance!, snapshot.accountId, config);
|
|
325
366
|
} else {
|
|
326
367
|
genericFailoverAccountId = snapshot.accountId;
|
|
327
368
|
}
|
|
@@ -354,14 +395,20 @@ export async function prepareResponsesTransport(
|
|
|
354
395
|
}
|
|
355
396
|
};
|
|
356
397
|
const selectionIsCurrent = (binding: DispatchBinding | undefined): boolean => {
|
|
398
|
+
if (!anthropicAdmissionIsCurrent()) return false;
|
|
357
399
|
if (route.provider.authMode === "forward") return true;
|
|
358
400
|
if (!binding) return false;
|
|
359
401
|
if (binding.kind === "api-key") return providerApiKeySelectionIsCurrent(config, route.providerName, binding.provider);
|
|
402
|
+
if (binding.snapshot.provider !== route.providerName) return false;
|
|
403
|
+
if (anthropicInstance) {
|
|
404
|
+
anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
405
|
+
if (anthropicRouteDecision && !routeCandidates(anthropicRouting!.getEligibleAnthropicAccounts(Date.now(), route.modelId), anthropicRouteDecision).includes(binding.snapshot.accountId)) return false;
|
|
406
|
+
}
|
|
360
407
|
const selected = captureOAuthAccountSelection(route.providerName);
|
|
361
408
|
const row = getAccountCredentialWithStatus(route.providerName, binding.snapshot.accountId);
|
|
362
409
|
return selected?.accountId === binding.selection.accountId && selected?.revision === binding.selection.revision
|
|
363
410
|
&& !!row && !row.paused && !row.needsReauth && row.credential.expires > Date.now()
|
|
364
|
-
&& (
|
|
411
|
+
&& (anthropicInstance === undefined || !anthropicRouting!.getAnthropicAccountHealthSnapshot(binding.snapshot.accountId) && !anthropicRatePolicy!.anthropicRatePauseUntil(binding.snapshot.accountId) && !anthropicQuota!.anthropicFamilyRejected(binding.snapshot.accountId, route.modelId))
|
|
365
412
|
&& credentialGeneration(row.credential) === binding.snapshot.generation;
|
|
366
413
|
};
|
|
367
414
|
const resolveSelectionAdapter = (provider: OcxProviderConfig, retention = config.cacheRetention): ProviderAdapter => {
|
|
@@ -422,17 +469,18 @@ export async function prepareResponsesTransport(
|
|
|
422
469
|
return resolved;
|
|
423
470
|
};
|
|
424
471
|
const refreshDispatchAdapter = async (requestParsed: OcxParsedRequest): Promise<ProviderAdapter> => {
|
|
472
|
+
requireAnthropicAdmission();
|
|
425
473
|
if (route.provider.authMode === "oauth") {
|
|
426
474
|
// Pacing may outlive admission. Preserve local pause/cooldown reasons even when
|
|
427
475
|
// a strict route rejects the old proposal before another bearer can be resolved.
|
|
428
476
|
let candidate = servingOAuthSnapshot;
|
|
429
|
-
if (
|
|
477
|
+
if (anthropicInstance !== undefined) {
|
|
430
478
|
oauthSelection = captureOAuthAccountSelection(route.providerName);
|
|
431
|
-
const accountId = await resolveAnthropicDispatchAccountId(config, anthropicSessionKey, anthropicRouteDecision, route.modelId);
|
|
432
|
-
candidate = await getAnthropicPoolAccessSnapshot(accountId);
|
|
479
|
+
const accountId = await anthropicRouting!.resolveAnthropicDispatchAccountId(config, anthropicSessionKey, anthropicRouteDecision, route.modelId);
|
|
480
|
+
candidate = await anthropicRouting!.getAnthropicPoolAccessSnapshot(accountId);
|
|
433
481
|
}
|
|
434
482
|
if (!candidate || !await applyFailoverSnapshot(candidate, requestParsed)) {
|
|
435
|
-
if (
|
|
483
|
+
if (anthropicInstance !== undefined) await anthropicRouting!.resolveAnthropicDispatchAccountId(config, anthropicSessionKey, anthropicRouteDecision, route.modelId);
|
|
436
484
|
throw new Error("OAuth account selection changed before dispatch");
|
|
437
485
|
}
|
|
438
486
|
} else {
|
|
@@ -459,6 +507,9 @@ export async function prepareResponsesTransport(
|
|
|
459
507
|
selectedAdapter: ProviderAdapter,
|
|
460
508
|
...[requestParsed, incoming, emit]: Parameters<NonNullable<ProviderAdapter["runTurn"]>>
|
|
461
509
|
): Promise<void> => {
|
|
510
|
+
const producer = options.sendBudget && "beginSpendProducer" in options.sendBudget
|
|
511
|
+
? (options.sendBudget as import("../../lib/request-execution-budget").RequestExecutionBudget).beginSpendProducer?.() : undefined;
|
|
512
|
+
try {
|
|
462
513
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
463
514
|
if (!selectionIsCurrent(adapterBindings.get(selectedAdapter))) selectedAdapter = await refreshRunTurnAdapter(requestParsed);
|
|
464
515
|
const binding = adapterBindings.get(selectedAdapter);
|
|
@@ -499,6 +550,7 @@ export async function prepareResponsesTransport(
|
|
|
499
550
|
selectedAdapter = await refreshRunTurnAdapter(requestParsed);
|
|
500
551
|
}
|
|
501
552
|
throw new Error("Account selection changed repeatedly before turn dispatch");
|
|
553
|
+
} finally { producer?.close(); }
|
|
502
554
|
};
|
|
503
555
|
const oauthDispatch = (wireRequest: AdapterRequest, requestParsed = parsed): ProviderFetchOptions["dispatchOverride"] => {
|
|
504
556
|
if (route.provider.authMode === "forward") return undefined;
|
|
@@ -509,8 +561,12 @@ export async function prepareResponsesTransport(
|
|
|
509
561
|
if (selectionIsCurrent(requestBindings.get(wireRequest))) {
|
|
510
562
|
const fetchImpl = (route.provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? execute;
|
|
511
563
|
const binding = requestBindings.get(wireRequest);
|
|
512
|
-
const snapshot =
|
|
564
|
+
const snapshot = anthropicInstance !== undefined && binding?.kind === "oauth"
|
|
513
565
|
? binding.snapshot : undefined;
|
|
566
|
+
const target = destination instanceof Request ? destination.url : String(destination);
|
|
567
|
+
if (authorizedAnthropicTarget && target !== authorizedAnthropicTarget) {
|
|
568
|
+
throw new OAuthLoginRequiredError(anthropicInstance!);
|
|
569
|
+
}
|
|
514
570
|
const writerGeneration = snapshot ? captureConfigGeneration() : 0;
|
|
515
571
|
const sentHeaders = snapshot ? new Headers(dispatchInit.headers) : undefined;
|
|
516
572
|
const ownsBearer = snapshot !== undefined
|
|
@@ -523,10 +579,23 @@ export async function prepareResponsesTransport(
|
|
|
523
579
|
// against the destination it is actually going to rather than the one this dispatch
|
|
524
580
|
// started with. Account reselection can move the upstream host, which would otherwise
|
|
525
581
|
// apply a host-scoped decision to a different host.
|
|
526
|
-
const releaseFamily = snapshot ? claimAnthropicFamilyRevalidation(snapshot.accountId, route.modelId) : () => {};
|
|
582
|
+
const releaseFamily = snapshot ? anthropicQuota!.claimAnthropicFamilyRevalidation(snapshot.accountId, route.modelId) : () => {};
|
|
527
583
|
if (!releaseFamily) throw new AnthropicAccountCooldownError(1);
|
|
528
584
|
let response: Response;
|
|
585
|
+
let physicalOwner: AnthropicPhysicalSendOwnership | null = null;
|
|
529
586
|
try {
|
|
587
|
+
requireAnthropicAdmission();
|
|
588
|
+
if (!rebindPhysicalSend(options.sendBudget, { poolId: logCtx.spendPoolId ?? route.providerName,
|
|
589
|
+
identityId: logCtx.accountLogLabel })) throw new SendBudgetExhaustedError();
|
|
590
|
+
if (snapshot) {
|
|
591
|
+
// Reserve the incarnation at this synchronous send boundary, never on return.
|
|
592
|
+
physicalOwner = captureAnthropicPhysicalSendOwnership(snapshot);
|
|
593
|
+
if (!physicalOwner || !anthropicPhysicalSendOwnershipIsCurrent(physicalOwner)) {
|
|
594
|
+
throw new OAuthLoginRequiredError(anthropicInstance!);
|
|
595
|
+
}
|
|
596
|
+
sentOAuthSnapshot = snapshot;
|
|
597
|
+
passiveQuotaWriterGeneration = writerGeneration;
|
|
598
|
+
}
|
|
530
599
|
commitKeyAttemptSend();
|
|
531
600
|
response = await sendWithConnectionPolicy(
|
|
532
601
|
fetchImpl,
|
|
@@ -538,12 +607,15 @@ export async function prepareResponsesTransport(
|
|
|
538
607
|
// Observe each physical response before retries replace it. The binding belongs to
|
|
539
608
|
// this dispatch, so a manual switch cannot file A's headers against B. Header
|
|
540
609
|
// overrides and credential replacement make ownership unprovable: skip those writes.
|
|
541
|
-
if (ownsBearer && snapshot) {
|
|
610
|
+
if (ownsBearer && snapshot && physicalOwner) {
|
|
542
611
|
try {
|
|
543
|
-
const current = getAccountCredentialWithStatus(
|
|
544
|
-
if (
|
|
545
|
-
|
|
546
|
-
|
|
612
|
+
const current = getAccountCredentialWithStatus(anthropicInstance!, snapshot.accountId);
|
|
613
|
+
if (anthropicPhysicalSendOwnershipIsCurrent(physicalOwner)
|
|
614
|
+
&& snapshot.provider === anthropicInstance && current && !current.needsReauth
|
|
615
|
+
&& current.credential.access === snapshot.accessToken
|
|
616
|
+
&& credentialGeneration(current.credential) === snapshot.generation) {
|
|
617
|
+
bindAnthropicRefusalCredentialForSend(response, physicalOwner);
|
|
618
|
+
recordAnthropicAccountQuotaFromHeadersForInstance(anthropicInstance!, snapshot.accountId, response.headers, writerGeneration, response.status, route.modelId);
|
|
547
619
|
}
|
|
548
620
|
} catch { /* best-effort observation cannot fail the response */ }
|
|
549
621
|
}
|
|
@@ -583,7 +655,7 @@ export async function prepareResponsesTransport(
|
|
|
583
655
|
throw new Error("OAuth account selection changed repeatedly before dispatch");
|
|
584
656
|
};
|
|
585
657
|
};
|
|
586
|
-
const anthropicSessionKey =
|
|
658
|
+
const anthropicSessionKey = anthropicInstance !== undefined && route.provider.authMode === "oauth"
|
|
587
659
|
? anthropicSessionKeyFromParts({
|
|
588
660
|
sessionIdHeader: sessionIdHeaderFromRequest(req.headers),
|
|
589
661
|
threadIdHeader: req.headers.get("thread-id"),
|
|
@@ -594,17 +666,17 @@ export async function prepareResponsesTransport(
|
|
|
594
666
|
: null;
|
|
595
667
|
if (route.provider.authMode === "oauth") {
|
|
596
668
|
try {
|
|
597
|
-
if (
|
|
598
|
-
const routeResult =
|
|
669
|
+
if (anthropicInstance !== undefined && anthropicRouting!.isAnthropicAccountPoolEnabled(config)) {
|
|
670
|
+
const routeResult = resolveAnthropicModelRouteForInstance(anthropicInstance, config, route.modelId);
|
|
599
671
|
if (routeResult.error) return formatErrorResponse(400, "invalid_request_error", `Invalid Anthropic model routes: ${routeResult.error}`);
|
|
600
672
|
anthropicRouteDecision = routeResult.decision;
|
|
601
|
-
const selection = resolveAnthropicAccountForSession(anthropicSessionKey, config, Date.now(), anthropicRouteDecision, route.modelId);
|
|
673
|
+
const selection = anthropicRouting!.resolveAnthropicAccountForSession(anthropicSessionKey, config, Date.now(), anthropicRouteDecision, route.modelId);
|
|
602
674
|
if (!selection.accountId) {
|
|
603
675
|
if (selection.reason === "paused") return formatErrorResponse(403, "permission_error", "Anthropic OAuth accounts are paused. Resume an account in account settings and retry.");
|
|
604
676
|
// Route names may resemble account IDs; log only the matched rule position.
|
|
605
|
-
if (anthropicRouteDecision) console.warn(`[
|
|
677
|
+
if (anthropicRouteDecision) console.warn(`[${anthropicInstance}-pool] route:#${anthropicRouteDecision.position} ${selection.reason}; answering locally`);
|
|
606
678
|
if (selection.reason === "all-cooled") {
|
|
607
|
-
const retryAfterSec = getAnthropicPoolRetryAfterSeconds(Date.now(), anthropicRouteDecision, route.modelId);
|
|
679
|
+
const retryAfterSec = anthropicRouting!.getAnthropicPoolRetryAfterSeconds(Date.now(), anthropicRouteDecision, route.modelId);
|
|
608
680
|
return formatErrorResponse(
|
|
609
681
|
429,
|
|
610
682
|
"rate_limit_error",
|
|
@@ -614,12 +686,12 @@ export async function prepareResponsesTransport(
|
|
|
614
686
|
}
|
|
615
687
|
return formatErrorResponse(401, "authentication_error", anthropicRouteDecision ? "No eligible Anthropic OAuth account for this model route" : "No eligible Anthropic OAuth account available");
|
|
616
688
|
}
|
|
617
|
-
const admitted = await commitResolvedOAuthSelection(await getAnthropicPoolAccessSnapshot(selection.accountId), true, selection.reason);
|
|
689
|
+
const admitted = await commitResolvedOAuthSelection(await anthropicRouting!.getAnthropicPoolAccessSnapshot(selection.accountId), true, selection.reason);
|
|
618
690
|
if (!admitted) return formatErrorResponse(409, "conflict_error", "OAuth account selection changed; retry the request");
|
|
619
691
|
anthropicPoolAccountId = admitted.accountId;
|
|
620
|
-
if (anthropicRouteDecision) console.info(`[
|
|
692
|
+
if (anthropicRouteDecision) console.info(`[${anthropicInstance}-pool] route:#${anthropicRouteDecision.position} ${selection.reason}`);
|
|
621
693
|
route.provider = { ...route.provider, apiKey: admitted.accessToken };
|
|
622
|
-
logCtx.provider = formatAnthropicProviderForLog(
|
|
694
|
+
logCtx.provider = formatAnthropicProviderForLog(anthropicInstance!, admitted.accountId, config);
|
|
623
695
|
} else {
|
|
624
696
|
// Prefer the account with known headroom BEFORE the first attempt. Rotation alone
|
|
625
697
|
// only reacts to a 429, so a turn could open on an account a previous probe already
|
|
@@ -664,7 +736,13 @@ export async function prepareResponsesTransport(
|
|
|
664
736
|
const failedId = route.providerName === "kiro" ? oauthSelection?.accountId : undefined;
|
|
665
737
|
const failedRow = failedId ? getAccountCredentialWithStatus("kiro", failedId) : null;
|
|
666
738
|
const failedGeneration = failedRow ? credentialGeneration(failedRow.credential) : undefined;
|
|
667
|
-
try {
|
|
739
|
+
try {
|
|
740
|
+
if (anthropicInstance === "anthropic2") {
|
|
741
|
+
const accountId = oauthSelection?.accountId;
|
|
742
|
+
if (!accountId) throw new OAuthLoginRequiredError(anthropicInstance);
|
|
743
|
+
resolved = await anthropicRouting!.getAnthropicPoolAccessSnapshot(accountId);
|
|
744
|
+
} else resolved = await getValidAccessTokenSnapshot(route.providerName);
|
|
745
|
+
}
|
|
668
746
|
catch (error) {
|
|
669
747
|
if (route.providerName !== "kiro" || !(error instanceof OAuthLoginRequiredError)
|
|
670
748
|
|| !failedId || !failedGeneration) throw error;
|
|
@@ -733,7 +811,7 @@ export async function prepareResponsesTransport(
|
|
|
733
811
|
// dropped whenever the pool flag is off, and a later 429 has no account to cool. Reactive
|
|
734
812
|
// failover needs only the id: no affinity bind, no promotion, no quota-ranked pick. Those
|
|
735
813
|
// are proactive and stay behind anthropicAccountPool.enabled.
|
|
736
|
-
if (
|
|
814
|
+
if (anthropicInstance !== undefined && anthropicRouting!.hasAnthropicFailoverQuorum()) {
|
|
737
815
|
anthropicPoolAccountId = resolved.accountId;
|
|
738
816
|
}
|
|
739
817
|
// Captured beside the account it fences, so the two can never disagree.
|
|
@@ -903,7 +981,9 @@ export async function prepareResponsesTransport(
|
|
|
903
981
|
set replayOAuthCredentialSnapshot(value: Pick<OAuthAccessSnapshot, "accountId" | "generation"> | undefined) {
|
|
904
982
|
replayOAuthCredentialSnapshot = value;
|
|
905
983
|
},
|
|
906
|
-
anthropicRouteDecision,
|
|
984
|
+
get anthropicRouteDecision(): AnthropicRouteDecision | null { return anthropicRouteDecision; },
|
|
985
|
+
get anthropicInstance() { return anthropicInstance; },
|
|
986
|
+
currentAnthropicRouteDecision,
|
|
907
987
|
get anthropicPoolAccountId(): string | null {
|
|
908
988
|
return anthropicPoolAccountId;
|
|
909
989
|
},
|
|
@@ -981,7 +1061,7 @@ export async function prepareResponsesTransport(
|
|
|
981
1061
|
adapterBindings,
|
|
982
1062
|
commitResolvedOAuthSelection,
|
|
983
1063
|
refreshResolvedOAuthSelection,
|
|
984
|
-
passiveQuotaWriterGeneration,
|
|
1064
|
+
get passiveQuotaWriterGeneration(): number { return passiveQuotaWriterGeneration; },
|
|
985
1065
|
applyFailoverSnapshot,
|
|
986
1066
|
selectionIsCurrent,
|
|
987
1067
|
resolveSelectionAdapter,
|
|
@@ -75,6 +75,7 @@ export function createResponsesEffects(
|
|
|
75
75
|
// message, and leave Codex fataling on a missing compaction item (#422).
|
|
76
76
|
const commitReasoningReplayServingRoute = (outboundHeaders?: HeadersInit): void => {
|
|
77
77
|
commitReasoningReplayServingIdentity(parsed._reasoningReplayScope);
|
|
78
|
+
if (parsed._nativeReasoningMint) parsed._nativeReasoningMint.owner = parsed._nativeReasoningBoundOwner;
|
|
78
79
|
rememberServingConversationStateIssuer(admissionState.authCtx, poolAffinityKey);
|
|
79
80
|
// History has no model namespace. Record the account that actually accepted this
|
|
80
81
|
// final attempt, after refresh/failover, rather than guessing from mutable affinity.
|
|
@@ -10,6 +10,7 @@ import { createAdapterEventQueue, preflightAdapterEvents, type AdapterEventPrefl
|
|
|
10
10
|
import {
|
|
11
11
|
bindRouteReasoningReplayScope,
|
|
12
12
|
adapterNeedsForcedContinuation,
|
|
13
|
+
adapterNeedsToolCallContinuation,
|
|
13
14
|
adapterResponseReachedServingTerminal,
|
|
14
15
|
} from "./core-replay";
|
|
15
16
|
import { noteAttemptRecoveryWithheld, sealRequestAttemptIdentity, recordAttemptCredentialSource } from "../request-log";
|
|
@@ -51,6 +52,7 @@ import { planWebSearch } from "../../web-search";
|
|
|
51
52
|
import { runTurnWebSearchInitialParsed, runTurnWebSearchLoop } from "../../web-search/run-turn-loop";
|
|
52
53
|
import { WEB_SEARCH_TOOL_NAME } from "../../web-search/synthetic-tool";
|
|
53
54
|
import { orderDevinMessagesOutput } from "../../claude/devin-output-order";
|
|
55
|
+
import { unboundPoolSpendRefusalMessage } from "../workflow-refusal";
|
|
54
56
|
|
|
55
57
|
// LOCAL PATCH (runturn-websearch): top-level fields route binding or the
|
|
56
58
|
// adapter itself may write during a turn. Iteration-local `turnParsed` objects
|
|
@@ -233,6 +235,7 @@ export async function executeResponsesRunTurn(
|
|
|
233
235
|
preacquiredSlot?: ProviderRequestSlot,
|
|
234
236
|
): Promise<void> => {
|
|
235
237
|
const attemptSeq = ++runTurnAttemptSeq;
|
|
238
|
+
if (attemptSeq === 1 && options.comboInitialSend) options.comboInitialSend.producerOwned = true;
|
|
236
239
|
let pacingSlot = preacquiredSlot;
|
|
237
240
|
const emit = (event: AdapterEvent) => {
|
|
238
241
|
options.onCompactionRecoveryAdapterEvent?.(event);
|
|
@@ -330,13 +333,14 @@ export async function executeResponsesRunTurn(
|
|
|
330
333
|
status: 429,
|
|
331
334
|
errorType: "rate_limit_error",
|
|
332
335
|
code: SEND_BUDGET_EXHAUSTED_CODE,
|
|
333
|
-
message: err.message,
|
|
336
|
+
message: unboundPoolSpendRefusalMessage(logCtx) ?? err.message,
|
|
334
337
|
}
|
|
335
338
|
: {
|
|
336
339
|
type: "error",
|
|
337
340
|
message: err instanceof Error ? err.message : String(err),
|
|
338
341
|
});
|
|
339
342
|
} finally {
|
|
343
|
+
if (attemptSeq === 1) options.comboInitialSend?.permit.release();
|
|
340
344
|
devinProducers.delete(producerAbort);
|
|
341
345
|
cleanupProducerAbort?.();
|
|
342
346
|
releaseProviderRequestSlot(pacingSlot);
|
|
@@ -790,7 +794,10 @@ export async function executeResponsesRunTurn(
|
|
|
790
794
|
parsed._rawBody,
|
|
791
795
|
response,
|
|
792
796
|
continuationStateForResponse(providerState),
|
|
793
|
-
|
|
797
|
+
{
|
|
798
|
+
...responseStateOptions(adapterNeedsForcedContinuation(transportState.adapter.name)),
|
|
799
|
+
retainForToolContinuation: adapterNeedsToolCallContinuation(transportState.adapter.name),
|
|
800
|
+
},
|
|
794
801
|
);
|
|
795
802
|
}
|
|
796
803
|
notifyResponseComplete(response);
|
|
@@ -935,7 +942,10 @@ export async function executeResponsesRunTurn(
|
|
|
935
942
|
parsed._rawBody,
|
|
936
943
|
json,
|
|
937
944
|
continuationStateForResponse(providerState),
|
|
938
|
-
|
|
945
|
+
{
|
|
946
|
+
...responseStateOptions(adapterNeedsForcedContinuation(transportState.adapter.name)),
|
|
947
|
+
retainForToolContinuation: adapterNeedsToolCallContinuation(transportState.adapter.name),
|
|
948
|
+
},
|
|
939
949
|
);
|
|
940
950
|
}
|
|
941
951
|
// #1926 gap 2: the buffered path queued its signature persists inside
|