@bitkyc08/opencodex 2.79.0 → 2.81.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/gui/dist/assets/App-7yhoys8a.js +54 -0
- package/gui/dist/assets/Tray-EwAOsP0S.js +1 -0
- package/gui/dist/assets/index-RsoaAxXY.js +94 -0
- package/gui/dist/assets/quota-summary-D2lN8tDm.js +1 -0
- package/gui/dist/index.html +1 -1
- 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 +7 -2
- 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/cursor/live-transport.ts +5 -3
- package/src/adapters/cursor/native-exec-fs.ts +12 -9
- package/src/adapters/cursor/native-exec.ts +13 -5
- package/src/adapters/cursor/protobuf-request.ts +13 -7
- package/src/adapters/cursor/request-builder.ts +23 -10
- package/src/adapters/cursor/tool-definitions.ts +9 -6
- package/src/adapters/cursor/tool-guidance.ts +29 -8
- package/src/adapters/cursor/tool-naming.ts +40 -7
- package/src/adapters/cursor/tool-wording.ts +46 -0
- package/src/adapters/cursor.ts +3 -0
- package/src/adapters/devin/live-models.ts +2 -0
- package/src/adapters/devin.ts +25 -11
- package/src/adapters/kiro-retry.ts +9 -4
- package/src/adapters/openai-chat/messages.ts +7 -4
- 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/inbound-cache-stabilize.ts +4 -9
- package/src/claude/inbound.ts +10 -0
- package/src/claude/intercept/model-bindings.ts +1 -0
- package/src/claude/intercept/picker-listener.ts +71 -4
- 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/capabilities-accounts.ts +2 -2
- package/src/cli/capabilities-agents-routing.ts +24 -0
- package/src/cli/capabilities-integrations.ts +16 -0
- package/src/cli/codex-shim-autorestore.ts +3 -0
- package/src/cli/dispatch.ts +10 -1
- package/src/cli/help.ts +4 -1
- package/src/cli/index.ts +11 -5
- package/src/cli/integration-plan-dto.ts +1 -0
- package/src/cli/integration-preview.ts +8 -1
- package/src/cli/integrations.ts +32 -3
- 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/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/codex/auth-api/account-list.ts +11 -3
- 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 +1 -0
- package/src/codex/autostart-health.ts +3 -3
- package/src/codex/catalog/auto-review.ts +13 -6
- package/src/codex/catalog/build-entries.ts +15 -7
- package/src/codex/catalog/control-plane.ts +45 -0
- package/src/codex/catalog/effort.ts +11 -1
- package/src/codex/catalog/gather-capture.ts +5 -3
- package/src/codex/catalog/parsing.ts +2 -1
- package/src/codex/catalog/provider-models.ts +15 -9
- package/src/codex/control-plane-models.ts +6 -0
- package/src/codex/journal.ts +36 -5
- package/src/codex/shim-overlay.ts +9 -1
- package/src/combos/jev-decision-contract.ts +25 -2
- package/src/combos/jev.ts +6 -3
- package/src/combos/types.ts +1 -1
- package/src/config/diagnostics.ts +27 -16
- package/src/config/load-degrade.ts +34 -0
- package/src/config/schema/anthropic-account-pool.ts +143 -0
- package/src/config/schema/config-schema.ts +7 -1
- package/src/config/schema/leaf-validators.ts +4 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +347 -199
- package/src/generated/model-metadata.ts +5 -4
- package/src/images/loop.ts +2 -1
- package/src/integrations/catalog-refresh.ts +1 -1
- 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 +8 -2
- package/src/lib/lab-live-route-production.ts +9 -1
- package/src/lib/request-execution-budget.ts +236 -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/upstream-retry.ts +17 -5
- 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 +51 -17
- 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/generic-account-failover.ts +3 -1
- package/src/oauth/health.ts +8 -6
- package/src/oauth/index.ts +90 -173
- 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 +67 -9
- 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/derive.ts +2 -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-oauth.ts +46 -14
- package/src/providers/quota.ts +22 -32
- 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/spill-store.ts +5 -1
- package/src/responses/state/metrics.ts +87 -0
- package/src/responses/state/snapshot-codec.ts +6 -0
- package/src/responses/state/spill-queue.ts +1 -0
- package/src/responses/state/unforced-store-false.ts +55 -0
- package/src/responses/state.ts +50 -66
- 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/chat-completions.ts +6 -1
- package/src/server/chat-native.ts +45 -25
- package/src/server/claude-messages.ts +16 -2
- package/src/server/gui-static.ts +38 -4
- package/src/server/index/spend-ledger-lifecycle.ts +10 -4
- package/src/server/index.ts +16 -16
- package/src/server/inference/context.ts +1 -1
- package/src/server/lifecycle.ts +1 -1
- package/src/server/management/agent-settings-routes.ts +30 -6
- 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/config-routes.ts +27 -7
- 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/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 +86 -41
- package/src/server/messages-native-scope.ts +4 -1
- package/src/server/messages-native-selector.ts +39 -0
- package/src/server/messages-native.ts +84 -25
- package/src/server/request-log.ts +5 -0
- package/src/server/responses/adapter-continuation.ts +29 -17
- package/src/server/responses/adapter-dispatch.ts +47 -17
- package/src/server/responses/antigravity-validation-refusal.ts +20 -6
- package/src/server/responses/combo-requested-effort.ts +14 -0
- package/src/server/responses/compact.ts +25 -8
- package/src/server/responses/compaction-recovery.ts +1 -1
- package/src/server/responses/core-combo-native.ts +4 -1
- package/src/server/responses/core-combo.ts +21 -18
- package/src/server/responses/core-normalize.ts +1 -0
- package/src/server/responses/core-options.ts +3 -1
- package/src/server/responses/core-replay.ts +5 -0
- package/src/server/responses/passthrough-delivery.ts +7 -3
- package/src/server/responses/passthrough-dispatch.ts +21 -8
- package/src/server/responses/request-prepare.ts +37 -5
- package/src/server/responses/request-send-budget.ts +74 -37
- package/src/server/responses/request-spend.ts +325 -33
- package/src/server/responses/request-transport.ts +132 -52
- package/src/server/responses/run-turn-execution.ts +11 -3
- package/src/server/responses/sidecar-execution.ts +96 -14
- package/src/server/responses-undeclared-tool-guard.ts +5 -1
- package/src/server/workflow-refusal.ts +30 -0
- package/src/service/desktop-startup.ts +100 -3
- package/src/service/ownership-mutation-lease.d.mts +1 -1
- package/src/service/ownership-mutation-lease.mjs +5 -7
- package/src/sidecar/anthropic-binding.ts +79 -0
- package/src/sidecar/auth.ts +76 -2
- package/src/types/anthropic-account-pool.ts +33 -0
- package/src/types/config.ts +12 -28
- package/src/types/provider.ts +5 -0
- package/src/types/tools.ts +7 -0
- package/src/types.ts +4 -0
- 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/header-deadline.ts +67 -0
- package/src/web-search/index.ts +7 -3
- package/src/web-search/loop.ts +32 -10
- package/src/web-search/passthrough-bridge.ts +4 -1
- package/src/web-search/sidecar-providers.ts +4 -3
- package/gui/dist/assets/App-BOUa-ek3.js +0 -54
- package/gui/dist/assets/Tray-DUtzB4zF.js +0 -1
- package/gui/dist/assets/index-DwHNDF4s.js +0 -94
- package/gui/dist/assets/quota-summary-BuL4WIBo.js +0 -1
package/src/sidecar/auth.ts
CHANGED
|
@@ -17,6 +17,73 @@ import { OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers";
|
|
|
17
17
|
import { isCodexAccountUsable } from "../codex/account-usability";
|
|
18
18
|
import { MAIN_CODEX_ACCOUNT_ID, isSelectableCodexPoolAccount } from "../codex/account-id";
|
|
19
19
|
import { getAccountSet } from "../oauth/store";
|
|
20
|
+
import { configuredAnthropicInstance, type AnthropicInstanceId } from "../providers/anthropic-instance";
|
|
21
|
+
import { isAnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The parent request's pool for an inheriting helper. A missing or disabled row keeps the parent's
|
|
25
|
+
* identity, so a pool removed mid-request refuses instead of discovering another pool; only a present
|
|
26
|
+
* custom row that is not the builtin instance (an unmarked custom `anthropic2`) stops inheritance.
|
|
27
|
+
*/
|
|
28
|
+
export function inheritedAnthropicInstance(config: OcxConfig, parentProviderName: string | undefined): AnthropicInstanceId | undefined {
|
|
29
|
+
if (!isAnthropicInstanceId(parentProviderName)) return undefined;
|
|
30
|
+
const row = config.providers?.[parentProviderName];
|
|
31
|
+
if (!row || row.disabled === true) return parentProviderName;
|
|
32
|
+
return configuredAnthropicInstance(config, parentProviderName);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class AnthropicHelperUnavailableError extends Error {
|
|
36
|
+
readonly code = "anthropic_helper_unavailable";
|
|
37
|
+
constructor(readonly instance: AnthropicInstanceId) {
|
|
38
|
+
super(`The selected ${instance} helper account pool is unavailable`);
|
|
39
|
+
this.name = "AnthropicHelperUnavailableError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export type AnthropicHelperContext = {
|
|
43
|
+
backendFamily: string;
|
|
44
|
+
anthropicInstance?: AnthropicInstanceId;
|
|
45
|
+
parentProviderName?: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Availability of one selected pool: the configured builtin row plus at least one stored account the
|
|
50
|
+
* pool could select. Which account actually sends (model route, cooldown, manual choice) is decided
|
|
51
|
+
* by snapshot resolution at send time, exactly as the main request path does, so a paused or
|
|
52
|
+
* reauth-pending ACTIVE account does not make a pool with another usable account unavailable.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveAnthropicSidecarAuth(config: OcxConfig, instance: AnthropicInstanceId):
|
|
55
|
+
{ anthropicProviderName: AnthropicInstanceId; anthropicProvider: OcxProviderConfig } | undefined {
|
|
56
|
+
const provider = config.providers[instance];
|
|
57
|
+
if (!provider || provider.disabled || provider.authMode !== "oauth" || provider.adapter !== "anthropic"
|
|
58
|
+
|| configuredAnthropicInstance(config, instance) !== instance) return undefined;
|
|
59
|
+
if (!getAccountSet(instance)?.accounts.some(row => row.paused !== true && row.needsReauth !== true)) return undefined;
|
|
60
|
+
return { anthropicProviderName: instance, anthropicProvider: provider };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Explicit target, then the parent's CONFIGURED builtin instance. The parent name alone is not
|
|
65
|
+
* enough: a custom provider that happens to be named `anthropic2` is not Pool 2 and is never inherited.
|
|
66
|
+
*/
|
|
67
|
+
export function resolveAnthropicHelperInstance(config: OcxConfig, context: AnthropicHelperContext): AnthropicInstanceId | undefined {
|
|
68
|
+
if (context.backendFamily !== "anthropic") return undefined;
|
|
69
|
+
const instance = context.anthropicInstance ?? inheritedAnthropicInstance(config, context.parentProviderName);
|
|
70
|
+
if (instance && !resolveAnthropicSidecarAuth(config, instance)) throw new AnthropicHelperUnavailableError(instance);
|
|
71
|
+
return instance;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Planner boundary for the typed refusal: an unavailable selected pool means "this helper does not
|
|
76
|
+
* run", never "fail the main request" and never "discover another pool". Other errors propagate.
|
|
77
|
+
*/
|
|
78
|
+
export function withAnthropicHelperRefusal<T>(surface: string, resolve: () => T): T | undefined {
|
|
79
|
+
try {
|
|
80
|
+
return resolve();
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (!(error instanceof AnthropicHelperUnavailableError)) throw error;
|
|
83
|
+
console.warn(`[${surface}] ${error.message}; the request continues without this helper`);
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
20
87
|
|
|
21
88
|
export interface SidecarAuthState {
|
|
22
89
|
/** ChatGPT login usable: canonical forward provider AND a live stored credential. */
|
|
@@ -63,6 +130,10 @@ function findAnthropicAuthProvider(
|
|
|
63
130
|
config: OcxConfig,
|
|
64
131
|
): { providerName: string; provider: OcxProviderConfig } | undefined {
|
|
65
132
|
for (const [providerName, provider] of Object.entries(config.providers)) {
|
|
133
|
+
// Never adds Pool 2 automatically. The OAuth store key `anthropic2` belongs to the builtin pool:
|
|
134
|
+
// its token path and the token guardian refuse an unmarked row of that name, so offering such a
|
|
135
|
+
// custom row here would advertise credentials no helper executor will spend.
|
|
136
|
+
if (providerName === "anthropic2") continue;
|
|
66
137
|
if (provider.disabled === true) continue;
|
|
67
138
|
if (provider.adapter !== "anthropic" || provider.authMode !== "oauth") continue;
|
|
68
139
|
const set = getAccountSet(providerName);
|
|
@@ -72,8 +143,11 @@ function findAnthropicAuthProvider(
|
|
|
72
143
|
return undefined;
|
|
73
144
|
}
|
|
74
145
|
|
|
75
|
-
export function resolveSidecarAuth(config: OcxConfig): SidecarAuthState {
|
|
76
|
-
const
|
|
146
|
+
export function resolveSidecarAuth(config: OcxConfig, instance?: AnthropicInstanceId): SidecarAuthState {
|
|
147
|
+
const exact = instance ? resolveAnthropicSidecarAuth(config, instance) : undefined;
|
|
148
|
+
if (instance && !exact) throw new AnthropicHelperUnavailableError(instance);
|
|
149
|
+
const anthropic = exact ? { providerName: exact.anthropicProviderName, provider: exact.anthropicProvider }
|
|
150
|
+
: findAnthropicAuthProvider(config);
|
|
77
151
|
return {
|
|
78
152
|
isCodexAuth: hasUsableCodexLogin(config),
|
|
79
153
|
isAnthropicAuth: anthropic !== undefined,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth account-pool settings. One shape, two locations:
|
|
3
|
+
* `config.anthropicAccountPool` for the `anthropic` instance and
|
|
4
|
+
* `config.providers.anthropic2.anthropicAccountPool` for `anthropic2`. Neither inherits from the other.
|
|
5
|
+
*
|
|
6
|
+
* Leaf module: `config.ts` and `provider.ts` import these types, never the reverse.
|
|
7
|
+
*/
|
|
8
|
+
export type OcxAccountPoolRotationStrategy = "quota" | "round-robin" | "fill-first";
|
|
9
|
+
|
|
10
|
+
export type OcxAccountPoolQuotaWindow = "five-hour" | "weekly" | "max-utilization";
|
|
11
|
+
|
|
12
|
+
export interface AnthropicModelRoute {
|
|
13
|
+
name: string;
|
|
14
|
+
match: string;
|
|
15
|
+
accounts: string[];
|
|
16
|
+
fallback?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AnthropicAccountPoolConfig {
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
/** Preserve native Claude Messages while the pool is enabled. Default true; false selects legacy translation. */
|
|
22
|
+
nativeMessages?: boolean;
|
|
23
|
+
/** Usage % threshold for new-session auto-pick. Default 80. 0 = disabled (affinity/active only). */
|
|
24
|
+
autoSwitchThreshold?: number;
|
|
25
|
+
/** New-session rotation strategy. Default quota (today's behaviour). */
|
|
26
|
+
strategy?: OcxAccountPoolRotationStrategy;
|
|
27
|
+
/** Successful new-session binds retained on one round-robin selection. Default 1; range 1..100. */
|
|
28
|
+
stickyLimit?: number;
|
|
29
|
+
/** Usage window for quota-based scoring. Default "five-hour" (today's behaviour). */
|
|
30
|
+
quotaWindow?: OcxAccountPoolQuotaWindow;
|
|
31
|
+
/** Ordered model allowlists; inactive while the pool is disabled. Stored account IDs only. */
|
|
32
|
+
routes?: AnthropicModelRoute[];
|
|
33
|
+
}
|
package/src/types/config.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import type { OcxProviderConfig } from "./provider";
|
|
2
2
|
import type { CodexAccount } from "./accounts";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
match: string;
|
|
7
|
-
accounts: string[];
|
|
8
|
-
fallback?: boolean;
|
|
9
|
-
}
|
|
3
|
+
import type { AnthropicAccountPoolConfig, OcxAccountPoolRotationStrategy } from "./anthropic-account-pool";
|
|
4
|
+
import type { AnthropicInstanceId } from "../providers/anthropic-instance-id";
|
|
5
|
+
export type { AnthropicAccountPoolConfig, AnthropicModelRoute, OcxAccountPoolRotationStrategy, OcxAccountPoolQuotaWindow } from "./anthropic-account-pool";
|
|
10
6
|
|
|
11
7
|
/** Public inference API exposure. Responses and Chat Completions are always served. */
|
|
12
8
|
export interface OcxApiSurfacesConfig {
|
|
@@ -222,9 +218,9 @@ export interface OcxClaudeCodeConfig {
|
|
|
222
218
|
/** Optional roster-style model forced on subagents at the next routed Claude Code launch. */
|
|
223
219
|
subagentModelForce?: string;
|
|
224
220
|
/** Claude-originated web-search override. Unset fields inherit the global sidecar settings. */
|
|
225
|
-
webSearchSidecar?: { backend?: "openai" | "anthropic" | "xai" | "gemini" | "exa"; model?: string };
|
|
221
|
+
webSearchSidecar?: { backend?: "openai" | "anthropic" | "xai" | "gemini" | "exa"; model?: string; anthropicInstance?: AnthropicInstanceId };
|
|
226
222
|
/** Claude-originated vision override. Unset fields inherit the global sidecar settings. */
|
|
227
|
-
visionSidecar?: { backend?: "openai" | "anthropic" | "routed"; model?: string };
|
|
223
|
+
visionSidecar?: { backend?: "openai" | "anthropic" | "routed"; model?: string; anthropicInstance?: AnthropicInstanceId };
|
|
228
224
|
/** Persisted Claude Desktop four-family routing profile. */
|
|
229
225
|
desktopProfile?: OcxClaudeDesktopProfile;
|
|
230
226
|
/**
|
|
@@ -1052,6 +1048,8 @@ export interface OcxConfig {
|
|
|
1052
1048
|
* upgrade against a number nobody chose.
|
|
1053
1049
|
*/
|
|
1054
1050
|
spend?: OcxSpendConfig;
|
|
1051
|
+
/** Historical salted pool aliases; h(pool,P) cannot map to Q != P for any configured provider P. */
|
|
1052
|
+
spendPoolAliases?: Record<string, string>;
|
|
1055
1053
|
/** Opt-in per-account activation of newly reset Codex quota windows. */
|
|
1056
1054
|
codexQuotaAutoRefresh?: Record<string, {
|
|
1057
1055
|
fiveHour?: boolean;
|
|
@@ -1216,21 +1214,7 @@ export interface OcxConfig {
|
|
|
1216
1214
|
* upstream has just rate-limited only ever runs after a refusal, so stranding it while a
|
|
1217
1215
|
* second logged-in account sits idle is a defect rather than a configuration choice.
|
|
1218
1216
|
*/
|
|
1219
|
-
anthropicAccountPool?:
|
|
1220
|
-
enabled?: boolean;
|
|
1221
|
-
/** Preserve native Claude Messages while the pool is enabled. Default true; false selects legacy translation. */
|
|
1222
|
-
nativeMessages?: boolean;
|
|
1223
|
-
/** Usage % threshold for new-session auto-pick. Default 80. 0 = disabled (affinity/active only). */
|
|
1224
|
-
autoSwitchThreshold?: number;
|
|
1225
|
-
/** New-session rotation strategy. Default quota (today's behaviour). */
|
|
1226
|
-
strategy?: OcxAccountPoolRotationStrategy;
|
|
1227
|
-
/** Successful new-session binds retained on one round-robin selection. Default 1; range 1..100. */
|
|
1228
|
-
stickyLimit?: number;
|
|
1229
|
-
/** Usage window for quota-based scoring. Default "five-hour" (today's behaviour). */
|
|
1230
|
-
quotaWindow?: OcxAccountPoolQuotaWindow;
|
|
1231
|
-
/** Ordered model allowlists; inactive while the pool is disabled. Stored account IDs only. */
|
|
1232
|
-
routes?: AnthropicModelRoute[];
|
|
1233
|
-
};
|
|
1217
|
+
anthropicAccountPool?: AnthropicAccountPoolConfig;
|
|
1234
1218
|
/**
|
|
1235
1219
|
* Generic OAuth multi-account PROACTIVE account preference (#2568, #695).
|
|
1236
1220
|
*
|
|
@@ -1262,10 +1246,6 @@ export interface OcxConfig {
|
|
|
1262
1246
|
corsAllowOrigins?: string[];
|
|
1263
1247
|
}
|
|
1264
1248
|
|
|
1265
|
-
export type OcxAccountPoolRotationStrategy = "quota" | "round-robin" | "fill-first";
|
|
1266
|
-
|
|
1267
|
-
export type OcxAccountPoolQuotaWindow = "five-hour" | "weekly" | "max-utilization";
|
|
1268
|
-
|
|
1269
1249
|
export type OcxComboStrategy = "failover" | "round-robin" | "random" | "least-used" | "reset-window" | "jev";
|
|
1270
1250
|
export type OcxComboDefaultEffort = "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
|
|
1271
1251
|
export type OcxComboDefaultEffortMode = "fallback" | "force";
|
|
@@ -1526,6 +1506,8 @@ export interface OcxSearchConfig {
|
|
|
1526
1506
|
}
|
|
1527
1507
|
|
|
1528
1508
|
export interface OcxVisionSidecarConfig {
|
|
1509
|
+
/** Explicit Anthropic account pool; unset inherits the request's instance. */
|
|
1510
|
+
anthropicInstance?: AnthropicInstanceId;
|
|
1529
1511
|
/** Master switch. Default: enabled when the selected backend has a usable credential. */
|
|
1530
1512
|
enabled?: boolean;
|
|
1531
1513
|
/**
|
|
@@ -1545,6 +1527,8 @@ export interface OcxVisionSidecarConfig {
|
|
|
1545
1527
|
}
|
|
1546
1528
|
|
|
1547
1529
|
export interface OcxWebSearchSidecarConfig {
|
|
1530
|
+
/** Explicit Anthropic account pool; unset inherits the request's instance. */
|
|
1531
|
+
anthropicInstance?: AnthropicInstanceId;
|
|
1548
1532
|
/** Master switch. Default: enabled when a forward (ChatGPT) provider exists and the caller is logged in. */
|
|
1549
1533
|
enabled?: boolean;
|
|
1550
1534
|
/**
|
package/src/types/provider.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UpstreamHttpVersion, ReasoningSummaryDelivery, CodexAccountMode } from "./wire";
|
|
2
|
+
import type { AnthropicAccountPoolConfig } from "./anthropic-account-pool";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Per-provider proactive-refresh policy. The guardian only ever touches a provider whose EFFECTIVE
|
|
@@ -274,6 +275,10 @@ export interface ModelCapabilities {
|
|
|
274
275
|
}
|
|
275
276
|
|
|
276
277
|
export interface OcxProviderConfig {
|
|
278
|
+
/** Explicit builtin Pool 2 provenance; endpoints never imply ownership. */
|
|
279
|
+
anthropicOAuthInstance?: "anthropic2";
|
|
280
|
+
/** Independent Anthropic pool settings; valid only on providers.anthropic2. */
|
|
281
|
+
anthropicAccountPool?: AnthropicAccountPoolConfig;
|
|
277
282
|
/** Optional browser-compatible outbound TLS profile; disabled by default. */
|
|
278
283
|
tlsProfile?: "antigravity-browser";
|
|
279
284
|
/** Optional short provider namespace used only at request/catalog presentation time. */
|
package/src/types/tools.ts
CHANGED
|
@@ -399,6 +399,13 @@ export function isAllowedToolChoice(value: OcxToolChoice | undefined): value is
|
|
|
399
399
|
return typeof value === "object" && value !== null && "allowedTools" in value;
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
+
export function requiresToolCall(choice: OcxToolChoice | undefined): boolean {
|
|
403
|
+
return choice === "required"
|
|
404
|
+
|| (typeof choice === "object" && choice !== null && (
|
|
405
|
+
"name" in choice || ("mode" in choice && choice.mode === "required")
|
|
406
|
+
));
|
|
407
|
+
}
|
|
408
|
+
|
|
402
409
|
/** Compile the request's tool-choice policy into a reusable advertisement/restoration predicate. */
|
|
403
410
|
export function toolChoiceToolPredicate(
|
|
404
411
|
choice: OcxToolChoice | undefined,
|
package/src/types.ts
CHANGED
|
@@ -16,6 +16,7 @@ export {
|
|
|
16
16
|
resolveToolChoiceWireName,
|
|
17
17
|
modelInList,
|
|
18
18
|
isAllowedToolChoice,
|
|
19
|
+
requiresToolCall,
|
|
19
20
|
toolChoiceToolPredicate,
|
|
20
21
|
declaresCodeModeExec,
|
|
21
22
|
toolRestrictsCallers,
|
|
@@ -23,6 +24,9 @@ export {
|
|
|
23
24
|
} from "./types/tools";
|
|
24
25
|
|
|
25
26
|
export type { UpstreamHttpVersion, ReasoningSummaryDelivery, CodexAccountMode } from "./types/wire";
|
|
27
|
+
export type { AnthropicInstanceId } from "./providers/anthropic-instance-id";
|
|
28
|
+
export { ANTHROPIC_INSTANCE_IDS, ANTHROPIC_PRIMARY_INSTANCE, ANTHROPIC_POOL2_INSTANCE, isAnthropicInstanceId } from "./providers/anthropic-instance-id";
|
|
29
|
+
export type { AnthropicAccountPoolConfig, AnthropicModelRoute } from "./types/anthropic-account-pool";
|
|
26
30
|
export {
|
|
27
31
|
UPSTREAM_HTTP_VERSION_VALUES,
|
|
28
32
|
REASONING_SUMMARY_DELIVERY_VALUES,
|
package/src/usage/cost.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
cursorFastPriceSupported,
|
|
31
31
|
findContextTier,
|
|
32
32
|
isLongContext,
|
|
33
|
+
pricingFamilyProvider,
|
|
33
34
|
type Cost4,
|
|
34
35
|
type ExpectedPriceOverlay,
|
|
35
36
|
type ExpectedPriceStatus,
|
|
@@ -262,7 +263,7 @@ function resolveMatchedPriceExact(
|
|
|
262
263
|
if (userOverlay) return userOverlay;
|
|
263
264
|
if (!cursorFastPriceSupported(provider, modelId)) return null;
|
|
264
265
|
const verifiedOverride = overlays === EXPECTED_PRICE_OVERLAYS
|
|
265
|
-
? findVerifiedPriceOverride(provider, modelId)
|
|
266
|
+
? findVerifiedPriceOverride(pricingFamilyProvider(provider), modelId)
|
|
266
267
|
: undefined;
|
|
267
268
|
if (verifiedOverride && verifiedOverride.status !== "unverified" && validCost4(verifiedOverride.cost4) && hasNonZeroCost(verifiedOverride.cost4)) {
|
|
268
269
|
return {
|
|
@@ -291,7 +292,7 @@ function resolveMatchedPriceExact(
|
|
|
291
292
|
...cursorFastPriceProvenance(provider, modelId),
|
|
292
293
|
};
|
|
293
294
|
}
|
|
294
|
-
const overlay = findExpectedPriceOverlay(provider, modelId, overlays);
|
|
295
|
+
const overlay = findExpectedPriceOverlay(overlays === EXPECTED_PRICE_OVERLAYS ? pricingFamilyProvider(provider) : provider, modelId, overlays);
|
|
295
296
|
if (!overlay || !validCost4(overlay.cost4) || !hasNonZeroCost(overlay.cost4)) {
|
|
296
297
|
if (options.allowModelLevelFallback === false) return null;
|
|
297
298
|
const fallback = resolveModelLevelPrice(provider, modelId);
|
|
@@ -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,
|