@bitkyc08/opencodex 2.86.0 → 2.87.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/gui/dist/assets/App-ZfYbLHkB.js +58 -0
- package/gui/dist/assets/App-wT3mXqFz.css +1 -0
- package/gui/dist/assets/{Tray-DyR9yBee.js → Tray-DCd-A1az.js} +1 -1
- package/gui/dist/assets/index-CfYDMj34.js +94 -0
- package/gui/dist/assets/index-DPeB9HpV.css +1 -0
- package/gui/dist/assets/quota-summary-ChvmKGOk.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic/beta-allowlist.ts +9 -8
- package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
- package/src/adapters/anthropic/passthrough.ts +7 -23
- package/src/adapters/anthropic-progress.ts +84 -0
- package/src/adapters/anthropic.ts +108 -21
- package/src/adapters/base.ts +2 -0
- package/src/adapters/claude-cli/adapter.ts +111 -23
- package/src/adapters/claude-cli/profiles.ts +2 -1
- package/src/adapters/claude-cli/stable-replay.ts +108 -0
- package/src/adapters/claude-cli/usage-admission.ts +230 -0
- package/src/adapters/coding-agent/protocol.ts +1 -1
- package/src/adapters/coding-agent/turn.ts +18 -2
- package/src/adapters/dsh-account.ts +97 -0
- package/src/adapters/google.ts +35 -8
- package/src/adapters/openai-chat/messages.ts +4 -3
- package/src/adapters/openai-chat/passthrough.ts +8 -2
- package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
- package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
- package/src/adapters/openai-responses/passthrough.ts +57 -125
- package/src/adapters/openai-responses/request-strips.ts +25 -3
- package/src/adapters/openai-responses/transport.ts +81 -0
- package/src/adapters/qoder/adapter.ts +4 -2
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/zed.ts +26 -1
- package/src/advisor/activity.ts +55 -0
- package/src/advisor/budget.ts +62 -0
- package/src/advisor/consult.ts +4 -1
- package/src/advisor/context.ts +16 -4
- package/src/advisor/evidence-tool.ts +21 -0
- package/src/advisor/evidence.ts +117 -0
- package/src/advisor/runtime.ts +79 -31
- package/src/advisor/settings.ts +11 -2
- package/src/bridge/errors.ts +19 -1
- package/src/bridge/internal.ts +3 -1
- package/src/bridge/response-json.ts +18 -3
- package/src/bridge/sse.ts +58 -8
- package/src/bridge/terminal-refusal.ts +59 -0
- package/src/claude/desktop-3p-library.ts +32 -7
- package/src/claude/desktop-3p.ts +55 -13
- package/src/claude/desktop-first-party.ts +1 -1
- package/src/claude/desktop-picker-platform.ts +4 -0
- package/src/claude/desktop-picker.ts +15 -8
- package/src/claude/desktop-system-proxy.ts +50 -4
- package/src/claude/inbound-content-options.ts +11 -0
- package/src/claude/inbound.ts +33 -0
- package/src/claude/intercept/picker-ca-startup.ts +2 -1
- package/src/claude/intercept/picker-runtime.ts +6 -5
- package/src/claude/intercept/picker-trust-windows.ts +338 -0
- package/src/claude/intercept/picker-trust.ts +19 -0
- package/src/claude/intercept/port-policy.ts +30 -0
- package/src/claude/intercept/runtime.ts +97 -94
- package/src/claude/outbound.ts +38 -13
- package/src/cli/account-api.ts +1 -0
- package/src/cli/account-policy-dto.ts +6 -0
- package/src/cli/account-policy.ts +34 -5
- package/src/cli/account-preservation.ts +44 -0
- package/src/cli/account.ts +8 -2
- package/src/cli/advisor.ts +17 -3
- package/src/cli/capabilities-accounts.ts +20 -1
- package/src/cli/capabilities-agents-routing.ts +5 -2
- package/src/cli/capabilities-base.ts +38 -10
- package/src/cli/capabilities-observe-system.ts +63 -3
- package/src/cli/capabilities-provider-models.ts +11 -0
- package/src/cli/codex-cli-update.ts +151 -41
- package/src/cli/codex-provider.ts +44 -0
- package/src/cli/combo-input.ts +10 -1
- package/src/cli/combo-result.ts +1 -1
- package/src/cli/combo.ts +2 -1
- package/src/cli/cross-home-owner.ts +17 -14
- package/src/cli/dispatch.ts +25 -4
- package/src/cli/doctor.ts +6 -1
- package/src/cli/ensure-desktop-cold-start.ts +60 -7
- package/src/cli/help.ts +3 -2
- package/src/cli/index.ts +1 -1
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/log-history.ts +172 -0
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +72 -8
- package/src/cli/observe-stream.ts +2 -0
- package/src/cli/observe.ts +16 -4
- package/src/cli/provider.ts +27 -5
- package/src/cli/registry.ts +28 -8
- package/src/cli/runtime-api.ts +5 -3
- package/src/cli/system-command.ts +40 -8
- package/src/cli/uninstall-client-state.ts +32 -0
- package/src/cli/usage-compare.ts +309 -0
- package/src/cli/usage-model-search.ts +4 -4
- package/src/cli/usage-report.ts +2 -2
- package/src/cli/v2.ts +1 -1
- package/src/client/machine-listener.ts +1 -3
- package/src/client/runtime.ts +1 -0
- package/src/clients/client-path.ts +51 -0
- package/src/clients/config-export/contracts.ts +2 -1
- package/src/clients/config-export.ts +18 -44
- package/src/clients/gentle-shell-path.ts +87 -0
- package/src/codex/account-auto-switch.ts +2 -0
- package/src/codex/account-identity.ts +29 -0
- package/src/codex/account-label.ts +1 -1
- package/src/codex/account-lifecycle.ts +21 -5
- package/src/codex/account-preservation.ts +28 -0
- package/src/codex/account-use-remaining.ts +23 -0
- package/src/codex/app-server-processes.ts +97 -7
- package/src/codex/app-server-restart-service.ts +55 -4
- package/src/codex/auth-api/account-list.ts +4 -0
- package/src/codex/auth-api/account-pause-group.ts +6 -50
- package/src/codex/auth-api/account-preservation.ts +57 -0
- package/src/codex/auth-api/routes.ts +8 -0
- package/src/codex/auth-api/use-remaining-route.ts +36 -0
- package/src/codex/auth-api.ts +0 -1
- package/src/codex/auth-context.ts +2 -2
- package/src/codex/catalog/auto-review.ts +20 -3
- package/src/codex/catalog/build-entries.ts +9 -1
- package/src/codex/catalog/combo-member.ts +14 -5
- package/src/codex/catalog/configured-tiers.ts +1 -1
- package/src/codex/catalog/gather-capture.ts +2 -0
- package/src/codex/catalog/metadata.ts +11 -9
- package/src/codex/catalog/model-hints.ts +21 -16
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/parsing.ts +30 -86
- package/src/codex/catalog/provider-models.ts +36 -34
- package/src/codex/catalog/routed-gather.ts +12 -13
- package/src/codex/cli-install-provenance.ts +105 -17
- package/src/codex/cli-update-plan.ts +545 -0
- package/src/codex/config-write-lock.ts +23 -2
- package/src/codex/desktop-app/picker-freshness.ts +96 -0
- package/src/codex/desktop-app-restart.ts +21 -0
- package/src/codex/desktop-compatibility/installed-build.ts +24 -6
- package/src/codex/desktop-compatibility/routing-preflight.ts +1 -1
- package/src/codex/desktop-compatibility/runtime.ts +12 -3
- package/src/codex/desktop-compatibility/windows-key-protection.ts +115 -9
- package/src/codex/features.ts +85 -45
- package/src/codex/inject/history-failure.ts +27 -0
- package/src/codex/inject/restore.ts +24 -2
- package/src/codex/inject/routing-classify.ts +4 -3
- package/src/codex/inject.ts +18 -27
- package/src/codex/main-account-hard-lock.ts +30 -1
- package/src/codex/native-profile-startup.ts +1 -1
- package/src/codex/ocx-compaction-history.ts +12 -10
- package/src/codex/paths.ts +86 -1
- package/src/codex/provider-routing.ts +174 -0
- package/src/codex/refresh.ts +2 -2
- package/src/codex/routing/health-store.ts +1 -1
- package/src/codex/routing/selection.ts +4 -3
- package/src/codex/routing/thread-affinity.ts +1 -1
- package/src/codex/signed-in-identity.ts +43 -0
- package/src/codex/subagent-model-fallback.ts +1 -1
- package/src/codex/sync.ts +6 -1
- package/src/codex/user-identity.ts +16 -5
- package/src/codex/windows-local-appdata.ts +84 -0
- package/src/combos/failover.ts +6 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +46 -10
- package/src/combos/types.ts +15 -0
- package/src/config/diagnostics.ts +33 -6
- package/src/config/live-reconcile.ts +38 -2
- package/src/config/load-degrade.ts +17 -0
- package/src/config/opencode-wire-upgrade.ts +54 -0
- package/src/config/opencode-zen-upgrade.ts +52 -0
- package/src/config/owner-registry.ts +22 -17
- package/src/config/provider-validation.ts +45 -2
- package/src/config/schema/config-schema.ts +22 -0
- package/src/config/schema/leaf-validators.ts +38 -9
- package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
- package/src/config/schema/native-reasoning-retention.ts +26 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +608 -284
- package/src/grok/sync.ts +1 -1
- package/src/images/loop.ts +46 -8
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/mutation-plan.ts +1 -0
- package/src/integrations/registry.ts +8 -0
- package/src/lib/codex-restart-contract.ts +15 -0
- package/src/lib/desktop-upstream-tunnel.ts +18 -53
- package/src/lib/empty-tool-catalog.ts +62 -0
- package/src/lib/errors.ts +19 -3
- package/src/lib/gcp-adc.ts +96 -9
- package/src/lib/gcp-credential-input.ts +12 -0
- package/src/lib/lab-live-route-production.ts +5 -0
- package/src/lib/opaque-proxy-tunnel.ts +217 -0
- package/src/lib/redact.ts +2 -2
- package/src/oauth/account-quota-rank.ts +69 -2
- package/src/oauth/anthropic-account-refusal.ts +20 -2
- package/src/oauth/anthropic-oauth-definitions.ts +3 -1
- package/src/oauth/anthropic-routing.ts +1 -21
- package/src/oauth/anthropic.ts +38 -7
- package/src/oauth/callback-server.ts +27 -1
- package/src/oauth/chatgpt-device.ts +1 -1
- package/src/oauth/chatgpt-shared.ts +83 -0
- package/src/oauth/chatgpt.ts +8 -72
- package/src/oauth/dsh.ts +203 -0
- package/src/oauth/generic-account-failover.ts +33 -7
- package/src/oauth/generic-session-affinity.ts +125 -0
- package/src/oauth/index.ts +184 -109
- package/src/oauth/local-token-detect.ts +21 -1
- package/src/oauth/login-cli-errors.ts +44 -0
- package/src/oauth/login-cli.ts +69 -7
- package/src/oauth/login-flow-state.ts +371 -23
- package/src/oauth/meta-muse-errors.ts +41 -0
- package/src/oauth/meta-muse-keychain.ts +52 -0
- package/src/oauth/meta-muse.ts +51 -84
- package/src/oauth/model-discovery-auth.ts +3 -0
- package/src/oauth/pool-settings-capability.ts +4 -2
- package/src/oauth/refresh-flight-retirement.ts +48 -0
- package/src/oauth/session-affinity-key.ts +23 -0
- package/src/oauth/store-anthropic-instance.ts +9 -2
- package/src/oauth/store.ts +12 -5
- package/src/protocols/encoders/adapter-events.ts +5 -4
- package/src/protocols/encoders/messages.ts +9 -6
- package/src/protocols/provider-summary.ts +2 -1
- package/src/providers/api-key-cooldowns.ts +49 -0
- package/src/providers/api-key-resolve.ts +11 -6
- package/src/providers/api-key-response-ownership.ts +57 -0
- package/src/providers/api-key-selection.ts +31 -6
- package/src/providers/api-keys.ts +214 -3
- package/src/providers/claude-cli-usage.ts +96 -0
- package/src/providers/dsh-account-destination.ts +31 -0
- package/src/providers/dsh-account-models.ts +41 -0
- package/src/providers/gcp-credential-cleanup.ts +59 -0
- package/src/providers/key-failover.ts +54 -50
- package/src/providers/key-store.ts +7 -2
- package/src/providers/model-rename-fields.ts +3 -0
- package/src/providers/model-rename-migration.ts +2 -2
- package/src/providers/openai-tiers-destination.ts +11 -2
- package/src/providers/openai-tiers.ts +5 -12
- package/src/providers/opencode-go-transport.ts +3 -1
- package/src/providers/quota/account-cache.ts +6 -5
- package/src/providers/quota/account-row.ts +34 -0
- package/src/providers/quota/antigravity.ts +28 -7
- package/src/providers/quota/dsh-account.ts +70 -0
- package/src/providers/quota/vendor-probes-oauth.ts +1 -93
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +14 -20
- package/src/providers/registry/entries-core.ts +37 -8
- package/src/providers/registry/types.ts +1 -1
- package/src/providers/request-pacing.ts +77 -19
- package/src/providers/routed-config.ts +339 -0
- package/src/providers/service-tier.ts +2 -1
- package/src/quota/window-mapping.ts +5 -2
- package/src/responses/anthropic-progress.ts +34 -0
- package/src/responses/assistant-replay.ts +35 -0
- package/src/responses/compaction-history-framing.ts +65 -0
- package/src/responses/compaction.ts +6 -1
- package/src/responses/incomplete-reason.ts +31 -0
- package/src/responses/parser.ts +50 -5
- package/src/responses/reasoning-envelope.ts +4 -0
- package/src/responses/reasoning-replay-cache.ts +24 -2
- package/src/responses/reasoning-retention.ts +173 -0
- package/src/responses/retained-compaction.ts +46 -0
- package/src/responses/schema.ts +23 -0
- package/src/router.ts +8 -321
- package/src/routing/health.ts +37 -22
- package/src/routing/history/indexer.ts +6 -5
- package/src/routing/history/ingest.ts +6 -2
- package/src/routing/profile.ts +1 -1
- package/src/server/admission-model-scope.ts +17 -0
- package/src/server/auth-cors.ts +11 -0
- package/src/server/chat-completions.ts +7 -1
- package/src/server/chat-native-reasoning.ts +123 -0
- package/src/server/chat-native-sse.ts +110 -7
- package/src/server/chat-native.ts +76 -17
- package/src/server/claude-messages.ts +55 -414
- package/src/server/effort-policy.ts +1 -1
- package/src/server/images.ts +15 -2
- package/src/server/index/model-alias-id.ts +36 -0
- package/src/server/index/optional-listeners.ts +2 -0
- package/src/server/index/serve-options.ts +9 -1
- package/src/server/index/startup-warnings.ts +2 -0
- package/src/server/index.ts +1 -1
- package/src/server/inference/advisor-diagnostics.ts +31 -0
- package/src/server/management/advisor-routes.ts +15 -4
- package/src/server/management/claude-desktop-picker-routes.ts +1 -1
- package/src/server/management/combo-routes.ts +176 -50
- package/src/server/management/companion-routes.ts +1 -1
- package/src/server/management/config-routes.ts +75 -4
- package/src/server/management/cursor-integration-routes.ts +1 -1
- package/src/server/management/model-routes.ts +11 -6
- package/src/server/management/model-rows.ts +14 -0
- package/src/server/management/native-integration-routes.ts +2 -7
- package/src/server/management/native-reasoning-retention-routes.ts +41 -0
- package/src/server/management/oauth-account-routes.ts +87 -14
- package/src/server/management/provider-gcp-credential-routes.ts +29 -0
- package/src/server/management/provider-key-pacing-routes.ts +31 -0
- package/src/server/management/provider-overwrite-carry.ts +7 -0
- package/src/server/management/provider-routes.ts +25 -30
- package/src/server/management/route-registry.ts +10 -1
- package/src/server/management-api.ts +3 -1
- package/src/server/messages-native-tool-guard.ts +185 -0
- package/src/server/messages-native.ts +101 -21
- package/src/server/messages-shared.ts +431 -0
- package/src/server/relay.ts +1 -1
- package/src/server/request-log-terminal-status.ts +1 -1
- package/src/server/request-log.ts +6 -1
- package/src/server/responses/account-change-state.ts +8 -2
- package/src/server/responses/adapter-continuation.ts +13 -1
- package/src/server/responses/adapter-delivery.ts +19 -6
- package/src/server/responses/adapter-dispatch.ts +19 -2
- package/src/server/responses/advisor-retention.ts +117 -0
- package/src/server/responses/advisor-slot.ts +73 -41
- package/src/server/responses/codex-ws-wire.ts +15 -8
- package/src/server/responses/compact.ts +303 -125
- package/src/server/responses/compaction-recovery.ts +18 -10
- package/src/server/responses/compaction-retention.ts +61 -0
- package/src/server/responses/context-overflow.ts +11 -6
- package/src/server/responses/core-auth.ts +6 -0
- package/src/server/responses/core-codex-account.ts +11 -1
- package/src/server/responses/core-combo-failure.ts +2 -0
- package/src/server/responses/core-combo.ts +120 -36
- package/src/server/responses/core-errors.ts +3 -3
- package/src/server/responses/core-lifetime.ts +5 -2
- package/src/server/responses/core-opaque-recovery.ts +35 -0
- package/src/server/responses/core-options.ts +5 -0
- package/src/server/responses/core-pipeline.ts +141 -0
- package/src/server/responses/core-replay.ts +18 -2
- package/src/server/responses/core.ts +2 -115
- package/src/server/responses/fetch-helpers.ts +73 -19
- package/src/server/responses/main-hard-lock-routing.ts +109 -0
- package/src/server/responses/native-response-control.ts +4 -2
- package/src/server/responses/passthrough-delivery.ts +3 -1
- package/src/server/responses/passthrough-dispatch.ts +15 -13
- package/src/server/responses/request-prepare.ts +76 -12
- package/src/server/responses/request-sidecar-auth.ts +2 -2
- package/src/server/responses/request-transport.ts +104 -27
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +96 -30
- package/src/server/responses/sidecar-execution.ts +20 -2
- package/src/server/responses/terminal-guard.ts +2 -16
- package/src/service/auth-preflight.ts +71 -0
- package/src/service/cli.ts +4 -2
- package/src/service/definition.ts +97 -0
- package/src/service/guards.ts +1 -61
- package/src/service/health-sentinel-linux.ts +112 -0
- package/src/service/health-sentinel-main.ts +76 -57
- package/src/service/health.ts +5 -89
- package/src/service/launchd.ts +27 -7
- package/src/service/logging.ts +72 -9
- package/src/service/repair.ts +2 -1
- package/src/service/state.ts +7 -8
- package/src/service/systemd.ts +1 -1
- package/src/service/windows-guarded-manager.ts +2 -1
- package/src/service/windows-ops.ts +1 -1
- package/src/service/windows-scheduler.ts +2 -7
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service/windows-wscript.ts +14 -0
- package/src/service.ts +4 -2
- package/src/sidecar/auth.ts +2 -0
- package/src/types/config.ts +64 -3
- package/src/types/opencode-go.ts +61 -0
- package/src/types/opencode-zen.ts +29 -0
- package/src/types/provider.ts +32 -6
- package/src/types/request.ts +23 -2
- package/src/types/wire.ts +29 -37
- package/src/types.ts +1 -0
- package/src/update/npm-invocation.mjs +12 -2
- package/src/usage/cost.ts +48 -12
- package/src/usage/expected-prices.ts +3 -0
- package/src/usage/ledger-retention.ts +2 -1
- package/src/usage/ledger-scanner.ts +6 -5
- package/src/usage/log.ts +17 -8
- package/src/usage/summary.ts +22 -9
- package/src/usage/user-cost-overlays.ts +14 -19
- package/src/usage/user-cost-validation.ts +38 -0
- package/src/vision/eligibility.ts +13 -0
- package/src/web-search/loop.ts +55 -5
- package/src/web-search/progress-stream.ts +4 -1
- package/src/web-search/run-turn-loop.ts +9 -1
- package/gui/dist/assets/App-BjlttVLy.js +0 -58
- package/gui/dist/assets/App-CSJvmjNs.css +0 -1
- package/gui/dist/assets/index-BB6uK6tU.css +0 -1
- package/gui/dist/assets/index-BMssP4k3.js +0 -94
- package/gui/dist/assets/quota-summary-D8M1bc_R.js +0 -1
|
@@ -61,7 +61,9 @@ import {
|
|
|
61
61
|
type UpstreamSendRecovery,
|
|
62
62
|
UPSTREAM_RESET_REPLAY_REFUSED_CODE,
|
|
63
63
|
} from "../lib/upstream-retry";
|
|
64
|
+
import { distributedKeyPhysicalFetch, distributedKeyResponseOwner, recordDistributedResponseFailure } from "../providers/api-key-response-ownership";
|
|
64
65
|
import { providerApiKeySelectionIsCurrent, resolveCurrentProviderApiKeyTransport } from "../providers/api-key-selection";
|
|
66
|
+
import { RequestPacingQueueOverloadError } from "../providers/request-pacing";
|
|
65
67
|
import {
|
|
66
68
|
hasKeyPoolFailover,
|
|
67
69
|
rateLimitRetryDelayMs,
|
|
@@ -91,12 +93,14 @@ import {
|
|
|
91
93
|
resolvePassthroughBodyGuard,
|
|
92
94
|
sanitizePassthroughToolCallIds,
|
|
93
95
|
tapAnthropicSseForLog,
|
|
94
|
-
} from "./
|
|
96
|
+
} from "./messages-shared";
|
|
95
97
|
import { beginInferenceAttempt } from "./inference/attempt";
|
|
96
98
|
import { createFinalRequestLog, type FinalRequestLogMeta } from "./inference/final-log";
|
|
97
99
|
import { registerTurn, unregisterTurn } from "./lifecycle";
|
|
98
100
|
import { nativeMessagesDeclineReason, type NativeMessagesSelector } from "./messages-native-eligibility";
|
|
99
101
|
import { messagesSecondaryInstanceUnavailable } from "./messages-native-selector";
|
|
102
|
+
import { guardNativeMessagesEmptyToolCatalog, nativeMessagesClientToolName, nativeMessagesInlineToolNames } from "./messages-native-tool-guard";
|
|
103
|
+
import { UNDECLARED_TOOL_CALL_ERROR_CODE, undeclaredToolCallMessage } from "./responses-undeclared-tool-guard";
|
|
100
104
|
import {
|
|
101
105
|
nativeOAuthBindingIsCurrent,
|
|
102
106
|
NativeOAuthSelectionChangedError,
|
|
@@ -315,6 +319,8 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
315
319
|
const { req, config, logCtx, logIds, route, body, requestedModel, translatorBudget } = options;
|
|
316
320
|
const nativeInstance = configuredAnthropicInstance(config, route.providerName);
|
|
317
321
|
const requestedStream = body.stream === true;
|
|
322
|
+
const clientDeclaredEmptyToolCatalog = Array.isArray(body.tools) && body.tools.length === 0;
|
|
323
|
+
const declaredInlineTools = clientDeclaredEmptyToolCatalog ? nativeMessagesInlineToolNames(body) : undefined;
|
|
318
324
|
logCtx.inboundProtocol = "messages";
|
|
319
325
|
logCtx.model = route.modelId;
|
|
320
326
|
logCtx.provider = route.providerName;
|
|
@@ -436,8 +442,16 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
436
442
|
}
|
|
437
443
|
} else {
|
|
438
444
|
// Same pre-dispatch key preference every direct send path applies (see chat-native.ts).
|
|
439
|
-
|
|
440
|
-
|
|
445
|
+
try {
|
|
446
|
+
const proactiveKeyProvider = selectProactiveApiKeyTransport(config, route.providerName, route.provider);
|
|
447
|
+
if (proactiveKeyProvider) route.provider = proactiveKeyProvider;
|
|
448
|
+
} catch (error) {
|
|
449
|
+
cleanupAbort(); upstream.abort();
|
|
450
|
+
if (!(error instanceof RequestPacingQueueOverloadError)) throw error;
|
|
451
|
+
const refusal = fail(429, error.message, "rate_limit_error");
|
|
452
|
+
refusal.headers.set("Retry-After", String(error.retryAfterSeconds));
|
|
453
|
+
return refusal;
|
|
454
|
+
}
|
|
441
455
|
}
|
|
442
456
|
let activeProvider: OcxProviderConfig = oauthBinding ? oauthProvider(oauthBinding) : route.provider;
|
|
443
457
|
stampApiKeyAccountLabel(logCtx, route.providerName, activeProvider);
|
|
@@ -521,6 +535,15 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
521
535
|
&& nativeMessagesDeclineReason({ ...route, provider: routed }, body, config, selector) === undefined;
|
|
522
536
|
};
|
|
523
537
|
|
|
538
|
+
// Keep the actual failed wire identity if a later recovery is refused before sending.
|
|
539
|
+
// A 429 remains eligible for explicit same-key retries until that ladder is finished.
|
|
540
|
+
let pendingDistributedFailure: (() => void) | undefined;
|
|
541
|
+
let distributedResponseOwnsKey = true;
|
|
542
|
+
const settleDistributedFailure = () => {
|
|
543
|
+
const record = pendingDistributedFailure;
|
|
544
|
+
pendingDistributedFailure = undefined;
|
|
545
|
+
record?.();
|
|
546
|
+
};
|
|
524
547
|
const send = async (recovery?: "rate-limit-429" | "oauth-401" | "oauth-account-403" | "key-429" | "key-401"): Promise<Response> => {
|
|
525
548
|
const remaining = remainingTransientSends();
|
|
526
549
|
if (requestTransientPolicy && remaining <= 0) {
|
|
@@ -538,7 +561,7 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
538
561
|
providerFetch(activeProvider, undefined, {
|
|
539
562
|
providerName: route.providerName,
|
|
540
563
|
modelId: route.modelId,
|
|
541
|
-
dispatchOverride: async (_input, init, execute) => {
|
|
564
|
+
dispatchOverride: async (_input, init, execute, reacquirePacing) => {
|
|
542
565
|
if (oauthBinding) {
|
|
543
566
|
if (!nativeOAuthRouteIsCurrent(oauthBinding)) throw new NativeOAuthSelectionChangedError();
|
|
544
567
|
// The OAuth twin of the key check below: re-resolve through the same selection
|
|
@@ -555,12 +578,25 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
555
578
|
rebuildFor(oauthProvider(oauthBinding));
|
|
556
579
|
logCtx.provider = formatAnthropicProviderForLog(route.providerName, oauthBinding.snapshot.accountId, config);
|
|
557
580
|
}
|
|
558
|
-
} else
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
581
|
+
} else {
|
|
582
|
+
for (let attempt = 0; !providerApiKeySelectionIsCurrent(config, route.providerName, activeProvider); attempt++) {
|
|
583
|
+
if (attempt >= 3) throw new Error("Provider key selection changed repeatedly before native Messages dispatch");
|
|
584
|
+
let current = resolveCurrentProviderApiKeyTransport(config, route.providerName, activeProvider);
|
|
585
|
+
if (!current && activeProvider.requestPacing?.enabled
|
|
586
|
+
&& (activeProvider.requestPacing.keys || activeProvider.requestPacing.keySelection === "round-robin")) {
|
|
587
|
+
const fresh = resolveCurrentProviderApiKeyTransport(config, route.providerName, { ...activeProvider, _apiKeyAttempt: undefined });
|
|
588
|
+
if (fresh) current = selectProactiveApiKeyTransport(config, route.providerName, fresh) ?? fresh;
|
|
589
|
+
}
|
|
590
|
+
if (!current || nativeMessagesDeclineReason({ ...route, provider: current }, body, config, selector) !== undefined) {
|
|
591
|
+
throw new Error("Provider key selection is no longer available for native Messages");
|
|
592
|
+
}
|
|
593
|
+
rebuildFor(current);
|
|
594
|
+
if (current.requestPacing?.enabled
|
|
595
|
+
&& (current.requestPacing.keys || current.requestPacing.keySelection === "round-robin")) {
|
|
596
|
+
if (!reacquirePacing) throw new Error("Refreshed native Messages dispatch requires pacing readmission");
|
|
597
|
+
await reacquirePacing(current, route.modelId);
|
|
598
|
+
}
|
|
562
599
|
}
|
|
563
|
-
rebuildFor(current);
|
|
564
600
|
}
|
|
565
601
|
// The retry closure may hold a pre-reselection request: send the current one whole.
|
|
566
602
|
const wire = activeRequest;
|
|
@@ -579,6 +615,7 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
579
615
|
}
|
|
580
616
|
const releaseFamily = snapshot && oauthBinding ? anthropicModelQuotaFor(oauthBinding.instance).claimAnthropicFamilyRevalidation(snapshot.accountId, route.modelId) : () => {};
|
|
581
617
|
if (!releaseFamily) throw new AnthropicAccountCooldownError(1);
|
|
618
|
+
const selection = activeProvider._apiKeyAttempt;
|
|
582
619
|
let dispatched: Response;
|
|
583
620
|
const spendReport = createPhysicalSendReporter(physicalBudget, () => ({
|
|
584
621
|
poolId: logCtx.spendPoolId ?? route.providerName, identityId: logCtx.accountLogLabel,
|
|
@@ -599,7 +636,9 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
599
636
|
if (snapshot && !sendOwner) throw new NativeOAuthSelectionChangedError();
|
|
600
637
|
physicalSendsUsed++;
|
|
601
638
|
dispatched = await sendWithConnectionPolicy(
|
|
602
|
-
|
|
639
|
+
distributedKeyPhysicalFetch(
|
|
640
|
+
anthropicBillingPhysicalFetch((activeProvider as OcxProviderTransport).fetch ?? execute, route.providerName, activeProvider),
|
|
641
|
+
route.providerName, activeProvider, wire.url, activeProvider.apiKeyTransport === "bearer" ? "authorization" : "x-api-key"),
|
|
603
642
|
wire.url,
|
|
604
643
|
applyUpstreamRecoveryInit({ ...init, method: "POST", headers, body: wire.body }, transportRecovery),
|
|
605
644
|
{ providerName: route.providerName, provider: activeProvider },
|
|
@@ -623,6 +662,14 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
623
662
|
}
|
|
624
663
|
} catch { /* Passive observation must not fail the response. */ }
|
|
625
664
|
}
|
|
665
|
+
const ownsDistributedKey = !selection?.distributed
|
|
666
|
+
|| distributedKeyResponseOwner(dispatched, config, route.providerName) !== null;
|
|
667
|
+
distributedResponseOwnsKey = ownsDistributedKey;
|
|
668
|
+
const failureStatus = dispatched.status;
|
|
669
|
+
pendingDistributedFailure = selection?.distributed && ownsDistributedKey && (failureStatus === 401 || failureStatus === 429)
|
|
670
|
+
&& !isNonReplayableResponse(dispatched)
|
|
671
|
+
? () => { recordDistributedResponseFailure(dispatched, config, route.providerName, req.signal); }
|
|
672
|
+
: undefined;
|
|
626
673
|
if (!dispatched.ok) await recordKeyAttemptFailure(logCtx, dispatched, init.signal ?? upstream.signal);
|
|
627
674
|
return dispatched;
|
|
628
675
|
},
|
|
@@ -647,25 +694,28 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
647
694
|
let response: Response;
|
|
648
695
|
try {
|
|
649
696
|
response = await send();
|
|
650
|
-
|
|
697
|
+
let retryPolicy: ReturnType<typeof rateLimitRetryPolicyFor> | undefined;
|
|
651
698
|
let retries = 0;
|
|
652
699
|
let billingRecoveryActive = false;
|
|
653
700
|
const keySendAvailable = () => transientSendAvailable()
|
|
654
701
|
&& (!billingRecoveryActive || Math.max(physicalSendsUsed, physicalBudget.used) < physicalBudget.policy.maxTotalModelSends);
|
|
655
|
-
|
|
702
|
+
const recoveryPasses = activeProvider._apiKeyAttempt?.distributed ? activeProvider.apiKeyPool?.length ?? 1 : 1;
|
|
703
|
+
for (let pass = 0; ; pass++) {
|
|
656
704
|
const priorResponse = response;
|
|
657
705
|
// A credential-scoped 401 on a static key pool says nothing about the sibling keys.
|
|
658
|
-
while (response.status === 401 && hasKeyPoolFailover(activeProvider) && keySendAvailable()) {
|
|
706
|
+
while (response.status === 401 && distributedResponseOwnsKey && hasKeyPoolFailover(activeProvider) && keySendAvailable()) {
|
|
659
707
|
const rotated = rotateProviderTransportOn401(config, route.providerName, activeProvider, {
|
|
660
708
|
now: Date.now(),
|
|
661
709
|
attemptedKey: activeProvider.apiKey,
|
|
710
|
+
attemptedSelection: activeProvider._apiKeyAttempt,
|
|
662
711
|
});
|
|
712
|
+
pendingDistributedFailure = undefined; // Rotation already records this physical failure.
|
|
663
713
|
if (!rotated) break;
|
|
664
714
|
discard(response);
|
|
665
715
|
rebuildFor(rotated);
|
|
666
716
|
response = await send("key-401");
|
|
667
717
|
}
|
|
668
|
-
while ((response.status === 400 || response.status === 402) && hasKeyPoolFailover(activeProvider)) {
|
|
718
|
+
while ((response.status === 400 || response.status === 402) && distributedResponseOwnsKey && hasKeyPoolFailover(activeProvider)) {
|
|
669
719
|
const rotated = await rotateAnthropicBillingKeyOnResponse(response, config, route.providerName, activeProvider, { signal: upstream.signal });
|
|
670
720
|
if (!rotated) break;
|
|
671
721
|
billingRecoveryActive = true;
|
|
@@ -674,9 +724,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
674
724
|
rebuildFor(rotated);
|
|
675
725
|
response = await send("key-401");
|
|
676
726
|
}
|
|
727
|
+
if (pass === 0) retryPolicy = oauthBinding ? undefined : rateLimitRetryPolicyFor(activeProvider);
|
|
677
728
|
// A refusal this proxy synthesized for a reset replay is not a provider rate limit.
|
|
678
729
|
while (
|
|
679
730
|
response.status === 429
|
|
731
|
+
&& distributedResponseOwnsKey
|
|
680
732
|
&& !isNonReplayableResponse(response)
|
|
681
733
|
&& retryPolicy
|
|
682
734
|
&& retries < retryPolicy.attempts
|
|
@@ -691,13 +743,14 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
691
743
|
if (upstream.signal.aborted) throw upstream.signal.reason;
|
|
692
744
|
response = await send("rate-limit-429");
|
|
693
745
|
}
|
|
694
|
-
while (response.status === 429 && !isNonReplayableResponse(response) && hasKeyPoolFailover(activeProvider)) {
|
|
746
|
+
while (response.status === 429 && distributedResponseOwnsKey && !isNonReplayableResponse(response) && hasKeyPoolFailover(activeProvider)) {
|
|
695
747
|
const rotated = rotateProviderTransportOn429(config, route.providerName, activeProvider, {
|
|
696
748
|
retryAfter: response.headers.get("retry-after"),
|
|
697
749
|
now: Date.now(),
|
|
698
750
|
attemptedKey: activeProvider.apiKey,
|
|
699
751
|
attemptedSelection: activeProvider._apiKeyAttempt,
|
|
700
752
|
});
|
|
753
|
+
pendingDistributedFailure = undefined; // Rotation already records this physical failure.
|
|
701
754
|
if (!rotated) break;
|
|
702
755
|
// Rotation already recorded the cooldown; keep the terminal 429 when no send remains.
|
|
703
756
|
if (!keySendAvailable()) break;
|
|
@@ -705,13 +758,17 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
705
758
|
rebuildFor(rotated);
|
|
706
759
|
response = await send("key-429");
|
|
707
760
|
}
|
|
708
|
-
|
|
709
|
-
|
|
761
|
+
if (response === priorResponse || isNonReplayableResponse(response) || !keySendAvailable()) break;
|
|
762
|
+
// Billing class transitions share the physical-send ceiling; distributed-only
|
|
763
|
+
// transitions additionally retain their original bounded pool-pass allowance.
|
|
764
|
+
if (distributedResponseOwnsKey && (
|
|
710
765
|
(billingRecoveryActive && [401, 429].includes(response.status))
|
|
711
766
|
|| (activeProvider.adapter === "anthropic" && hasKeyPoolFailover(activeProvider) && [400, 402].includes(response.status))
|
|
712
767
|
)) continue;
|
|
713
|
-
|
|
768
|
+
if (!activeProvider._apiKeyAttempt?.distributed || !distributedResponseOwnsKey
|
|
769
|
+
|| (response.status !== 401 && response.status !== 429) || pass + 1 >= recoveryPasses) break;
|
|
714
770
|
}
|
|
771
|
+
settleDistributedFailure();
|
|
715
772
|
const oauthRetryKey = {};
|
|
716
773
|
const triedAccountIds = new Set<string>();
|
|
717
774
|
let oauthFailovers = 0;
|
|
@@ -749,7 +806,13 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
749
806
|
cleanupAbort();
|
|
750
807
|
upstream.abort();
|
|
751
808
|
if (req.signal.aborted) return fail(499, "Client cancelled request", "api_error");
|
|
809
|
+
settleDistributedFailure();
|
|
752
810
|
const sendError = error instanceof UpstreamRetryEvidenceError ? error.cause : error;
|
|
811
|
+
if (sendError instanceof RequestPacingQueueOverloadError) {
|
|
812
|
+
const refusal = fail(429, sendError.message, "rate_limit_error");
|
|
813
|
+
refusal.headers.set("Retry-After", String(sendError.retryAfterSeconds));
|
|
814
|
+
return refusal;
|
|
815
|
+
}
|
|
753
816
|
if (sendError instanceof SendBudgetExhaustedError) return fail(429, sendError.message, "send_budget_exhausted", "send_budget_exhausted");
|
|
754
817
|
if (sendError instanceof NativeMessagesSpendRefusal) {
|
|
755
818
|
const refusal = workflowRefusalResponse("workflow-spend-exhausted", logCtx);
|
|
@@ -794,15 +857,22 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
794
857
|
const renamed = activeRequest.oauthToolNames
|
|
795
858
|
? restoreOAuthToolNamesInSse(observed, activeRequest.oauthToolNames, translatorBudget)
|
|
796
859
|
: observed;
|
|
797
|
-
const
|
|
860
|
+
const echoed = echoRequestedModel(renamed, requestedModel);
|
|
861
|
+
let toolRefusal: string | undefined;
|
|
862
|
+
const source = clientDeclaredEmptyToolCatalog
|
|
863
|
+
? guardNativeMessagesEmptyToolCatalog(echoed, translatorBudget, message => {
|
|
864
|
+
toolRefusal = message;
|
|
865
|
+
logCtx.errorCode = UNDECLARED_TOOL_CALL_ERROR_CODE;
|
|
866
|
+
}, declaredInlineTools)
|
|
867
|
+
: echoed;
|
|
798
868
|
if (requestedStream) {
|
|
799
869
|
transferTurnToStream();
|
|
800
870
|
const relayed = tapAnthropicSseForLog(source, logCtx, (status, meta) => {
|
|
801
871
|
try {
|
|
802
872
|
cleanupAbort();
|
|
803
873
|
bindUsage(logCtx.usage);
|
|
804
|
-
finishLog(status,
|
|
805
|
-
if (meta.closeReason !== "terminal") upstream.abort();
|
|
874
|
+
finishLog(toolRefusal ? 502 : status, toolRefusal, toolRefusal ? { ...meta, terminalStatus: "failed" } : meta);
|
|
875
|
+
if (toolRefusal || meta.closeReason !== "terminal") upstream.abort();
|
|
806
876
|
} finally {
|
|
807
877
|
releaseStreamTurn();
|
|
808
878
|
}
|
|
@@ -833,6 +903,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
833
903
|
if (message.type === "error") {
|
|
834
904
|
const error = isRec(message.error) ? message.error : {};
|
|
835
905
|
const text = typeof error.message === "string" ? error.message : "upstream stream failed";
|
|
906
|
+
if (toolRefusal) {
|
|
907
|
+
upstream.abort();
|
|
908
|
+
finishLog(502, toolRefusal, { closeReason: "terminal", terminalStatus: "failed" });
|
|
909
|
+
return fail(502, toolRefusal, "api_error", UNDECLARED_TOOL_CALL_ERROR_CODE);
|
|
910
|
+
}
|
|
836
911
|
// The tap's own verdict (a reset, a stall, the byte cap) closes this row with the same meta
|
|
837
912
|
// as the streaming lane's row; a plain upstream error event keeps the non_stream row.
|
|
838
913
|
const tapMeta = tapState.meta;
|
|
@@ -884,6 +959,11 @@ export async function handleNativeMessages(options: HandleNativeMessagesOptions)
|
|
|
884
959
|
const message = activeRequest.oauthToolNames
|
|
885
960
|
? restoreOAuthToolNamesInMessage(parsedMessage, activeRequest.oauthToolNames)
|
|
886
961
|
: parsedMessage;
|
|
962
|
+
const undeclaredTool = clientDeclaredEmptyToolCatalog ? nativeMessagesClientToolName(message, declaredInlineTools) : undefined;
|
|
963
|
+
if (undeclaredTool !== undefined) {
|
|
964
|
+
logCtx.errorCode = UNDECLARED_TOOL_CALL_ERROR_CODE;
|
|
965
|
+
return fail(502, undeclaredToolCallMessage(undeclaredTool), "api_error", UNDECLARED_TOOL_CALL_ERROR_CODE);
|
|
966
|
+
}
|
|
887
967
|
bindUsage(anthropicUsageToOcx(isRec(message.usage) ? message.usage : undefined));
|
|
888
968
|
if (logIds) recordFirstOutput(logCtx, logIds.start);
|
|
889
969
|
try {
|