@bitkyc08/opencodex 2.40.0 → 2.41.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 +4 -0
- package/gui/dist/assets/index-B2YjLA-i.css +1 -0
- package/gui/dist/assets/{index-BHe2rl_C.js → index-aPup8CKb.js} +20 -20
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/meta.svg +1 -0
- package/package.json +4 -3
- package/src/adapters/cursor/catalog.ts +71 -29
- package/src/adapters/cursor/claude-id.ts +76 -0
- package/src/adapters/cursor/discovery.ts +16 -3
- package/src/adapters/cursor/effort-map.ts +27 -12
- package/src/adapters/google.ts +39 -2
- package/src/adapters/openai-responses.ts +14 -1
- package/src/cli/claude.ts +11 -2
- package/src/cli/connect.ts +7 -1
- package/src/cli/registry.ts +1 -1
- package/src/cli/status.ts +19 -4
- package/src/client/connect.ts +5 -1
- package/src/client/hub-client.ts +29 -5
- package/src/clients/config-export.ts +12 -2
- package/src/codex/catalog/aggregation.ts +8 -0
- package/src/codex/catalog/metadata.ts +5 -0
- package/src/codex/catalog/parsing.ts +2 -0
- package/src/codex/catalog/provider-fetch.ts +163 -26
- package/src/codex/catalog.ts +1 -1
- package/src/codex/convergence-types.ts +1 -0
- package/src/codex/desired-state.ts +18 -11
- package/src/combos/failover.ts +185 -6
- package/src/combos/index.ts +6 -0
- package/src/combos/resolve.ts +43 -6
- package/src/config.ts +5 -1
- package/src/generated/compatibility-version.json +85 -61
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/sync.ts +10 -2
- package/src/integrations/cursor-effort-table.ts +143 -0
- package/src/integrations/state.ts +1 -1
- package/src/integrations/writer.ts +2 -2
- package/src/lib/app-owned-memory-stores.ts +27 -8
- package/src/lib/bounded-body.ts +16 -1
- package/src/oauth/generic-account-failover.ts +2 -2
- package/src/oauth/index.ts +11 -0
- package/src/oauth/meta-muse.ts +235 -0
- package/src/providers/antigravity-models.ts +71 -13
- package/src/providers/command-code-efforts.ts +15 -0
- package/src/providers/free-directory.ts +4 -1
- package/src/providers/registry.ts +116 -8
- package/src/responses/code-mode-helper-compat.ts +4 -1
- package/src/responses/state.ts +5 -4
- package/src/server/auth-cors.ts +241 -56
- package/src/server/chat-completions.ts +11 -2
- package/src/server/chat-native.ts +30 -4
- package/src/server/claude-messages.ts +17 -3
- package/src/server/effort-row.ts +131 -0
- package/src/server/index.ts +67 -38
- package/src/server/management/api-key-rotation.ts +2 -1
- package/src/server/management/api-key-usage.ts +97 -43
- package/src/server/management/context.ts +3 -0
- package/src/server/management/cursor-integration-routes.ts +36 -7
- package/src/server/management/logs-usage-routes.ts +64 -87
- package/src/server/management/provider-routes.ts +218 -1
- package/src/server/management/route-registry.ts +1 -0
- package/src/server/management/usage-aggregate-cache.ts +464 -0
- package/src/server/management/usage-summary-cache.ts +4 -0
- package/src/server/models-capabilities.ts +60 -5
- package/src/server/responses/core.ts +61 -7
- package/src/types/config.ts +10 -1
- package/src/types/tools.ts +12 -9
- package/src/usage/expected-prices.ts +43 -7
- package/src/usage/ledger-scanner.ts +448 -0
- package/src/usage/log.ts +1 -1
- package/src/usage/summary.ts +915 -655
- package/src/web-search/index.ts +1 -1
- package/gui/dist/assets/index-CJSb3HPe.css +0 -1
|
@@ -68,12 +68,14 @@ import { resolvePassiveRouteSubjectId } from "../passive-route-linker";
|
|
|
68
68
|
import {
|
|
69
69
|
advanceComboAfterFailure,
|
|
70
70
|
comboDefaultEffort,
|
|
71
|
+
comboFailureCooldownScope,
|
|
71
72
|
comboFailureDecision,
|
|
72
73
|
comboIdFromRawBody,
|
|
73
74
|
comboRequestHasImageInput,
|
|
74
75
|
concreteComboRequestBody,
|
|
75
76
|
getCombo,
|
|
76
77
|
isComboTargetInCooldown,
|
|
78
|
+
comboCooldownRetryAfterSeconds,
|
|
77
79
|
NoAvailableComboTargetsError,
|
|
78
80
|
noteComboSuccess,
|
|
79
81
|
parseRetryAfterMs,
|
|
@@ -326,6 +328,7 @@ import {
|
|
|
326
328
|
restoreImageGenCallsInJson,
|
|
327
329
|
} from "../responses-image-gen-repair";
|
|
328
330
|
import { createResponsesModelPayloadRewrite, rewriteResponsesModelJson } from "../responses-model-rewrite";
|
|
331
|
+
import { parseRequestEffortRowId } from "../effort-row";
|
|
329
332
|
import {
|
|
330
333
|
collectSelfNamedNamespaceScrubAuthorization,
|
|
331
334
|
createSelfNamedToolCallNamespaceScrubRewrite,
|
|
@@ -1434,15 +1437,29 @@ export function decodeRequestErrorResponse(err: unknown, label: string): Respons
|
|
|
1434
1437
|
|
|
1435
1438
|
|
|
1436
1439
|
|
|
1437
|
-
export function comboUnavailableResponse(
|
|
1440
|
+
export function comboUnavailableResponse(
|
|
1441
|
+
message: string,
|
|
1442
|
+
options?: { retryAfter?: string | null },
|
|
1443
|
+
): Response {
|
|
1444
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
1445
|
+
const retryAfter = options?.retryAfter?.trim();
|
|
1446
|
+
if (retryAfter && retryAfter.length > 0 && retryAfter.length <= 128) {
|
|
1447
|
+
headers.set("Retry-After", retryAfter);
|
|
1448
|
+
}
|
|
1438
1449
|
return new Response(
|
|
1439
1450
|
JSON.stringify({
|
|
1440
1451
|
error: { message, type: "server_error", code: "combo_unavailable" },
|
|
1441
1452
|
}),
|
|
1442
|
-
{ status: 503, headers
|
|
1453
|
+
{ status: 503, headers },
|
|
1443
1454
|
);
|
|
1444
1455
|
}
|
|
1445
1456
|
|
|
1457
|
+
function comboUnavailable(comboId: string, now = Date.now()): Response {
|
|
1458
|
+
return comboUnavailableResponse(`No available targets for combo: ${comboId}`, {
|
|
1459
|
+
retryAfter: comboCooldownRetryAfterSeconds(comboId, now),
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1446
1463
|
|
|
1447
1464
|
|
|
1448
1465
|
export interface ConsumedComboFailure {
|
|
@@ -2297,7 +2314,7 @@ export async function handleComboResponses(
|
|
|
2297
2314
|
config,
|
|
2298
2315
|
{ parentThreadId: inboundClientThreadId },
|
|
2299
2316
|
);
|
|
2300
|
-
return
|
|
2317
|
+
return comboUnavailable(comboId);
|
|
2301
2318
|
}
|
|
2302
2319
|
let recovered = false;
|
|
2303
2320
|
try {
|
|
@@ -2334,7 +2351,7 @@ export async function handleComboResponses(
|
|
|
2334
2351
|
}
|
|
2335
2352
|
|
|
2336
2353
|
if (!pick) {
|
|
2337
|
-
return
|
|
2354
|
+
return comboUnavailable(comboId);
|
|
2338
2355
|
}
|
|
2339
2356
|
// One immutable combo selection trace, before any child dispatch; child
|
|
2340
2357
|
// adoption below must never replace it with a concrete child route trace.
|
|
@@ -2541,7 +2558,13 @@ export async function handleComboResponses(
|
|
|
2541
2558
|
const nextPick = advanceComboAfterFailure(config, pick, {
|
|
2542
2559
|
retryAfter: failure.retryAfter,
|
|
2543
2560
|
now: Date.now(),
|
|
2561
|
+
cooldownScope: comboFailureCooldownScope(failure.response.status, failure.classificationText, {
|
|
2562
|
+
code: failure.upstreamCode,
|
|
2563
|
+
}),
|
|
2544
2564
|
eligible: payloadEligible,
|
|
2565
|
+
status: failure.response.status,
|
|
2566
|
+
code: failure.upstreamCode,
|
|
2567
|
+
message: failure.classificationText,
|
|
2545
2568
|
});
|
|
2546
2569
|
if (!nextPick) adoptFailedChildLog(childLog);
|
|
2547
2570
|
pick = nextPick;
|
|
@@ -2697,6 +2720,23 @@ async function handleResponsesInner(
|
|
|
2697
2720
|
}
|
|
2698
2721
|
return decodeRequestErrorResponse(err, "responses");
|
|
2699
2722
|
}
|
|
2723
|
+
// An effort row naming a table-less combo (`combo/x--high`) must reach the combo dispatcher
|
|
2724
|
+
// as its base id, so the selector is normalized here, before comboIdFromRawBody reads model.
|
|
2725
|
+
const comboEffortRow = !options.comboAttempt && body && typeof body === "object" && !Array.isArray(body)
|
|
2726
|
+
&& typeof (body as { model?: unknown }).model === "string"
|
|
2727
|
+
? parseRequestEffortRowId((body as { model: string }).model, config)
|
|
2728
|
+
: null;
|
|
2729
|
+
if (comboEffortRow) {
|
|
2730
|
+
const raw = body as Record<string, unknown>;
|
|
2731
|
+
raw.model = comboEffortRow.baseId;
|
|
2732
|
+
const rawReasoning = raw.reasoning;
|
|
2733
|
+
raw.reasoning = {
|
|
2734
|
+
...(rawReasoning && typeof rawReasoning === "object" && !Array.isArray(rawReasoning)
|
|
2735
|
+
? rawReasoning as Record<string, unknown>
|
|
2736
|
+
: {}),
|
|
2737
|
+
effort: comboEffortRow.effort,
|
|
2738
|
+
};
|
|
2739
|
+
}
|
|
2700
2740
|
const comboId = !options.comboAttempt ? comboIdFromRawBody(body, config) : null;
|
|
2701
2741
|
if (comboId && Object.hasOwn(config.combos ?? {}, comboId)) {
|
|
2702
2742
|
options.onRequestBodyRead?.();
|
|
@@ -2751,6 +2791,20 @@ async function handleResponsesInner(
|
|
|
2751
2791
|
let toolBridgeMaps: ReturnType<typeof buildToolBridgeMaps>;
|
|
2752
2792
|
try {
|
|
2753
2793
|
parsed = parseRequest(body);
|
|
2794
|
+
const effortRow = parseRequestEffortRowId(parsed.modelId, config);
|
|
2795
|
+
if (effortRow) {
|
|
2796
|
+
parsed.modelId = effortRow.baseId;
|
|
2797
|
+
parsed.options.reasoning = effortRow.effort;
|
|
2798
|
+
const raw = parsed._rawBody as Record<string, unknown>;
|
|
2799
|
+
const rawReasoning = raw.reasoning;
|
|
2800
|
+
raw.model = effortRow.baseId;
|
|
2801
|
+
raw.reasoning = {
|
|
2802
|
+
...(rawReasoning && typeof rawReasoning === "object" && !Array.isArray(rawReasoning)
|
|
2803
|
+
? rawReasoning as Record<string, unknown>
|
|
2804
|
+
: {}),
|
|
2805
|
+
effort: effortRow.effort,
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2754
2808
|
if (options.comboReplaySnapshot?.recoveredPlaintext) {
|
|
2755
2809
|
markBodyNonPersistable(parsed._rawBody);
|
|
2756
2810
|
}
|
|
@@ -2881,7 +2935,7 @@ async function handleResponsesInner(
|
|
|
2881
2935
|
logCtx.routeDecision = route.routeDecision;
|
|
2882
2936
|
} catch (err) {
|
|
2883
2937
|
if (err instanceof NoAvailableComboTargetsError) {
|
|
2884
|
-
return
|
|
2938
|
+
return comboUnavailable(err.comboId);
|
|
2885
2939
|
}
|
|
2886
2940
|
if (err instanceof NoEligiblePolicyCandidateError) {
|
|
2887
2941
|
// Persist the evaluation trace (per-candidate exclusions + the
|
|
@@ -2991,7 +3045,7 @@ async function handleResponsesInner(
|
|
|
2991
3045
|
logCtx.routeDecision = route.routeDecision;
|
|
2992
3046
|
} catch (err) {
|
|
2993
3047
|
if (err instanceof NoAvailableComboTargetsError) {
|
|
2994
|
-
return
|
|
3048
|
+
return comboUnavailable(err.comboId);
|
|
2995
3049
|
}
|
|
2996
3050
|
if (err instanceof NoEligiblePolicyCandidateError) {
|
|
2997
3051
|
logCtx.routeDecision = err.trace;
|
|
@@ -3115,7 +3169,7 @@ async function handleResponsesInner(
|
|
|
3115
3169
|
logCtx.routeDecision = route.routeDecision;
|
|
3116
3170
|
} catch (err) {
|
|
3117
3171
|
if (err instanceof NoAvailableComboTargetsError) {
|
|
3118
|
-
return
|
|
3172
|
+
return comboUnavailable(err.comboId);
|
|
3119
3173
|
}
|
|
3120
3174
|
if (err instanceof NoEligiblePolicyCandidateError) {
|
|
3121
3175
|
logCtx.routeDecision = err.trace;
|
package/src/types/config.ts
CHANGED
|
@@ -348,7 +348,10 @@ export interface OcxConfig {
|
|
|
348
348
|
* the guess is wrong.
|
|
349
349
|
*/
|
|
350
350
|
oauthOpenBrowser?: boolean;
|
|
351
|
-
/**
|
|
351
|
+
/**
|
|
352
|
+
* @deprecated Compatibility-only limit for bounded legacy usage readers.
|
|
353
|
+
* `GET /api/usage` always aggregates the complete ledger.
|
|
354
|
+
*/
|
|
352
355
|
managementUsageMaxReadBytes?: number;
|
|
353
356
|
providers: Record<string, OcxProviderConfig>;
|
|
354
357
|
defaultProvider: string;
|
|
@@ -366,6 +369,12 @@ export interface OcxConfig {
|
|
|
366
369
|
};
|
|
367
370
|
/** Enable the shipped model alias patterns for providers without an override. */
|
|
368
371
|
defaultModelAliases?: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* Opt-in Cursor Private Inference compatibility rows. When true, `/v1/models`
|
|
374
|
+
* adds `<base-id>--<effort>` selectors for reasoning-capable model ids absent
|
|
375
|
+
* from Cursor's built-in effort table. Omitted/false preserves discovery output.
|
|
376
|
+
*/
|
|
377
|
+
cursorEffortRows?: boolean;
|
|
369
378
|
/** Explicit top-level deletion intent used by stale whole-config rebases. */
|
|
370
379
|
configRebaseProvenance?: OcxConfigRebaseProvenance | Record<string, unknown>;
|
|
371
380
|
/** OpenAI provider-contract migration marker (v2 = single `openai` provider with account mode). */
|
package/src/types/tools.ts
CHANGED
|
@@ -35,20 +35,23 @@ export function namespacedToolName(namespace: string | undefined, name: string):
|
|
|
35
35
|
* Codex unified-exec name normalization.
|
|
36
36
|
*
|
|
37
37
|
* Codex's code-mode shell tool is declared as `exec` (a freeform custom tool whose own
|
|
38
|
-
* description mentions the nested `await tools.exec_command(...)` helper).
|
|
39
|
-
*
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
38
|
+
* description mentions the nested `await tools.exec_command(...)` helper). Some routed providers
|
|
39
|
+
* echo that helper name as the tool-call name, emitting `exec_command`, `write_stdin`, or
|
|
40
|
+
* `apply_patch` instead of the declared `exec`. Accept these nested helper names only when the
|
|
41
|
+
* request catalog actually declares `exec` and does not itself declare the emitted name (an MCP
|
|
42
|
+
* server may legitimately advertise one under its own namespace).
|
|
43
43
|
*/
|
|
44
44
|
const LEGACY_SHELL_BRIDGE_TOOL_NAMES = ["exec_command", "shell_command"] as const;
|
|
45
|
-
const CODE_MODE_HELPER_TOOL_NAMES = [
|
|
45
|
+
const CODE_MODE_HELPER_TOOL_NAMES = [
|
|
46
|
+
...LEGACY_SHELL_BRIDGE_TOOL_NAMES,
|
|
47
|
+
"write_stdin",
|
|
48
|
+
"apply_patch",
|
|
49
|
+
] as const;
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
52
|
* The one declared name that turns nested-helper normalization on. Declaring it is not just a
|
|
49
|
-
* name: it also decides whether an emitted
|
|
50
|
-
*
|
|
51
|
-
* genuine bare declaration.
|
|
53
|
+
* name: it also decides whether an emitted helper name is accepted as that shell tool, so callers
|
|
54
|
+
* that build declared-name sets must add it only for a genuine bare declaration.
|
|
52
55
|
*/
|
|
53
56
|
export const CODE_MODE_EXEC_TOOL_NAME = "exec";
|
|
54
57
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeCursorClaudeId } from "../adapters/cursor/claude-id";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Expected-price overlay for models whose jawcode cost rows are missing or all-zero
|
|
3
5
|
* (subscription/OAuth surfaces). Sourced from official pricing pages only
|
|
@@ -56,6 +58,10 @@ const GEMINI_36_FLASH: Cost4 = { input: 1.5, output: 7.5, cacheRead: 0.15, cache
|
|
|
56
58
|
// through 2026-12-31, stepping up to $1.50 / $7.50 on 2027-01-01. Revisit this row
|
|
57
59
|
// then — the promotional rate is dated on the pricing page, not open-ended.
|
|
58
60
|
const GEMINI_37_FLASH: Cost4 = { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 };
|
|
61
|
+
// Gemini 3.8 Flash carries the same published promotional shape as 3.7 through 2026-12-31,
|
|
62
|
+
// rising to $1.50 / $7.50 on 2027-01-01. A SEPARATE constant on purpose: equal today, but
|
|
63
|
+
// aliasing them would silently drag 3.8 along if 3.7's row is ever re-verified differently.
|
|
64
|
+
const GEMINI_38_FLASH: Cost4 = { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0 };
|
|
59
65
|
const MINIMAX_M21_HIGHSPEED: Cost4 = { input: 0.6, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 };
|
|
60
66
|
const KIMI_K3: Cost4 = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3 };
|
|
61
67
|
const KIMI_K27_CODE: Cost4 = { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0.95 };
|
|
@@ -79,8 +85,19 @@ const ANTHROPIC_PRICING = "https://platform.claude.com/docs/en/about-claude/pric
|
|
|
79
85
|
|
|
80
86
|
const GEMINI_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-07-22); cacheWrite=0: storage is billed per-hour, not per-token";
|
|
81
87
|
const GEMINI_37_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-08-14); promotional rate through 2026-12-31, rises to 1.50/7.50 on 2027-01-01; cacheWrite=0: storage is billed per-hour, not per-token";
|
|
88
|
+
const GEMINI_38_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-09-03); promotional rate through 2026-12-31, rises to 1.50/7.50 on 2027-01-01; cacheWrite=0: storage is billed per-hour, not per-token";
|
|
82
89
|
const MINIMAX_PRICING = "https://platform.minimax.io/docs/guides/pricing-paygo";
|
|
83
90
|
const OPENAI_GPT56_PRICING = "https://developers.openai.com/api/docs/pricing";
|
|
91
|
+
const META_MODEL_PRICING = "https://dev.meta.ai/docs/pricing-rate-limits";
|
|
92
|
+
/*
|
|
93
|
+
* Shared by both Meta providers. Overlays resolve by EXACT provider id, so `meta-muse`
|
|
94
|
+
* cannot inherit `meta-model`'s rows — and an unpriced provider whose whole warning is
|
|
95
|
+
* "treat every call as billable" would report no cost at all.
|
|
96
|
+
*/
|
|
97
|
+
const META_MUSE_SPARK_13: Cost4 = { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 };
|
|
98
|
+
const META_MUSE_SPARK_13_CONTRIBUTOR: Cost4 = { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 };
|
|
99
|
+
const META_SPARK_SOURCE = `Meta Model API published price ${META_MODEL_PRICING}`;
|
|
100
|
+
const META_SPARK_CONTRIBUTOR_SOURCE = `Meta Model API published Contributor-tier price ${META_MODEL_PRICING}; data-sharing discount tier`;
|
|
84
101
|
const DEEPSEEK_PRICING = "https://api-docs.deepseek.com/quick_start/pricing-details-usd; V4 Flash alias transition scheduled 2026-07-24 — re-verify after";
|
|
85
102
|
// Kimi official tables publish input/output/cache-hit only; cacheWrite is mapped to the
|
|
86
103
|
// cache-miss input price (Kimi auto-caches with no separate write billing). 2026-07-20 re-verified.
|
|
@@ -100,13 +117,8 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
100
117
|
// bundle collapses anthropic-apikey onto anthropic).
|
|
101
118
|
{ provider: "anthropic", modelId: "claude-fable-5-1", cost4: CLAUDE_FABLE_51, source: `anthropic official Claude Fable 5.1 ${ANTHROPIC_PRICING}; cache hit = 0.025x base input`, verifiedAt: "2026-09-02", status: "verified" },
|
|
102
119
|
{ provider: "anthropic-apikey", modelId: "claude-fable-5-1", cost4: CLAUDE_FABLE_51, source: `anthropic official Claude Fable 5.1 ${ANTHROPIC_PRICING}; cache hit = 0.025x base input`, verifiedAt: "2026-09-02", status: "verified" },
|
|
103
|
-
// Cursor
|
|
104
|
-
// the model-level vendor fallback only searches jawcode metadata, which has no Fable 5.1
|
|
105
|
-
// row yet, so each Cursor spelling needs its own overlay. Vendor list price, like the
|
|
106
|
-
// cursor/claude-opus-5 row.
|
|
120
|
+
// Cursor canonicalizes every Fable 5.1 spelling onto this sole overlay row.
|
|
107
121
|
{ provider: "cursor", modelId: "claude-fable-5-1", cost4: CLAUDE_FABLE_51, source: `anthropic official Claude Fable 5.1 ${ANTHROPIC_PRICING}; cache hit = 0.025x base input; vendor list price applied to the Cursor surface`, verifiedAt: "2026-09-02", status: "verified-derived" },
|
|
108
|
-
{ provider: "cursor", modelId: "claude-fable-5.1", cost4: CLAUDE_FABLE_51, source: `anthropic official Claude Fable 5.1 ${ANTHROPIC_PRICING}; cache hit = 0.025x base input; vendor list price applied to the Cursor surface`, verifiedAt: "2026-09-02", status: "verified-derived" },
|
|
109
|
-
{ provider: "cursor", modelId: "claude-5.1-fable", cost4: CLAUDE_FABLE_51, source: `anthropic official Claude Fable 5.1 ${ANTHROPIC_PRICING}; cache hit = 0.025x base input; vendor list price applied to the Cursor surface`, verifiedAt: "2026-09-02", status: "verified-derived" },
|
|
110
122
|
// claude-opus-5 is exposed by three providers but absent from the jawcode bundle, so
|
|
111
123
|
// cost resolution returned null and the Logs `~$` column rendered an em dash. The
|
|
112
124
|
// model-level vendor fallback only searches jawcode metadata, never overlays, so one
|
|
@@ -126,6 +138,10 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
126
138
|
// 3.7 Flash rides CCA, whose billing equivalence to the Developer API list price is
|
|
127
139
|
// not published, so this is `verified-derived` rather than `verified`: the number is
|
|
128
140
|
// proven, the claim that Antigravity charges it is inferred.
|
|
141
|
+
{ provider: "google-antigravity", modelId: "gemini-3.8-flash", cost4: GEMINI_38_FLASH, source: `derived: Gemini 3.8 Flash promotional rate through 2026-12-31 ${GEMINI_38_PRICING}`, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
142
|
+
{ provider: "google-antigravity", modelId: "gemini-3.8-flash-low", cost4: GEMINI_38_FLASH, source: `derived: gemini-3.8-flash ${GEMINI_38_PRICING}`, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
143
|
+
{ provider: "google-antigravity", modelId: "gemini-3.8-flash-medium", cost4: GEMINI_38_FLASH, source: `derived: gemini-3.8-flash ${GEMINI_38_PRICING}`, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
144
|
+
{ provider: "google-antigravity", modelId: "gemini-3.8-flash-high", cost4: GEMINI_38_FLASH, source: `derived: gemini-3.8-flash ${GEMINI_38_PRICING}`, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
129
145
|
{ provider: "google-antigravity", modelId: "gemini-3.7-flash", cost4: GEMINI_37_FLASH, source: `derived: Gemini 3.7 Flash promotional rate through 2026-12-31 ${GEMINI_37_PRICING}`, verifiedAt: "2026-08-14", status: "verified-derived" },
|
|
130
146
|
// Retained after the 3.6 retirement: historical usage.jsonl rows still carry these
|
|
131
147
|
// ids, and dropping the row would silently zero the cost of requests already made.
|
|
@@ -139,6 +155,19 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
139
155
|
{ provider: "openai-apikey", modelId: "gpt-5.6-sol-pro", cost4: GPT56_SOL, source: `collapsed base ID ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-03", status: "verified-derived" },
|
|
140
156
|
{ provider: "openai-apikey", modelId: "gpt-5.6-terra-pro", cost4: GPT56_TERRA, source: `collapsed base ID ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-03", status: "verified-derived" },
|
|
141
157
|
{ provider: "openai-apikey", modelId: "gpt-5.6-luna-pro", cost4: GPT56_LUNA, source: `collapsed base ID ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-03", status: "verified-derived" },
|
|
158
|
+
// Meta Model API direct provider. `meta-model` has no jawcode metadata alias, so an
|
|
159
|
+
// unpriced row falls through the whole resolution chain and the Logs cost column
|
|
160
|
+
// renders nothing — these exact overlays are the only source. Both are Meta's own
|
|
161
|
+
// published list prices for Meta's own endpoint (hence "verified", not derived), and
|
|
162
|
+
// they match the figures Command Code republishes for the same two models.
|
|
163
|
+
// cacheWrite=0: Meta publishes a cached-input price but no cache-write charge.
|
|
164
|
+
{ provider: "meta-model", modelId: "muse-spark-1.3", cost4: META_MUSE_SPARK_13, source: META_SPARK_SOURCE, verifiedAt: "2026-09-03", status: "verified" },
|
|
165
|
+
{ provider: "meta-model", modelId: "muse-spark-1.3-contributor", cost4: META_MUSE_SPARK_13_CONTRIBUTOR, source: META_SPARK_CONTRIBUTOR_SOURCE, verifiedAt: "2026-09-03", status: "verified" },
|
|
166
|
+
// Same endpoint, same list price, different credential. Meta does not authorize this
|
|
167
|
+
// reuse and settlement is not observable, so these are the public Model API rates as a
|
|
168
|
+
// conservative estimate — not evidence of how the call is actually billed.
|
|
169
|
+
{ provider: "meta-muse", modelId: "muse-spark-1.3", cost4: META_MUSE_SPARK_13, source: META_SPARK_SOURCE, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
170
|
+
{ provider: "meta-muse", modelId: "muse-spark-1.3-contributor", cost4: META_MUSE_SPARK_13_CONTRIBUTOR, source: META_SPARK_CONTRIBUTOR_SOURCE, verifiedAt: "2026-09-03", status: "verified-derived" },
|
|
142
171
|
// Daybreak aliases: priced as their current snapshots (red -> gpt-5.6-cyber,
|
|
143
172
|
// blue -> gpt-5.6-sol). The alias ids carry no rows of their own upstream, hence
|
|
144
173
|
// verified-derived. Blue deliberately reuses GPT56_SOL rather than duplicating the tuple.
|
|
@@ -163,6 +192,7 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
163
192
|
{ provider: "google", modelId: "gemini-3.6-flash", cost4: GEMINI_36_FLASH, source: GEMINI_PRICING, verifiedAt: "2026-07-22", status: "verified" },
|
|
164
193
|
// Developer API row: the price IS published for this surface, so `verified`.
|
|
165
194
|
{ provider: "google", modelId: "gemini-3.7-flash", cost4: GEMINI_37_FLASH, source: GEMINI_37_PRICING, verifiedAt: "2026-08-14", status: "verified" },
|
|
195
|
+
{ provider: "google", modelId: "gemini-3.8-flash", cost4: GEMINI_38_FLASH, source: GEMINI_38_PRICING, verifiedAt: "2026-09-03", status: "verified" },
|
|
166
196
|
{ provider: "google-antigravity", modelId: "gemini-3.1-pro-preview", cost4: GEMINI_31_PRO, source: GEMINI_PRICING, verifiedAt: "2026-07-20", status: "verified" },
|
|
167
197
|
// Antigravity-bundled third-party models — derived from the underlying vendor's
|
|
168
198
|
// official API price (Antigravity itself bills via subscription quota).
|
|
@@ -236,8 +266,14 @@ export function findExpectedPriceOverlay(
|
|
|
236
266
|
overlays: readonly ExpectedPriceOverlay[] = EXPECTED_PRICE_OVERLAYS,
|
|
237
267
|
): ExpectedPriceOverlay | undefined {
|
|
238
268
|
const exact = overlays.filter(row => row.provider === provider && row.modelId === modelId);
|
|
239
|
-
|
|
269
|
+
const match = exact.find(row => row.status === "verified")
|
|
240
270
|
?? exact.find(row => row.status === "verified-derived");
|
|
271
|
+
if (match || provider !== "cursor") return match;
|
|
272
|
+
const canonicalBaseId = normalizeCursorClaudeId(modelId)?.canonicalBaseId;
|
|
273
|
+
if (!canonicalBaseId) return undefined;
|
|
274
|
+
const canonical = overlays.filter(row => row.provider === provider && row.modelId === canonicalBaseId);
|
|
275
|
+
return canonical.find(row => row.status === "verified")
|
|
276
|
+
?? canonical.find(row => row.status === "verified-derived");
|
|
241
277
|
}
|
|
242
278
|
|
|
243
279
|
/** OpenAI Fast price multipliers retained as a compatibility export. */
|