@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,4 +1,15 @@
|
|
|
1
|
+
import { CURSOR_CAPABILITIES } from "../adapters/cursor/catalog";
|
|
1
2
|
import { normalizeCursorClaudeId } from "../adapters/cursor/claude-id";
|
|
3
|
+
import { isAnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Provider key the compiled price catalogs are written under. Both Anthropic OAuth instances run
|
|
7
|
+
* the same models at the same published prices, so Pool 2 reads Pool 1's rows. Callers apply this
|
|
8
|
+
* only to the built-in catalogs; operator-supplied overlays and tiers stay keyed exactly.
|
|
9
|
+
*/
|
|
10
|
+
export function pricingFamilyProvider(provider: string): string {
|
|
11
|
+
return isAnthropicInstanceId(provider) ? "anthropic" : provider;
|
|
12
|
+
}
|
|
2
13
|
|
|
3
14
|
/**
|
|
4
15
|
* Expected-price overlay for models whose jawcode cost rows are missing or all-zero
|
|
@@ -123,13 +134,23 @@ const CURSOR_OPUS_48 = CLAUDE_OPUS_46;
|
|
|
123
134
|
// 0.1x most families use. 1M context and 128K output at one flat rate (no long-context tier).
|
|
124
135
|
const CLAUDE_OPUS_55: Cost4 = { input: 4, output: 20, cacheRead: 0.2, cacheWrite: 5 };
|
|
125
136
|
// Claude Sonnet 5.5 (claude-sonnet-5-5, released 2026-09-28): the Sonnet 5 tuple, 2 / 10, 5m cache
|
|
126
|
-
// write 2.50
|
|
127
|
-
const CLAUDE_SONNET_55: Cost4 = { input: 2, output: 10, cacheRead: 0.
|
|
137
|
+
// write 2.50; cache hits cut to 0.05x (0.10) on 2026-10-08. No fast mode or long-context tier.
|
|
138
|
+
const CLAUDE_SONNET_55: Cost4 = { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 2.5 };
|
|
139
|
+
// Haiku 5.5 (2026-10-07): <=100K prompt base tuple; every rate is 5x above 100K.
|
|
140
|
+
const CLAUDE_HAIKU_55: Cost4 = { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 };
|
|
128
141
|
const ANTHROPIC_PRICING = "https://platform.claude.com/docs/en/about-claude/pricing (official; 5m cache-write tier)";
|
|
129
142
|
const CLAUDE_OPUS_5_SOURCE = `anthropic official Claude Opus 5 ${ANTHROPIC_PRICING}`;
|
|
130
143
|
const CLAUDE_OPUS_55_SOURCE = `anthropic official Claude Opus 5.5 ${ANTHROPIC_PRICING}; cache hit = 0.05x base input`;
|
|
131
|
-
const CLAUDE_SONNET_55_SOURCE = `anthropic official Claude Sonnet 5.5 ${ANTHROPIC_PRICING}`;
|
|
132
|
-
const
|
|
144
|
+
const CLAUDE_SONNET_55_SOURCE = `anthropic official Claude Sonnet 5.5 ${ANTHROPIC_PRICING}; cache hit = 0.05x base input (2026-10-08 cut)`;
|
|
145
|
+
const CLAUDE_HAIKU_55_SOURCE = `anthropic official Claude Haiku 5.5 ${ANTHROPIC_PRICING}; >100K prompt prices every token category at 5x`;
|
|
146
|
+
const CURSOR_HAIKU_55_PRICING = "https://cursor.com/docs/models/claude-haiku-5-5 (same base and >100K rates as Anthropic)";
|
|
147
|
+
const DEVIN_HAIKU_55_SOURCE = `derived (preemptive): Devin live catalog and modelCostData do not list claude-haiku-5-5 yet; Anthropic reference price ${ANTHROPIC_PRICING}`;
|
|
148
|
+
const VENICE_55_SOURCE = "derived: Venice listing on https://models.dev/api.json (2026-10-08), 1.25x Anthropic list price";
|
|
149
|
+
// Exact lookup must cover regular effort ids as well as every spelling Cursor can emit.
|
|
150
|
+
const CURSOR_HAIKU_55_IDS = ["claude-haiku-5-5", "claude-haiku-5.5", "claude-5.5-haiku"].flatMap(base =>
|
|
151
|
+
[base, ...CURSOR_CAPABILITIES["claude-haiku-5-5"]!.variants.regular!.levels.map(level => `${base}-${level}`)],
|
|
152
|
+
);
|
|
153
|
+
const CURSOR_SONNET_55_PRICING = `https://cursor.com/docs/models/claude-sonnet-5-5 (same list rate as Anthropic; cache hit 0.05x) ${ANTHROPIC_PRICING}`;
|
|
133
154
|
const DEVIN_SONNET_55_SOURCE = `derived (preemptive): Devin's live catalog and modelCostData table do not list claude-sonnet-5-5 yet; Anthropic list price shown as estimate ${ANTHROPIC_PRICING}`;
|
|
134
155
|
const CURSOR_OPUS_55_PRICING = "https://cursor.com/docs/models/claude-opus-5-5 (Cursor Other Models pool; same list rate as Anthropic, Fast Mode billed separately)";
|
|
135
156
|
const CURSOR_OPUS_48_FAST_PRICING = "https://cursor.com/docs/models/claude-opus-4-8";
|
|
@@ -291,11 +312,26 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
291
312
|
{ provider: "anthropic-apikey", modelId: "claude-opus-5-5", cost4: CLAUDE_OPUS_55, source: CLAUDE_OPUS_55_SOURCE, verifiedAt: "2026-09-23", status: "verified" },
|
|
292
313
|
// Cursor canonicalizes every Opus 5.5 spelling (thinking/effort/fast suffixes) onto this row.
|
|
293
314
|
{ provider: "cursor", modelId: "claude-opus-5-5", cost4: CLAUDE_OPUS_55, source: CURSOR_OPUS_55_PRICING, verifiedAt: "2026-09-23", status: "verified" },
|
|
315
|
+
// Haiku 5.5: official Anthropic and Cursor rates; reseller/preemptive rows remain estimates.
|
|
316
|
+
...["anthropic", "anthropic-apikey"].map((provider): ExpectedPriceOverlay => ({
|
|
317
|
+
provider, modelId: "claude-haiku-5-5", cost4: CLAUDE_HAIKU_55,
|
|
318
|
+
source: CLAUDE_HAIKU_55_SOURCE, verifiedAt: "2026-10-08", status: "verified",
|
|
319
|
+
})),
|
|
320
|
+
...CURSOR_HAIKU_55_IDS.map((modelId): ExpectedPriceOverlay => ({
|
|
321
|
+
provider: "cursor", modelId, cost4: CLAUDE_HAIKU_55,
|
|
322
|
+
source: CURSOR_HAIKU_55_PRICING, verifiedAt: "2026-10-08", status: "verified",
|
|
323
|
+
})),
|
|
324
|
+
...["devin", "devin-cli"].map((provider): ExpectedPriceOverlay => ({
|
|
325
|
+
provider, modelId: "claude-haiku-5-5", cost4: CLAUDE_HAIKU_55,
|
|
326
|
+
source: DEVIN_HAIKU_55_SOURCE, verifiedAt: "2026-10-08", status: "verified-derived",
|
|
327
|
+
})),
|
|
328
|
+
{ provider: "venice", modelId: "claude-haiku-5-5", cost4: { input: 0.125, output: 0.625, cacheRead: 0.0125, cacheWrite: 0.15625 }, source: VENICE_55_SOURCE, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
329
|
+
{ provider: "venice", modelId: "claude-sonnet-5-5", cost4: { input: 2.5, output: 12.5, cacheRead: 0.125, cacheWrite: 3.125 }, source: VENICE_55_SOURCE, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
294
330
|
// Claude Sonnet 5.5. Same layering as Opus 5.5: the anthropic bundle row wins for the bare id,
|
|
295
331
|
// these cover account-label namespaces, and Cursor publishes the list rate on its model page.
|
|
296
|
-
{ provider: "anthropic", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CLAUDE_SONNET_55_SOURCE, verifiedAt: "2026-
|
|
297
|
-
{ provider: "anthropic-apikey", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CLAUDE_SONNET_55_SOURCE, verifiedAt: "2026-
|
|
298
|
-
{ provider: "cursor", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CURSOR_SONNET_55_PRICING, verifiedAt: "2026-
|
|
332
|
+
{ provider: "anthropic", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CLAUDE_SONNET_55_SOURCE, verifiedAt: "2026-10-08", status: "verified" },
|
|
333
|
+
{ provider: "anthropic-apikey", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CLAUDE_SONNET_55_SOURCE, verifiedAt: "2026-10-08", status: "verified" },
|
|
334
|
+
{ provider: "cursor", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: CURSOR_SONNET_55_PRICING, verifiedAt: "2026-10-08", status: "verified" },
|
|
299
335
|
// MiniMax M2.1 highspeed — published PAYG price (verified).
|
|
300
336
|
{ provider: "minimax", modelId: "MiniMax-M2.1-highspeed", cost4: MINIMAX_M21_HIGHSPEED, source: MINIMAX_PRICING, verifiedAt: "2026-07-20", status: "verified" },
|
|
301
337
|
{ provider: "minimax-cn", modelId: "MiniMax-M2.1-highspeed", cost4: MINIMAX_M21_HIGHSPEED, source: MINIMAX_PRICING, verifiedAt: "2026-07-20", status: "verified" },
|
|
@@ -371,10 +407,10 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
371
407
|
// Alias without the Antigravity "-thinking" suffix (if logs/UI ever surface it).
|
|
372
408
|
{ provider: "google-antigravity", modelId: "claude-opus-4-6", cost4: CLAUDE_OPUS_46, source: `anthropic official Claude Opus 4.6 ${ANTHROPIC_PRICING}`, verifiedAt: "2026-07-23", status: "verified" },
|
|
373
409
|
// Antigravity uses subscription quota; these are derived Anthropic reference estimates.
|
|
374
|
-
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-
|
|
375
|
-
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-low", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-
|
|
376
|
-
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-medium", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-
|
|
377
|
-
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-high", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-
|
|
410
|
+
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price (cache hit 0.05x); ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
411
|
+
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-low", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price (cache hit 0.05x); ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
412
|
+
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-medium", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price (cache hit 0.05x); ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
413
|
+
{ provider: "google-antigravity", modelId: "claude-sonnet-5-5-high", cost4: CLAUDE_SONNET_55, source: `derived: Anthropic Claude Sonnet 5.5 reference price (cache hit 0.05x); ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
378
414
|
{ provider: "google-antigravity", modelId: "claude-opus-5-5", cost4: CLAUDE_OPUS_55, source: `derived: Anthropic Claude Opus 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-03", status: "verified-derived" },
|
|
379
415
|
{ provider: "google-antigravity", modelId: "claude-opus-5-5-low", cost4: CLAUDE_OPUS_55, source: `derived: Anthropic Claude Opus 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-03", status: "verified-derived" },
|
|
380
416
|
{ provider: "google-antigravity", modelId: "claude-opus-5-5-medium", cost4: CLAUDE_OPUS_55, source: `derived: Anthropic Claude Opus 5.5 reference price; ${ANTHROPIC_PRICING}`, verifiedAt: "2026-10-03", status: "verified-derived" },
|
|
@@ -482,7 +518,7 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
482
518
|
{ provider: "devin-cli", modelId: "claude-opus-5", cost4: CLAUDE_OPUS_46, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
483
519
|
{ provider: "devin-cli", modelId: "claude-opus-5-5", cost4: CLAUDE_OPUS_55, source: `derived: live Devin catalog lists claude-opus-5-5 but Devin's modelCostData table does not yet; Anthropic list price shown as estimate ${ANTHROPIC_PRICING}`, verifiedAt: "2026-09-23", status: "verified-derived" },
|
|
484
520
|
{ provider: "devin-cli", modelId: "claude-fable-5-1", cost4: CLAUDE_FABLE_51, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
485
|
-
{ provider: "devin-cli", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: DEVIN_SONNET_55_SOURCE, verifiedAt: "2026-
|
|
521
|
+
{ provider: "devin-cli", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: DEVIN_SONNET_55_SOURCE, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
486
522
|
{ provider: "devin-cli", modelId: "claude-sonnet-5", cost4: DEVIN_SONNET_5, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
487
523
|
{ provider: "devin-cli", modelId: "glm-5-3", cost4: GLM_53, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
488
524
|
{ provider: "devin-cli", modelId: "kimi-k3", cost4: DEVIN_KIMI_K3, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
@@ -501,7 +537,7 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
501
537
|
{ provider: "devin", modelId: "claude-opus-4-8", cost4: CLAUDE_OPUS_46, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
502
538
|
{ provider: "devin", modelId: "claude-opus-5-5", cost4: CLAUDE_OPUS_55, source: `derived: live Devin catalog lists claude-opus-5-5 but Devin's modelCostData table does not yet; Anthropic list price shown as estimate ${ANTHROPIC_PRICING}`, verifiedAt: "2026-09-23", status: "verified-derived" },
|
|
503
539
|
{ provider: "devin", modelId: "claude-fable-5-1", cost4: CLAUDE_FABLE_51, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
504
|
-
{ provider: "devin", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: DEVIN_SONNET_55_SOURCE, verifiedAt: "2026-
|
|
540
|
+
{ provider: "devin", modelId: "claude-sonnet-5-5", cost4: CLAUDE_SONNET_55, source: DEVIN_SONNET_55_SOURCE, verifiedAt: "2026-10-08", status: "verified-derived" },
|
|
505
541
|
{ provider: "devin", modelId: "claude-sonnet-5", cost4: DEVIN_SONNET_5, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
506
542
|
{ provider: "devin", modelId: "glm-5-2", cost4: GLM_52, source: `enterprise list column (self-serve shows an unannounced 0 promo); ${DEVIN_PRICING}`, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
507
543
|
{ provider: "devin", modelId: "kimi-k2-7", cost4: DEVIN_KIMI_K27, source: DEVIN_PRICING, verifiedAt: "2026-09-13", status: "verified-derived" },
|
|
@@ -705,6 +741,8 @@ export interface ContextTier {
|
|
|
705
741
|
const OPENAI_LONG_CONTEXT: Cost4 = { input: 2, output: 1.5, cacheRead: 2, cacheWrite: 2 };
|
|
706
742
|
/** xAI and MiniMax double every rate uniformly past their thresholds. */
|
|
707
743
|
const UNIFORM_DOUBLE: Cost4 = { input: 2, output: 2, cacheRead: 2, cacheWrite: 2 };
|
|
744
|
+
// Haiku 5.5 reprices the whole request above 100K (official pricing, read 2026-10-08).
|
|
745
|
+
const HAIKU_55_LONG_CONTEXT: Cost4 = { input: 5, output: 5, cacheRead: 5, cacheWrite: 5 };
|
|
708
746
|
|
|
709
747
|
const OPENAI_PRICING_DOC = "https://developers.openai.com/api/docs/pricing";
|
|
710
748
|
const OPENAI_CONTEXT_MODELS = [
|
|
@@ -723,6 +761,19 @@ const OPENAI_CONTEXT_MODELS = [
|
|
|
723
761
|
];
|
|
724
762
|
|
|
725
763
|
export const CONTEXT_TIERS: readonly ContextTier[] = [
|
|
764
|
+
// Reference bands on preemptive/subscription surfaces follow their reference price, not billing.
|
|
765
|
+
...[
|
|
766
|
+
...["anthropic", "anthropic-apikey", "opencode-go", "opencode-zen", "venice", "github-copilot", "devin", "devin-cli", "claude-cli"].map(provider => [provider, "claude-haiku-5-5"]),
|
|
767
|
+
...["", "global.", "us.", "eu.", "jp.", "au."].map(prefix => ["amazon-bedrock", `${prefix}anthropic.claude-haiku-5-5`]),
|
|
768
|
+
...["openrouter", "vercel-ai-gateway", "zenmux"].map(provider => [provider, "anthropic/claude-haiku-5.5"]),
|
|
769
|
+
["cloudflare-ai-gateway", "anthropic/claude-haiku-5-5"], ["kiro", "claude-haiku-5.5"],
|
|
770
|
+
...CURSOR_HAIKU_55_IDS.map(modelId => ["cursor", modelId]),
|
|
771
|
+
].map(([provider, modelId]): ContextTier => ({
|
|
772
|
+
provider, modelId, thresholdInputTokens: 100_000, inclusive: false,
|
|
773
|
+
multiplier: HAIKU_55_LONG_CONTEXT,
|
|
774
|
+
source: provider === "cursor" ? CURSOR_HAIKU_55_PRICING : ANTHROPIC_PRICING,
|
|
775
|
+
verifiedAt: "2026-10-08",
|
|
776
|
+
})),
|
|
726
777
|
// API-reference estimates do not apply subscription-only exemptions or multipliers.
|
|
727
778
|
...["openai", "openai-apikey"].flatMap(provider =>
|
|
728
779
|
OPENAI_CONTEXT_MODELS.map((modelId): ContextTier => ({
|
|
@@ -811,7 +862,8 @@ export function findContextTier(
|
|
|
811
862
|
modelId: string,
|
|
812
863
|
tiers: readonly ContextTier[] = CONTEXT_TIERS,
|
|
813
864
|
): ContextTier | undefined {
|
|
814
|
-
|
|
865
|
+
const familyProvider = tiers === CONTEXT_TIERS ? pricingFamilyProvider(provider) : provider;
|
|
866
|
+
return tiers.find(tier => tier.provider === familyProvider && tier.modelId === modelId);
|
|
815
867
|
}
|
|
816
868
|
|
|
817
869
|
/** Whether a raw input-token count crosses the tier's published boundary. */
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { resolveAnthropicHelperSnapshot, fetchAnthropicHelper, anthropicHelperMessagesUrl } from "../sidecar/anthropic-binding";
|
|
2
|
+
import { isAnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
3
|
+
import type { OAuthAccessSnapshot } from "../oauth";
|
|
1
4
|
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
2
5
|
import { sidecarThinkingOff } from "../adapters/anthropic-model-contract";
|
|
3
6
|
import { CLAUDE_CODE_HEADERS, claudeCodeSessionId } from "../adapters/client-fingerprint";
|
|
@@ -159,8 +162,15 @@ export async function describeImageAnthropic(
|
|
|
159
162
|
if (!image.block) return { text: "", error: image.error ?? "invalid image" };
|
|
160
163
|
|
|
161
164
|
let token: string;
|
|
165
|
+
let snapshot: OAuthAccessSnapshot | undefined;
|
|
166
|
+
const capturedTarget = provider.baseUrl;
|
|
162
167
|
try {
|
|
163
|
-
|
|
168
|
+
if (config && isAnthropicInstanceId(providerName)) {
|
|
169
|
+
snapshot = await resolveAnthropicHelperSnapshot(config, providerName, settings.model);
|
|
170
|
+
token = snapshot.accessToken;
|
|
171
|
+
} else {
|
|
172
|
+
token = await getAnthropicSidecarAccessToken(providerName, settings.model, config);
|
|
173
|
+
}
|
|
164
174
|
} catch (error) {
|
|
165
175
|
return { text: "", error: `anthropic vision sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(error)}` };
|
|
166
176
|
}
|
|
@@ -195,13 +205,16 @@ export async function describeImageAnthropic(
|
|
|
195
205
|
|
|
196
206
|
// Anthropic image blocks have no detail field, but detail remains part of the cache identity.
|
|
197
207
|
void detail;
|
|
198
|
-
const
|
|
208
|
+
const url = anthropicHelperMessagesUrl(provider.baseUrl);
|
|
209
|
+
const dispatch = (target: string, init: RequestInit) => snapshot && config
|
|
210
|
+
? fetchAnthropicHelper(config, snapshot, settings.model, capturedTarget, target, init)
|
|
211
|
+
: fetch(target, init);
|
|
199
212
|
const linkedSignal = signalWithTimeout(settings.timeoutMs, abortSignal);
|
|
200
213
|
const sidecarExit = sidecarEnter("vision");
|
|
201
214
|
const startedAt = Date.now();
|
|
202
215
|
try {
|
|
203
216
|
const res = await fetchWithResetRetry(
|
|
204
|
-
recovery =>
|
|
217
|
+
recovery => dispatch(url, applyUpstreamRecoveryInit({
|
|
205
218
|
method: "POST",
|
|
206
219
|
redirect: "manual",
|
|
207
220
|
headers,
|
package/src/vision/index.ts
CHANGED
|
@@ -217,6 +217,9 @@ function descriptionIdentity(job: ImageJob, plan: VisionPlan): { key: string; pe
|
|
|
217
217
|
key: JSON.stringify([
|
|
218
218
|
plan.backend,
|
|
219
219
|
plan.settings.model,
|
|
220
|
+
// Explicit identity: the resolved pool and reasoning. Settings that only gate or bound the call
|
|
221
|
+
// (enabled, timeoutMs, maxDescriptionsPerTurn) never split the cache.
|
|
222
|
+
...(plan.backend === "anthropic" ? [plan.anthropicSidecar?.providerName ?? null, plan.settings.reasoning] : []),
|
|
220
223
|
...(plan.backend === "openai" ? [plan.settings.reasoning] : []),
|
|
221
224
|
job.detail ?? "high",
|
|
222
225
|
imageHash,
|
package/src/vision/plan.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
modelAcceptsImageInput,
|
|
12
12
|
} from "./eligibility";
|
|
13
13
|
import { normalizeVisionReasoningForModel } from "./reasoning";
|
|
14
|
-
import { resolveSidecarAuth } from "../sidecar/auth";
|
|
14
|
+
import { inheritedAnthropicInstance, resolveSidecarAuth, resolveAnthropicHelperInstance, resolveAnthropicSidecarAuth, withAnthropicHelperRefusal } from "../sidecar/auth";
|
|
15
15
|
import { DEFAULT_VISION_TIMEOUT_MS, MAX_VISION_TIMEOUT_MS, MIN_VISION_TIMEOUT_MS } from "./timeout-bounds";
|
|
16
16
|
import { carriesImages } from "./image-rewrite";
|
|
17
17
|
|
|
@@ -50,8 +50,9 @@ export interface AnthropicVisionProvider {
|
|
|
50
50
|
* First enabled Anthropic OAuth provider whose active stored account is not marked for reauth.
|
|
51
51
|
* Delegates to the shared sidecar auth module (#2188) — same predicate as web-search.
|
|
52
52
|
*/
|
|
53
|
-
export function findAnthropicVisionProvider(config: OcxConfig): AnthropicVisionProvider | undefined {
|
|
54
|
-
const
|
|
53
|
+
export function findAnthropicVisionProvider(config: OcxConfig, parentProviderName?: string): AnthropicVisionProvider | undefined {
|
|
54
|
+
const instance = resolveAnthropicHelperInstance(config, { backendFamily: "anthropic", anthropicInstance: config.visionSidecar?.anthropicInstance, parentProviderName });
|
|
55
|
+
const auth = resolveSidecarAuth(config, instance);
|
|
55
56
|
if (!auth.isAnthropicAuth || !auth.anthropicProviderName || !auth.anthropicProvider) return undefined;
|
|
56
57
|
return { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider, config };
|
|
57
58
|
}
|
|
@@ -68,6 +69,16 @@ export function resolveVisionBackend(
|
|
|
68
69
|
return anthropicSidecar ? "anthropic" : "openai";
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/** Existing family preference, with a builtin parent contributing its own auth availability. */
|
|
73
|
+
function preferredVisionBackend(config: OcxConfig, parentProviderName?: string): "openai" | "anthropic" {
|
|
74
|
+
const cfg = config.visionSidecar ?? {};
|
|
75
|
+
const requested = cfg.anthropicInstance ?? inheritedAnthropicInstance(config, parentProviderName);
|
|
76
|
+
const exact = requested ? resolveAnthropicSidecarAuth(config, requested) : undefined;
|
|
77
|
+
const legacy = findAnthropicVisionProvider({ ...config, visionSidecar: { ...cfg, anthropicInstance: undefined } });
|
|
78
|
+
return resolveVisionBackend(cfg.backend, exact
|
|
79
|
+
? { providerName: exact.anthropicProviderName, provider: exact.anthropicProvider, config } : legacy);
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
/** Native model used by the OpenAI vision helper, including its bounded default. */
|
|
72
83
|
export function resolveOpenAiVisionModel(config: Pick<OcxConfig, "visionSidecar">): string {
|
|
73
84
|
const configured = config.visionSidecar?.model;
|
|
@@ -170,7 +181,7 @@ export function shouldResolveOpenAiVisionSidecar(
|
|
|
170
181
|
const cfg = config.visionSidecar ?? {};
|
|
171
182
|
if (cfg.enabled === false) return false;
|
|
172
183
|
if (usableRoutedVisionModel(config)) return false;
|
|
173
|
-
return
|
|
184
|
+
return preferredVisionBackend(config, providerName) === "openai";
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
export interface VisionPlan {
|
|
@@ -241,8 +252,10 @@ export function planVisionSidecar(
|
|
|
241
252
|
}
|
|
242
253
|
// A non-dispatchable routed configuration keeps the legacy backend fallback below.
|
|
243
254
|
|
|
244
|
-
const
|
|
245
|
-
|
|
255
|
+
const backend = preferredVisionBackend(config, options.providerName);
|
|
256
|
+
// An unavailable selected pool degrades to "no plan" (images stripped); it never fails the request.
|
|
257
|
+
const anthropicSidecar = backend === "anthropic"
|
|
258
|
+
? withAnthropicHelperRefusal("vision", () => findAnthropicVisionProvider(config, options.providerName)) : undefined;
|
|
246
259
|
// A namespaced routed model must never reach the forward/OAuth executors
|
|
247
260
|
// (they POST the string verbatim); the effective-model resolver falls back
|
|
248
261
|
// to each side's default in that case.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AnthropicHelperUnavailableError } from "../sidecar/auth";
|
|
1
2
|
/**
|
|
2
3
|
* Serve Codex's built-in `/v1/alpha/search` when no ChatGPT forward provider exists.
|
|
3
4
|
*
|
|
@@ -101,7 +102,12 @@ export function resolveAlphaSearchSidecar(config: OcxConfig): AlphaSearchSidecar
|
|
|
101
102
|
if (backend === "openai") return { status: "unconfigured" };
|
|
102
103
|
switch (backend) {
|
|
103
104
|
case "anthropic": {
|
|
104
|
-
|
|
105
|
+
let found;
|
|
106
|
+
try { found = findAnthropicSidecarProvider(config); }
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error instanceof AnthropicHelperUnavailableError) return { status: "missing-credential", backend };
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
105
111
|
return found
|
|
106
112
|
? { status: "ready", sidecar: { backend, providerName: found.providerName, provider: found.provider, config } }
|
|
107
113
|
: { status: "missing-credential", backend };
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { resolveAnthropicHelperSnapshot, fetchAnthropicHelper, anthropicHelperMessagesUrl } from "../sidecar/anthropic-binding";
|
|
2
|
+
import { isAnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
3
|
+
import type { OAuthAccessSnapshot } from "../oauth";
|
|
1
4
|
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
2
5
|
import { publicOAuthAuthenticationErrorMessage } from "../oauth";
|
|
3
6
|
import { getAnthropicSidecarAccessToken } from "../oauth/anthropic-routing";
|
|
@@ -167,11 +170,17 @@ export async function runAnthropicWebSearch(
|
|
|
167
170
|
abortSignal?: AbortSignal,
|
|
168
171
|
config?: OcxConfig,
|
|
169
172
|
): Promise<SidecarOutcome> {
|
|
170
|
-
const
|
|
171
|
-
const url = `${base}/v1/messages`;
|
|
173
|
+
const url = anthropicHelperMessagesUrl(provider.baseUrl);
|
|
172
174
|
let token: string;
|
|
175
|
+
let snapshot: OAuthAccessSnapshot | undefined;
|
|
176
|
+
const capturedTarget = provider.baseUrl;
|
|
173
177
|
try {
|
|
174
|
-
|
|
178
|
+
if (config && isAnthropicInstanceId(providerName)) {
|
|
179
|
+
snapshot = await resolveAnthropicHelperSnapshot(config, providerName, settings.model);
|
|
180
|
+
token = snapshot.accessToken;
|
|
181
|
+
} else {
|
|
182
|
+
token = await getAnthropicSidecarAccessToken(providerName, settings.model, config);
|
|
183
|
+
}
|
|
175
184
|
} catch (e) {
|
|
176
185
|
return { text: "", sources: [], error: `anthropic sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(e)}` };
|
|
177
186
|
}
|
|
@@ -205,6 +214,9 @@ export async function runAnthropicWebSearch(
|
|
|
205
214
|
stream: true,
|
|
206
215
|
};
|
|
207
216
|
|
|
217
|
+
const dispatch = (target: string, init: RequestInit) => snapshot && config
|
|
218
|
+
? fetchAnthropicHelper(config, snapshot, settings.model, capturedTarget, target, init)
|
|
219
|
+
: fetch(target, init);
|
|
208
220
|
const linkedSignal = signalWithTimeout(settings.timeoutMs, abortSignal);
|
|
209
221
|
const sidecarExit = sidecarEnter("web-search");
|
|
210
222
|
const t0 = Date.now();
|
|
@@ -212,7 +224,7 @@ export async function runAnthropicWebSearch(
|
|
|
212
224
|
const res = await fetchWithResetRetry(
|
|
213
225
|
// The replay needs `keepalive: false` to leave the half-closed pooled socket; Bun has
|
|
214
226
|
// ignored a bare `Connection: close` (oven-sh/bun#20492).
|
|
215
|
-
recovery =>
|
|
227
|
+
recovery => dispatch(url, applyUpstreamRecoveryInit({
|
|
216
228
|
method: "POST",
|
|
217
229
|
redirect: "manual",
|
|
218
230
|
headers,
|
package/src/web-search/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { CodexAuthPolicyConfig } from "../codex/auth-context";
|
|
|
6
6
|
import { isCodexReserveRequestEligible } from "../codex/loopback-target";
|
|
7
7
|
import type { DataPlaneAdmission } from "../server/auth-cors";
|
|
8
8
|
import type { ResolvedOpenAiForwardSidecar } from "../providers/openai-sidecar";
|
|
9
|
-
import { resolveSidecarAuth } from "../sidecar/auth";
|
|
9
|
+
import { resolveSidecarAuth, resolveAnthropicHelperInstance, withAnthropicHelperRefusal } from "../sidecar/auth";
|
|
10
10
|
import { validateXaiSearchOptions, type XaiSearchOptions } from "./xai-executor";
|
|
11
11
|
import type { OcxWebSearchSidecarConfig } from "../types";
|
|
12
12
|
import { DEFAULT_STALL_TIMEOUT_SEC } from "../stall-timeout";
|
|
@@ -168,11 +168,15 @@ export function planWebSearch(
|
|
|
168
168
|
const connectTimeoutMs = config.connectTimeoutMs ?? 200_000;
|
|
169
169
|
// Shared auth state (#2188): presence only — backend PREFERENCE stays with
|
|
170
170
|
// resolveSidecarBackend's explicit-or-openai contract.
|
|
171
|
-
const
|
|
171
|
+
const backend = resolveSidecarBackend(cfg.backend);
|
|
172
|
+
// Only the anthropic backend can be refused; an unavailable selected pool means no plan, so the
|
|
173
|
+
// main request takes the normal path instead of failing or borrowing another pool.
|
|
174
|
+
const auth = withAnthropicHelperRefusal("web-search", () => resolveSidecarAuth(config, resolveAnthropicHelperInstance(config,
|
|
175
|
+
{ backendFamily: backend, anthropicInstance: cfg.anthropicInstance, parentProviderName: options.providerName })));
|
|
176
|
+
if (!auth) return undefined;
|
|
172
177
|
const anthropicSidecar = auth.isAnthropicAuth && auth.anthropicProviderName && auth.anthropicProvider
|
|
173
178
|
? { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider, config }
|
|
174
179
|
: undefined;
|
|
175
|
-
const backend = resolveSidecarBackend(cfg.backend);
|
|
176
180
|
const maxSearches = cfg.maxSearchesPerTurn ?? DEFAULT_MAX_SEARCHES;
|
|
177
181
|
const stallTimeoutSec = webSearchStallTimeoutSec(
|
|
178
182
|
config.stallTimeoutSec,
|
package/src/web-search/loop.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "../adapters/base";
|
|
2
2
|
import type { AdapterEvent, OcxConfig, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxProviderOpaqueToolCallMetadata, OcxThinkingContent, OcxUsage, RateLimitRetryPolicy } from "../types";
|
|
3
3
|
import { namespacedToolName, toolChoiceToolPredicate } from "../types";
|
|
4
|
+
import { isAnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
4
5
|
import { cloneProviderOpaqueToolCallMetadata } from "../responses/provider-opaque-metadata";
|
|
5
6
|
import type { AttemptRecoveryKind } from "../usage/log";
|
|
6
7
|
import { isTruncatedStopReason } from "../responses/truncated-stop-reason";
|
|
@@ -322,7 +323,7 @@ export interface WebSearchLoopDeps {
|
|
|
322
323
|
/** Observe the exact adapter request selected for each routed-model iteration. */
|
|
323
324
|
onRequestBuilt?: (request: AdapterRequest) => void;
|
|
324
325
|
/** Request-scoped executor retains the core's selection binding across loop retries. */
|
|
325
|
-
fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest) => typeof globalThis.fetch;
|
|
326
|
+
fetchForRequest?: (request: AdapterRequest, parsed: OcxParsedRequest, adapter: ProviderAdapter) => typeof globalThis.fetch;
|
|
326
327
|
/** Called before each routed-model dispatch in the loop, for attempt telemetry. Same-target 429 replays pass the `rate-limit-429` recovery kind. */
|
|
327
328
|
onAttemptSend?: (recovery?: AttemptRecoveryKind) => void;
|
|
328
329
|
/**
|
|
@@ -353,6 +354,8 @@ export interface WebSearchLoopDeps {
|
|
|
353
354
|
| { adapter: ProviderAdapter; recoveryKind: AttemptRecoveryKind }
|
|
354
355
|
| null
|
|
355
356
|
| Promise<{ adapter: ProviderAdapter; recoveryKind: AttemptRecoveryKind } | null>;
|
|
357
|
+
/** Release a credential-hop permit if this iteration ended before the adapter used it. */
|
|
358
|
+
onIterationEnd?: () => void;
|
|
356
359
|
/** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */
|
|
357
360
|
retryOn429Policy?: Required<RateLimitRetryPolicy> | null;
|
|
358
361
|
/** Called only when the final bridged Responses stream reaches completed or incomplete. */
|
|
@@ -491,7 +494,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
491
494
|
cachedRequest = request;
|
|
492
495
|
cachedAdapter = requestAdapter;
|
|
493
496
|
}
|
|
494
|
-
const requestFetch = headerDeadline.pacedFetch(deps.fetchForRequest?.(request, iterParsed) ?? routedProviderFetch);
|
|
497
|
+
const requestFetch = headerDeadline.pacedFetch(deps.fetchForRequest?.(request, iterParsed, requestAdapter) ?? routedProviderFetch);
|
|
495
498
|
let response: Response;
|
|
496
499
|
try {
|
|
497
500
|
if (requestAdapter.fetchResponse) {
|
|
@@ -501,7 +504,10 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
501
504
|
timeoutMs: connectTimeoutMs,
|
|
502
505
|
returnRawErrors: true,
|
|
503
506
|
stream: true,
|
|
507
|
+
sendBudget: deps.incomingMeta.sendBudget,
|
|
508
|
+
onPhysicalSend: deps.incomingMeta.onPhysicalSend,
|
|
504
509
|
executor: requestFetch,
|
|
510
|
+
onRecoveryWithheld: deps.incomingMeta.onRecoveryWithheld,
|
|
505
511
|
});
|
|
506
512
|
} else {
|
|
507
513
|
response = await fetchWithResetRetry(
|
|
@@ -571,18 +577,36 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
571
577
|
// 429 key-failover parity with the normal routed path: rotate pool keys until one responds
|
|
572
578
|
// or the pool is exhausted (deps.on429 returns null — cooldown map guarantees termination).
|
|
573
579
|
while ((prepared.response.status === 429
|
|
574
|
-
|| (prepared.response.status ===
|
|
580
|
+
|| (prepared.response.status === 401 && isAnthropicInstanceId(deps.incomingMeta?.providerName)
|
|
581
|
+
&& !accountRefusalOutputStarted)
|
|
582
|
+
|| (prepared.response.status === 403
|
|
583
|
+
&& (isAnthropicInstanceId(deps.incomingMeta?.providerName) || deps.incomingMeta?.providerName === "google-antigravity")
|
|
584
|
+
&& !accountRefusalOutputStarted)
|
|
575
585
|
|| (iterParsed._kiroAuthContext && (prepared.response.status === 400 || prepared.response.status === 403))) && deps.on429) {
|
|
576
586
|
const rotated = await deps.on429(prepared.response.headers.get("retry-after"), prepared.response.headers,
|
|
577
587
|
iterParsed, prepared.response);
|
|
578
588
|
if (!rotated) break;
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
589
|
+
const retainRefusal = prepared.response.status === 403
|
|
590
|
+
&& deps.incomingMeta?.providerName === "google-antigravity" && rotated.recoveryKind === "oauth-account-403";
|
|
591
|
+
// Keep the bounded refusal readable until the sibling actually returns headers.
|
|
592
|
+
// Other rotation paths retain their existing cancellation boundary.
|
|
593
|
+
if (!retainRefusal) {
|
|
594
|
+
try { void prepared.response.body?.cancel().catch(() => {}); } catch { /* already closed */ }
|
|
595
|
+
}
|
|
582
596
|
adapter = rotated.adapter;
|
|
583
597
|
// Stall-watchdog seam between bounded retry fetches (audit 011 B3).
|
|
584
598
|
yield { type: "heartbeat" };
|
|
585
|
-
|
|
599
|
+
let replacement: IterationResponse;
|
|
600
|
+
try {
|
|
601
|
+
replacement = await fetchOnce(adapter, rotated.recoveryKind);
|
|
602
|
+
} catch (error) {
|
|
603
|
+
if (!retainRefusal || signal.aborted || headerDeadline.didExpire() || isTranslatorBudgetExceededError(error)) throw error;
|
|
604
|
+
break; // Format the original 403 safely; replacement diagnostics are not client errors.
|
|
605
|
+
}
|
|
606
|
+
if (retainRefusal) {
|
|
607
|
+
try { void prepared.response.body?.cancel().catch(() => {}); } catch { /* already closed */ }
|
|
608
|
+
}
|
|
609
|
+
prepared = replacement;
|
|
586
610
|
}
|
|
587
611
|
|
|
588
612
|
// Final headers have arrived. Clear only the deadline timer before ANY body read.
|
|
@@ -623,6 +647,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
623
647
|
throw new LoopError(502, `Provider unreachable: ${error instanceof Error ? error.message : String(error)}`);
|
|
624
648
|
} finally {
|
|
625
649
|
headerDeadline.clear();
|
|
650
|
+
deps.onIterationEnd?.();
|
|
626
651
|
}
|
|
627
652
|
};
|
|
628
653
|
|
|
@@ -76,6 +76,7 @@ import {
|
|
|
76
76
|
import { providerDestinationConfigError } from "../lib/destination-policy";
|
|
77
77
|
import { redactSecretString } from "../lib/redact";
|
|
78
78
|
import { rememberBridgeSearchReplay } from "../responses/bridge-search-replay-cache";
|
|
79
|
+
import { withAnthropicHelperRefusal } from "../sidecar/auth";
|
|
79
80
|
|
|
80
81
|
/** Canonical Ollama Cloud origin. The only origin the "ollama" backend derives on its own. */
|
|
81
82
|
export const OLLAMA_CLOUD_ORIGIN = "https://ollama.com";
|
|
@@ -246,12 +247,14 @@ export function resolvePassthroughWebSearchBridgeAuth(
|
|
|
246
247
|
backend: ProviderWebSearchBridgeBackend | undefined,
|
|
247
248
|
config: OcxConfig,
|
|
248
249
|
openAiSidecar?: ResolvedOpenAiForwardSidecar,
|
|
250
|
+
parentProviderName?: string,
|
|
249
251
|
): PassthroughWebSearchBridgeAuth {
|
|
250
252
|
switch (backend) {
|
|
251
253
|
case "openai":
|
|
252
254
|
return openAiSidecar ? { openAiSidecar } : {};
|
|
253
255
|
case "anthropic": {
|
|
254
|
-
|
|
256
|
+
// An unavailable selected pool leaves the bridge disarmed; it never fails the passthrough turn.
|
|
257
|
+
const anthropic = withAnthropicHelperRefusal("web-search", () => findAnthropicSidecarProvider(config, parentProviderName));
|
|
255
258
|
return anthropic ? { anthropic } : {};
|
|
256
259
|
}
|
|
257
260
|
case "xai": {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* evaluating when the bridge asks for these names).
|
|
6
6
|
*/
|
|
7
7
|
import type { OcxConfig, OcxProviderConfig, OcxWebSearchSidecarConfig } from "../types";
|
|
8
|
-
import { resolveSidecarAuth } from "../sidecar/auth";
|
|
8
|
+
import { resolveSidecarAuth, resolveAnthropicHelperInstance } from "../sidecar/auth";
|
|
9
9
|
import { getAccountSet } from "../oauth/store";
|
|
10
10
|
import type { XaiSearchOptions } from "./xai-executor";
|
|
11
11
|
|
|
@@ -46,8 +46,9 @@ export interface AnthropicSidecarProvider {
|
|
|
46
46
|
* Delegates to the shared sidecar auth module (#2188) so web-search and vision
|
|
47
47
|
* cannot drift on what "Anthropic auth present" means.
|
|
48
48
|
*/
|
|
49
|
-
export function findAnthropicSidecarProvider(config: OcxConfig): AnthropicSidecarProvider | undefined {
|
|
50
|
-
const
|
|
49
|
+
export function findAnthropicSidecarProvider(config: OcxConfig, parentProviderName?: string): AnthropicSidecarProvider | undefined {
|
|
50
|
+
const instance = resolveAnthropicHelperInstance(config, { backendFamily: "anthropic", anthropicInstance: config.webSearchSidecar?.anthropicInstance, parentProviderName });
|
|
51
|
+
const auth = resolveSidecarAuth(config, instance);
|
|
51
52
|
if (!auth.isAnthropicAuth || !auth.anthropicProviderName || !auth.anthropicProvider) return undefined;
|
|
52
53
|
return { providerName: auth.anthropicProviderName, provider: auth.anthropicProvider, config };
|
|
53
54
|
}
|