@yansigit/opencodex 2.33.0 → 2.35.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/index-BjCaHxdz.js +112 -0
- package/gui/dist/assets/index-DLkXOXLC.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic.ts +79 -2
- package/src/adapters/command-code.ts +141 -23
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/checkpoint-store.ts +15 -10
- package/src/adapters/cursor/discovery.ts +60 -2
- package/src/adapters/cursor/effort-map.ts +79 -1
- package/src/adapters/cursor/envelope-echo.ts +162 -0
- package/src/adapters/cursor/live-models.ts +7 -2
- package/src/adapters/cursor/live-transport.ts +17 -1
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-fs.ts +13 -12
- package/src/adapters/cursor/native-exec-network.ts +3 -5
- package/src/adapters/cursor/native-exec-policy.ts +47 -0
- package/src/adapters/cursor/native-exec-shell.ts +116 -31
- package/src/adapters/cursor/native-exec.ts +38 -10
- package/src/adapters/cursor/protobuf-events.ts +28 -2
- package/src/adapters/cursor/protobuf-request.ts +93 -41
- package/src/adapters/cursor/request-builder.ts +39 -10
- package/src/adapters/cursor/tool-definitions.ts +27 -3
- package/src/adapters/cursor/tool-result-normalize.ts +51 -6
- package/src/adapters/cursor/types.ts +23 -4
- package/src/adapters/cursor.ts +170 -29
- package/src/adapters/google-aistudio-parser.ts +49 -0
- package/src/adapters/google-antigravity-replay.ts +105 -25
- package/src/adapters/google-antigravity-wire.ts +5 -0
- package/src/adapters/google-errors.ts +41 -12
- package/src/adapters/google-http.ts +12 -11
- package/src/adapters/google.ts +219 -36
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +15 -0
- package/src/adapters/kiro-tools.ts +43 -15
- package/src/adapters/kiro.ts +54 -9
- package/src/adapters/openai-chat.ts +286 -242
- package/src/adapters/openai-responses.ts +335 -24
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-catalog-nudge.ts +2 -2
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/bridge.ts +67 -26
- package/src/chat/inbound.ts +29 -1
- package/src/chat/outbound.ts +15 -7
- package/src/claude/agents-inject.ts +8 -1
- package/src/claude/outbound.ts +10 -8
- package/src/cli/account-api.ts +27 -7
- package/src/cli/account-extended.ts +10 -3
- package/src/cli/account.ts +29 -5
- package/src/cli/alias.ts +66 -0
- package/src/cli/claude.ts +26 -1
- package/src/cli/dispatch.ts +13 -1
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +6 -1
- package/src/cli/init.ts +1 -0
- package/src/cli/models-runtime.ts +95 -0
- package/src/cli/models.ts +13 -7
- package/src/cli/provider-runtime.ts +16 -2
- package/src/cli/registry.ts +6 -1
- package/src/cli/telemetry-commands.ts +25 -0
- package/src/cli/v2.ts +34 -10
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +3 -2
- package/src/codex/app-server-processes.ts +80 -6
- package/src/codex/auth-api.ts +48 -8
- package/src/codex/auth-context.ts +21 -18
- package/src/codex/catalog/aggregation.ts +6 -0
- package/src/codex/catalog/model-metadata.ts +13 -1
- package/src/codex/catalog/native-models.ts +5 -2
- package/src/codex/catalog/parsing.ts +16 -0
- package/src/codex/catalog/provider-fetch.ts +20 -3
- package/src/codex/catalog/sync.ts +127 -2
- package/src/codex/catalog.ts +1 -1
- package/src/codex/codex-write-lock.ts +3 -1
- package/src/codex/convergence-types.ts +1 -1
- package/src/codex/convergence.ts +22 -2
- package/src/codex/desired-state.ts +2 -2
- package/src/codex/desktop-app-restart.ts +18 -5
- package/src/codex/inject-coordination.ts +83 -0
- package/src/codex/inject.ts +14 -1
- package/src/codex/log-guard/inspect.ts +22 -4
- package/src/codex/model-entitlements.ts +9 -2
- package/src/codex/prompt-layers.ts +371 -25
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota.ts +123 -18
- package/src/codex/routing.ts +9 -0
- package/src/codex/subagent-model-fallback.ts +198 -27
- package/src/codex/transition-state.ts +107 -8
- package/src/combos/types.ts +10 -0
- package/src/compatibility/openai-responses.ts +33 -1
- package/src/config/autonomous-remediation.ts +21 -0
- package/src/config/provider-validation.ts +14 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +191 -17
- package/src/generated/compatibility-version.json +279 -159
- package/src/generated/model-metadata.ts +3 -0
- package/src/images/loop.ts +5 -4
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +1 -1
- package/src/lab/fabric/producer-child.ts +1 -1
- package/src/lib/config-ownership.ts +20 -0
- package/src/lib/errors.ts +11 -2
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/oauth/aistudio-credentials.ts +65 -0
- package/src/oauth/aistudio-native-daemon.ts +116 -0
- package/src/oauth/aistudio-session-sync.ts +95 -0
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-aistudio-auth.ts +98 -0
- package/src/oauth/index.ts +57 -5
- package/src/oauth/key-providers.ts +18 -1
- package/src/oauth/kiro.ts +45 -0
- package/src/oauth/login-cli.ts +65 -1
- package/src/oauth/types.ts +15 -0
- package/src/providers/codex-capacity.ts +5 -2
- package/src/providers/command-code-efforts.ts +38 -6
- package/src/providers/context-cap.ts +4 -3
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +29 -1
- package/src/providers/fastwire.ts +7 -1
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/provider-id-rewrite.ts +2 -1
- package/src/providers/quota.ts +157 -46
- package/src/providers/registry.ts +184 -71
- package/src/providers/slug-codec.ts +52 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/custom-tool-compat.ts +34 -10
- package/src/responses/parser.ts +4 -0
- package/src/responses/schema.ts +5 -1
- package/src/responses/thought-signature-replay.ts +17 -0
- package/src/router.ts +43 -2
- package/src/routing/account-pool/cooldown.ts +8 -0
- package/src/routing/account-pool/index.ts +1 -0
- package/src/routing/analytics.ts +1 -0
- package/src/routing/quota.ts +10 -0
- package/src/server/auth-cors.ts +24 -0
- package/src/server/chat-completions.ts +26 -16
- package/src/server/chat-native-sse.ts +3 -3
- package/src/server/chat-native.ts +30 -11
- package/src/server/claude-messages.ts +1 -1
- package/src/server/effort-policy.ts +16 -0
- package/src/server/index.ts +180 -14
- package/src/server/lifecycle.ts +52 -1
- package/src/server/management/agent-settings-routes.ts +31 -15
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +2 -1
- package/src/server/management/config-routes.ts +27 -9
- package/src/server/management/context.ts +9 -0
- package/src/server/management/logs-usage-routes.ts +11 -5
- package/src/server/management/model-routes.ts +266 -0
- package/src/server/management/oauth-account-routes.ts +13 -3
- package/src/server/management/provider-routes.ts +137 -3
- package/src/server/management/routing-profile-routes.ts +2 -2
- package/src/server/management-api.ts +2 -0
- package/src/server/port-reclaim.ts +19 -1
- package/src/server/relay-eager.ts +147 -20
- package/src/server/relay.ts +251 -19
- package/src/server/request-log-conversation.ts +33 -0
- package/src/server/request-log.ts +48 -21
- package/src/server/responses/collaboration.ts +42 -5
- package/src/server/responses/combo-stream-preflight.ts +10 -3
- package/src/server/responses/core.ts +575 -140
- package/src/server/responses/empty-completion-guard.ts +35 -0
- package/src/server/responses/fetch-helpers.ts +14 -6
- package/src/server/responses/input-admission.ts +3 -1
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +1 -1
- package/src/server/responses/responses-field-backfill.ts +105 -13
- package/src/server/responses/ws-upstream.ts +35 -5
- package/src/server/responses-custom-tool-repair.ts +52 -7
- package/src/server/responses-terminal-repair.ts +25 -4
- package/src/server/sse-frame-buffer.ts +31 -4
- package/src/server/ws-bridge.ts +14 -2
- package/src/smoke/fingerprint-cache.ts +133 -0
- package/src/smoke/live-scenarios.ts +33 -0
- package/src/smoke/runner.ts +119 -0
- package/src/telemetry/dispatcher.ts +44 -0
- package/src/telemetry/fingerprint.ts +24 -0
- package/src/telemetry/hook.ts +43 -0
- package/src/telemetry/ledger.ts +54 -0
- package/src/telemetry/types.ts +23 -0
- package/src/types/config.ts +66 -14
- package/src/types/provider.ts +79 -1
- package/src/types/request.ts +18 -10
- package/src/types/tools.ts +30 -11
- package/src/types.ts +1 -0
- package/src/usage/command-code-manifest.ts +116 -0
- package/src/usage/cost.ts +2 -2
- package/src/usage/expected-prices.ts +126 -24
- package/src/usage/log.ts +18 -8
- package/src/usage/summary.ts +34 -12
- package/src/web-search/exa-executor.ts +40 -9
- package/src/web-search/index.ts +16 -8
- package/src/web-search/loop.ts +5 -4
- package/gui/dist/assets/index-DKLr4LTE.js +0 -102
- package/gui/dist/assets/index-DrSQdTRd.css +0 -1
|
@@ -39,7 +39,7 @@ export interface ExpectedPriceOverlay {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const GEMINI_31_PRO: Cost4 = { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 };
|
|
42
|
-
const GPT56_SOL: Cost4 = { input:
|
|
42
|
+
const GPT56_SOL: Cost4 = { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 };
|
|
43
43
|
/**
|
|
44
44
|
* Daybreak aliases. `daybreak-*-latest` never appears in the pricing table itself — only its
|
|
45
45
|
* current snapshot does — so these tuples are the snapshot's published rates and carry
|
|
@@ -89,6 +89,17 @@ const KIMI_PRICING = "https://platform.kimi.ai/docs/pricing (official table; cac
|
|
|
89
89
|
// anywhere. Cache stays 0 rather than inheriting the reseller's 0.15 — a reseller number
|
|
90
90
|
// under a vendor-price label would be a wrong value wearing a verified badge.
|
|
91
91
|
const QWEN38_MAX_PRICING = "https://qwen.ai/blog?id=qwen3.8 (Qwen release announcement; no Model Studio billing row yet; cache rates unpublished -> 0)";
|
|
92
|
+
const COMMAND_CODE_PRICING = "https://commandcode.ai/models + https://commandcode.ai/models.data (official model manifest)";
|
|
93
|
+
const COMMAND_CODE_VERIFIED_AT = "2026-08-26";
|
|
94
|
+
const CURSOR_DOCS_PRICING = "https://cursor.com/docs/models-and-pricing";
|
|
95
|
+
const CURSOR_GROK_46: Cost4 = { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 };
|
|
96
|
+
const CURSOR_GROK_45: Cost4 = { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 };
|
|
97
|
+
const CURSOR_COMPOSER_1: Cost4 = { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 };
|
|
98
|
+
const CURSOR_COMPOSER_25: Cost4 = { input: 0.5, output: 2.5, cacheRead: 0.2, cacheWrite: 0 };
|
|
99
|
+
const CURSOR_COMPOSER_25_FAST: Cost4 = { input: 3, output: 15, cacheRead: 0.5, cacheWrite: 0 };
|
|
100
|
+
const CURSOR_GROK_46_FAST: Cost4 = { input: 4, output: 12, cacheRead: 1, cacheWrite: 0 };
|
|
101
|
+
const CURSOR_GROK_45_FAST: Cost4 = { input: 4, output: 18, cacheRead: 1, cacheWrite: 0 };
|
|
102
|
+
const CLAUDE_OPUS_FAST: Cost4 = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 };
|
|
92
103
|
|
|
93
104
|
export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
94
105
|
// claude-opus-5 is exposed by three providers but absent from the jawcode bundle, so
|
|
@@ -126,6 +137,10 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
126
137
|
// Daybreak aliases: priced as their current snapshots (red -> gpt-5.6-cyber,
|
|
127
138
|
// blue -> gpt-5.6-sol). The alias ids carry no rows of their own upstream, hence
|
|
128
139
|
// verified-derived. Blue deliberately reuses GPT56_SOL rather than duplicating the tuple.
|
|
140
|
+
// The `gpt-` selector is native to ChatGPT/Codex accounts. The bare aliases below belong to
|
|
141
|
+
// the separately billed API-key catalog; keep those namespaces disjoint so pricing metadata
|
|
142
|
+
// cannot make an unroutable provider/model pair look supported.
|
|
143
|
+
{ provider: "openai", modelId: "gpt-daybreak-blue-latest", cost4: GPT56_SOL, source: `alias of gpt-5.6-sol ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-11", status: "verified-derived" },
|
|
129
144
|
{ provider: "openai-apikey", modelId: "daybreak-red-latest", cost4: DAYBREAK_RED, source: `alias of gpt-5.6-cyber ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-11", status: "verified-derived" },
|
|
130
145
|
{ provider: "openai-apikey", modelId: "daybreak-blue-latest", cost4: GPT56_SOL, source: `alias of gpt-5.6-sol ${OPENAI_GPT56_PRICING}`, verifiedAt: "2026-08-11", status: "verified-derived" },
|
|
131
146
|
{ provider: "google-antigravity", modelId: "gemini-3.1-pro-low", cost4: GEMINI_31_PRO, source: `derived: gemini-3.1-pro (<=200k tier) ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
|
|
@@ -179,6 +194,16 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
179
194
|
{ provider: "alibaba-token-plan-intl", modelId: "qwen3.8-max", cost4: QWEN38_MAX, source: QWEN38_MAX_PRICING, verifiedAt: "2026-08-04", status: "verified" },
|
|
180
195
|
// Cursor Auto router — Cursor's published fixed token price (verified).
|
|
181
196
|
{ provider: "cursor", modelId: "auto", cost4: { input: 1.25, output: 6, cacheRead: 0.25, cacheWrite: 1.25 }, source: "https://docs.cursor.com/account/pricing + https://cursor.com/blog/aug-2025-pricing", verifiedAt: "2026-07-20", status: "verified" },
|
|
197
|
+
// Cursor-specific native models (verified from official docs).
|
|
198
|
+
{ provider: "cursor", modelId: "grok-4.6", cost4: CURSOR_GROK_46, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
199
|
+
{ provider: "cursor", modelId: "grok-4.5", cost4: CURSOR_GROK_45, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
200
|
+
{ provider: "cursor", modelId: "composer-1", cost4: CURSOR_COMPOSER_1, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
201
|
+
{ provider: "cursor", modelId: "composer-2.5", cost4: CURSOR_COMPOSER_25, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
202
|
+
{ provider: "cursor", modelId: "composer-2.5-fast", cost4: CURSOR_COMPOSER_25_FAST, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
203
|
+
{ provider: "cursor", modelId: "grok-4.6-fast", cost4: CURSOR_GROK_46_FAST, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
204
|
+
{ provider: "cursor", modelId: "grok-4.5-fast", cost4: CURSOR_GROK_45_FAST, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
205
|
+
{ provider: "cursor", modelId: "claude-opus-5-fast", cost4: CLAUDE_OPUS_FAST, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
206
|
+
{ provider: "cursor", modelId: "claude-opus-4-8-fast", cost4: CLAUDE_OPUS_FAST, source: CURSOR_DOCS_PRICING, verifiedAt: "2026-08-26", status: "verified" },
|
|
182
207
|
];
|
|
183
208
|
|
|
184
209
|
/**
|
|
@@ -195,6 +220,68 @@ export const VERIFIED_PRICE_OVERRIDES: readonly ExpectedPriceOverlay[] = [
|
|
|
195
220
|
verifiedAt: "2026-08-18",
|
|
196
221
|
status: "verified",
|
|
197
222
|
},
|
|
223
|
+
// Command Code official model catalog rates (sourced from https://commandcode.ai/models.data).
|
|
224
|
+
{ provider: "command-code", modelId: "zai-org/GLM-5.3", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
225
|
+
{ provider: "command-code", modelId: "zai-org/glm-5.3", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified-derived" },
|
|
226
|
+
{ provider: "command-code", modelId: "zai-org/GLM-5.2", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
227
|
+
{ provider: "command-code", modelId: "zai-org/glm-5.2", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified-derived" },
|
|
228
|
+
{ provider: "command-code", modelId: "zai-org/GLM-5.2-Fast", cost4: { input: 3, output: 10.25, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
229
|
+
{ provider: "command-code", modelId: "zai-org/glm-5.2-fast", cost4: { input: 3, output: 10.25, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified-derived" },
|
|
230
|
+
{ provider: "command-code", modelId: "zai-org/GLM-5.1", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
231
|
+
{ provider: "command-code", modelId: "zai-org/glm-5.1", cost4: { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified-derived" },
|
|
232
|
+
{ provider: "command-code", modelId: "zai-org/GLM-5", cost4: { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
233
|
+
{ provider: "command-code", modelId: "zai-org/glm-5", cost4: { input: 1, output: 3.2, cacheRead: 0.2, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified-derived" },
|
|
234
|
+
{ provider: "command-code", modelId: "meta/muse-spark-1.2-contributor", cost4: { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
235
|
+
{ provider: "command-code", modelId: "meta/muse-spark-1.2", cost4: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
236
|
+
{ provider: "command-code", modelId: "meta/muse-spark-1.1", cost4: { input: 1.25, output: 4.25, cacheRead: 0.15, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
237
|
+
{ provider: "command-code", modelId: "google/gemini-3.7-flash", cost4: { input: 0.75, output: 3.75, cacheRead: 0.075, cacheWrite: 0.04167 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
238
|
+
{ provider: "command-code", modelId: "google/gemini-3.6-flash", cost4: { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
239
|
+
{ provider: "command-code", modelId: "google/gemini-3.5-flash", cost4: { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
240
|
+
{ provider: "command-code", modelId: "google/gemini-3.5-flash-lite", cost4: { input: 0.3, output: 2.5, cacheRead: 0.03, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
241
|
+
{ provider: "command-code", modelId: "google/gemini-3.1-flash-lite", cost4: { input: 0.25, output: 1.5, cacheRead: 0.03, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
242
|
+
{ provider: "command-code", modelId: "deepseek/deepseek-v4-pro", cost4: { input: 0.66, output: 1.98, cacheRead: 0.022, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
243
|
+
{ provider: "command-code", modelId: "deepseek/deepseek-v4-flash", cost4: { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
244
|
+
{ provider: "command-code", modelId: "deepseek/deepseek-v4-flash-vision-exp", cost4: { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
245
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.8-Max", cost4: { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
246
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.8-27B", cost4: { input: 0.4, output: 3, cacheRead: 0.04, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
247
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.7-Max", cost4: { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.13 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
248
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.7-Plus", cost4: { input: 0.4, output: 1.6, cacheRead: 0.08, cacheWrite: 0.5 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
249
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.7-Flash", cost4: { input: 0.03, output: 0.13, cacheRead: 0.006, cacheWrite: 0.038 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
250
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.6-Max-Preview", cost4: { input: 1.3, output: 7.8, cacheRead: 0.26, cacheWrite: 1.63 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
251
|
+
{ provider: "command-code", modelId: "Qwen/Qwen3.6-Plus", cost4: { input: 0.5, output: 3, cacheRead: 0.1, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
252
|
+
{ provider: "command-code", modelId: "MiniMaxAI/MiniMax-M3", cost4: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
253
|
+
{ provider: "command-code", modelId: "MiniMaxAI/MiniMax-M2.7", cost4: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
254
|
+
{ provider: "command-code", modelId: "MiniMaxAI/MiniMax-M2.5", cost4: { input: 0.3, output: 1.2, cacheRead: 0.03, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
255
|
+
{ provider: "command-code", modelId: "stepfun/Step-3.7-Flash", cost4: { input: 0.2, output: 1.15, cacheRead: 0.04, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
256
|
+
{ provider: "command-code", modelId: "stepfun/Step-3.5-Flash", cost4: { input: 0.1, output: 0.3, cacheRead: 0.02, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
257
|
+
{ provider: "command-code", modelId: "xiaomi/mimo-v2.5-pro", cost4: { input: 0.435, output: 0.87, cacheRead: 0.0036, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
258
|
+
{ provider: "command-code", modelId: "xiaomi/mimo-v2.5", cost4: { input: 0.14, output: 0.28, cacheRead: 0.0028, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
259
|
+
{ provider: "command-code", modelId: "nvidia/nemotron-3-ultra-550b-a55b", cost4: { input: 0.6, output: 2.4, cacheRead: 0.12, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
260
|
+
{ provider: "command-code", modelId: "tencent/hy3-paid", cost4: { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
261
|
+
{ provider: "command-code", modelId: "moonshotai/Kimi-K3", cost4: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
262
|
+
{ provider: "command-code", modelId: "moonshotai/Kimi-K2.7-Code", cost4: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
263
|
+
{ provider: "command-code", modelId: "moonshotai/Kimi-K2.7-Code-Highspeed", cost4: { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
264
|
+
{ provider: "command-code", modelId: "moonshotai/Kimi-K2.6", cost4: { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
265
|
+
{ provider: "command-code", modelId: "moonshotai/Kimi-K2.5", cost4: { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
266
|
+
{ provider: "command-code", modelId: "claude-fable-5", cost4: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
267
|
+
{ provider: "command-code", modelId: "claude-opus-5", cost4: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
268
|
+
{ provider: "command-code", modelId: "claude-opus-4-8", cost4: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
269
|
+
{ provider: "command-code", modelId: "claude-opus-4-7", cost4: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
270
|
+
{ provider: "command-code", modelId: "claude-sonnet-5", cost4: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
271
|
+
{ provider: "command-code", modelId: "claude-sonnet-4-6", cost4: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
272
|
+
{ provider: "command-code", modelId: "claude-haiku-4-5", cost4: { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
273
|
+
{ provider: "command-code", modelId: "gpt-5.6-sol", cost4: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
274
|
+
{ provider: "command-code", modelId: "gpt-5.6-terra", cost4: { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
275
|
+
{ provider: "command-code", modelId: "gpt-5.6-luna", cost4: { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
276
|
+
{ provider: "command-code", modelId: "gpt-5.5", cost4: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
277
|
+
{ provider: "command-code", modelId: "gpt-5.4", cost4: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
278
|
+
{ provider: "command-code", modelId: "gpt-5.4-mini", cost4: { input: 0.75, output: 4.5, cacheRead: 0.075, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
279
|
+
{ provider: "command-code", modelId: "gpt-5.3-codex", cost4: { input: 2, output: 8, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
280
|
+
{ provider: "command-code", modelId: "sakana/fugu-ultra", cost4: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
281
|
+
{ provider: "command-code", modelId: "xai/grok-4.6", cost4: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
282
|
+
{ provider: "command-code", modelId: "xai/grok-4.5", cost4: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
283
|
+
{ provider: "command-code", modelId: "thinkingmachines/inkling", cost4: { input: 1, output: 4.05, cacheRead: 0.17, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
284
|
+
{ provider: "command-code", modelId: "thinkingmachines/inkling-small", cost4: { input: 0.5, output: 1.2, cacheRead: 0.1, cacheWrite: 0 }, source: COMMAND_CODE_PRICING, verifiedAt: COMMAND_CODE_VERIFIED_AT, status: "verified" },
|
|
198
285
|
];
|
|
199
286
|
|
|
200
287
|
export function findVerifiedPriceOverride(
|
|
@@ -223,6 +310,8 @@ export function findExpectedPriceOverlay(
|
|
|
223
310
|
/** OpenAI Fast price multipliers retained as a compatibility export. */
|
|
224
311
|
export const PRIORITY_MULTIPLIERS: Readonly<Record<string, number>> = {
|
|
225
312
|
"gpt-5.6-sol": 2,
|
|
313
|
+
"gpt-daybreak-blue-latest": 2,
|
|
314
|
+
"daybreak-blue-latest": 2,
|
|
226
315
|
// Post-price-cut Fast tables (https://openai.com/api-fast-mode/, 2026-08-05):
|
|
227
316
|
// Terra 4/24/0.40/5 and Luna 0.40/2.40/0.04/0.50 are both 2× the corrected
|
|
228
317
|
// standard tuples; the stale bases made these look like 1.6/0.4 (#907).
|
|
@@ -257,13 +346,19 @@ const XAI_PRIORITY_PRICING = "https://docs.x.ai/developers/advanced-api-usage/pr
|
|
|
257
346
|
*/
|
|
258
347
|
export const PRIORITY_PRICING_RULES: readonly PriorityPricingRule[] = [
|
|
259
348
|
...["openai", "openai-apikey"].flatMap(provider =>
|
|
260
|
-
Object.entries(PRIORITY_MULTIPLIERS)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
349
|
+
Object.entries(PRIORITY_MULTIPLIERS)
|
|
350
|
+
// Daybreak's `gpt-` selector belongs to ChatGPT/Codex accounts; its bare selector belongs
|
|
351
|
+
// to the separately billed API-key catalog. All ordinary GPT ids remain valid on both.
|
|
352
|
+
.filter(([modelId]) => provider === "openai"
|
|
353
|
+
? modelId !== "daybreak-blue-latest"
|
|
354
|
+
: modelId !== "gpt-daybreak-blue-latest")
|
|
355
|
+
.map(([modelId, multiplier]): PriorityPricingRule => ({
|
|
356
|
+
provider,
|
|
357
|
+
modelId,
|
|
358
|
+
multiplier,
|
|
359
|
+
source: OPENAI_FAST_PRICING,
|
|
360
|
+
verifiedAt: "2026-08-05",
|
|
361
|
+
})),
|
|
267
362
|
),
|
|
268
363
|
...["grok-4.5", "grok-4.6"].map((modelId): PriorityPricingRule => ({
|
|
269
364
|
provider: "xai",
|
|
@@ -349,6 +444,29 @@ export const CONTEXT_TIERS: readonly ContextTier[] = [
|
|
|
349
444
|
verifiedAt: "2026-08-03",
|
|
350
445
|
})),
|
|
351
446
|
),
|
|
447
|
+
{
|
|
448
|
+
// The native Codex selector aliases gpt-5.6-sol and shares its 272k long-context tier.
|
|
449
|
+
provider: "openai",
|
|
450
|
+
modelId: "gpt-daybreak-blue-latest",
|
|
451
|
+
thresholdInputTokens: 272_000,
|
|
452
|
+
inclusive: false,
|
|
453
|
+
multiplier: OPENAI_LONG_CONTEXT,
|
|
454
|
+
confirmedPriorityRelation: "exclusive",
|
|
455
|
+
source: OPENAI_PRICING_DOC,
|
|
456
|
+
verifiedAt: "2026-08-11",
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
// The bare selector is the separately billed API-key alias. Daybreak Red has no tier row:
|
|
460
|
+
// the cyber snapshot's four long-context cells are all "-" on the pricing page.
|
|
461
|
+
provider: "openai-apikey",
|
|
462
|
+
modelId: "daybreak-blue-latest",
|
|
463
|
+
thresholdInputTokens: 272_000,
|
|
464
|
+
inclusive: false,
|
|
465
|
+
multiplier: OPENAI_LONG_CONTEXT,
|
|
466
|
+
confirmedPriorityRelation: "exclusive",
|
|
467
|
+
source: OPENAI_PRICING_DOC,
|
|
468
|
+
verifiedAt: "2026-08-11",
|
|
469
|
+
},
|
|
352
470
|
{
|
|
353
471
|
provider: "xai",
|
|
354
472
|
modelId: "grok-4.5",
|
|
@@ -371,22 +489,6 @@ export const CONTEXT_TIERS: readonly ContextTier[] = [
|
|
|
371
489
|
source: "https://docs.x.ai/developers/pricing",
|
|
372
490
|
verifiedAt: "2026-08-18",
|
|
373
491
|
},
|
|
374
|
-
{
|
|
375
|
-
// daybreak-blue-latest aliases gpt-5.6-sol, which publishes the full long-context row
|
|
376
|
-
// ($10 / $1 / $12.50 / $45). Scoped to openai-apikey ON PURPOSE: Daybreak is not
|
|
377
|
-
// routable on the Codex-login `openai` provider, so adding the alias to the shared
|
|
378
|
-
// OPENAI_GPT56_CONTEXT_MODELS list (expanded across both providers above) would mint a
|
|
379
|
-
// tier for a provider/model pair that cannot exist.
|
|
380
|
-
// daybreak-red-latest has NO tier row: the cyber snapshot's four long-context cells are
|
|
381
|
-
// all "-" on the pricing page (verified 2026-08-11).
|
|
382
|
-
provider: "openai-apikey",
|
|
383
|
-
modelId: "daybreak-blue-latest",
|
|
384
|
-
thresholdInputTokens: 272_000,
|
|
385
|
-
inclusive: false,
|
|
386
|
-
multiplier: OPENAI_LONG_CONTEXT,
|
|
387
|
-
source: OPENAI_PRICING_DOC,
|
|
388
|
-
verifiedAt: "2026-08-11",
|
|
389
|
-
},
|
|
390
492
|
...["minimax", "minimax-cn"].map((provider): ContextTier => ({
|
|
391
493
|
provider,
|
|
392
494
|
modelId: "MiniMax-M3",
|
package/src/usage/log.ts
CHANGED
|
@@ -13,6 +13,15 @@ import { CODEX_ACCOUNT_LOG_LABEL_RE } from "../codex/account-label";
|
|
|
13
13
|
export type UsageStatus = "reported" | "unreported" | "unsupported" | "estimated";
|
|
14
14
|
export type CodexUsageAccountLogLabel = "main" | `p${string}`;
|
|
15
15
|
|
|
16
|
+
export const OAUTH_ACCOUNT_LOG_LABEL_RE = /^[a-f0-9]{8,64}(?:-\d+)?$/;
|
|
17
|
+
|
|
18
|
+
export function isPersistableAccountLogLabel(value: unknown): value is string {
|
|
19
|
+
return (
|
|
20
|
+
value === "main"
|
|
21
|
+
|| (typeof value === "string" && (CODEX_ACCOUNT_LOG_LABEL_RE.test(value) || OAUTH_ACCOUNT_LOG_LABEL_RE.test(value)))
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
export function isCodexUsageAccountLogLabel(value: unknown): value is CodexUsageAccountLogLabel {
|
|
17
26
|
return value === "main" || (typeof value === "string" && CODEX_ACCOUNT_LOG_LABEL_RE.test(value));
|
|
18
27
|
}
|
|
@@ -30,6 +39,7 @@ export type AttemptRecoveryKind =
|
|
|
30
39
|
| "anthropic-oauth-429"
|
|
31
40
|
| "cursor-oauth-auth"
|
|
32
41
|
| "cursor-oauth-429"
|
|
42
|
+
| "oauth-account-429"
|
|
33
43
|
| "image-413"
|
|
34
44
|
| "opaque-blob-rejection"
|
|
35
45
|
| "empty-completion";
|
|
@@ -52,8 +62,8 @@ export interface PersistedUsageAttempt {
|
|
|
52
62
|
sendCount: number;
|
|
53
63
|
recoveryKinds: AttemptRecoveryKind[];
|
|
54
64
|
usageStatus: UsageStatus;
|
|
55
|
-
/** Stable non-PII identity for the
|
|
56
|
-
accountLogLabel?:
|
|
65
|
+
/** Stable non-PII identity for the account that served this attempt. */
|
|
66
|
+
accountLogLabel?: string;
|
|
57
67
|
inputTokenEstimate?: number;
|
|
58
68
|
usage?: OcxUsage;
|
|
59
69
|
totalTokens?: number;
|
|
@@ -70,6 +80,7 @@ export interface PersistedUsageAttempt {
|
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
export interface PersistedUsageEntry {
|
|
83
|
+
requestedAlias?: string;
|
|
73
84
|
requestId: string;
|
|
74
85
|
timestamp: number;
|
|
75
86
|
provider: string;
|
|
@@ -81,8 +92,8 @@ export interface PersistedUsageEntry {
|
|
|
81
92
|
admissionKind?: "configured" | "environment" | "loopback";
|
|
82
93
|
/** The inbound wire, not the client product — see `surface`. */
|
|
83
94
|
inboundProtocol?: "responses" | "chat" | "messages";
|
|
84
|
-
/** Stable non-PII identity for
|
|
85
|
-
accountLogLabel?:
|
|
95
|
+
/** Stable non-PII identity for the account that served this request. */
|
|
96
|
+
accountLogLabel?: string;
|
|
86
97
|
/** Best-effort chat/session correlation for Logs grouping (#330). */
|
|
87
98
|
conversationId?: string;
|
|
88
99
|
resolvedModel?: string;
|
|
@@ -220,8 +231,7 @@ const ATTEMPT_RECOVERY_KINDS = new Set<AttemptRecoveryKind>([
|
|
|
220
231
|
"key-429",
|
|
221
232
|
"rate-limit-429",
|
|
222
233
|
"anthropic-oauth-429",
|
|
223
|
-
"
|
|
224
|
-
"cursor-oauth-429",
|
|
234
|
+
"oauth-account-429",
|
|
225
235
|
"image-413",
|
|
226
236
|
"opaque-blob-rejection",
|
|
227
237
|
"empty-completion",
|
|
@@ -367,7 +377,7 @@ function normalizeUsageAttempt(raw: unknown): PersistedUsageAttempt | null {
|
|
|
367
377
|
sendCount: attempt.sendCount as number,
|
|
368
378
|
recoveryKinds,
|
|
369
379
|
usageStatus: attempt.usageStatus as UsageStatus,
|
|
370
|
-
...(
|
|
380
|
+
...(isPersistableAccountLogLabel(attempt.accountLogLabel)
|
|
371
381
|
? { accountLogLabel: attempt.accountLogLabel }
|
|
372
382
|
: {}),
|
|
373
383
|
...(isNonNegativeFiniteNumber(attempt.inputTokenEstimate)
|
|
@@ -454,7 +464,7 @@ function normalizeUsageEntry(entry: PersistedUsageEntry): PersistedUsageEntry {
|
|
|
454
464
|
: {}),
|
|
455
465
|
...(isKnownAdmissionKind(entry.admissionKind) ? { admissionKind: entry.admissionKind } : {}),
|
|
456
466
|
...(isKnownInboundProtocol(entry.inboundProtocol) ? { inboundProtocol: entry.inboundProtocol } : {}),
|
|
457
|
-
...(
|
|
467
|
+
...(isPersistableAccountLogLabel(entry.accountLogLabel)
|
|
458
468
|
? { accountLogLabel: entry.accountLogLabel }
|
|
459
469
|
: {}),
|
|
460
470
|
...(typeof entry.conversationId === "string" && entry.conversationId.trim()
|
package/src/usage/summary.ts
CHANGED
|
@@ -94,6 +94,7 @@ export interface UsageProvider {
|
|
|
94
94
|
|
|
95
95
|
export interface UsageAccount {
|
|
96
96
|
accountLogLabel: string;
|
|
97
|
+
provider?: string;
|
|
97
98
|
ambiguous: boolean;
|
|
98
99
|
requests: number;
|
|
99
100
|
attemptCount: number;
|
|
@@ -684,12 +685,25 @@ function legacyCodexAccountLabel(provider: string): string | null {
|
|
|
684
685
|
return suffix ?? LEGACY_AMBIGUOUS_ACCOUNT_LABEL;
|
|
685
686
|
}
|
|
686
687
|
|
|
687
|
-
function accountLabelForAttribution(
|
|
688
|
-
|
|
689
|
-
|
|
688
|
+
export function accountLabelForAttribution(
|
|
689
|
+
provider: string,
|
|
690
|
+
explicit: unknown,
|
|
691
|
+
fallbackAccountByProvider?: Record<string, string>,
|
|
692
|
+
): string | null {
|
|
693
|
+
if (typeof explicit === "string" && explicit.trim().length > 0) return explicit.trim();
|
|
694
|
+
const legacy = legacyCodexAccountLabel(provider);
|
|
695
|
+
if (legacy) return legacy;
|
|
696
|
+
const base = baseProviderLabel(provider);
|
|
697
|
+
if (fallbackAccountByProvider && fallbackAccountByProvider[base]) {
|
|
698
|
+
return fallbackAccountByProvider[base];
|
|
699
|
+
}
|
|
700
|
+
return null;
|
|
690
701
|
}
|
|
691
702
|
|
|
692
|
-
function buildAccounts(
|
|
703
|
+
function buildAccounts(
|
|
704
|
+
entries: PersistedUsageEntry[],
|
|
705
|
+
fallbackAccountByProvider?: Record<string, string>,
|
|
706
|
+
): UsageAccount[] {
|
|
693
707
|
const byLabel = new Map<string, UsageAccount>();
|
|
694
708
|
const requestIds = new Map<string, Set<string>>();
|
|
695
709
|
|
|
@@ -702,12 +716,13 @@ function buildAccounts(entries: PersistedUsageEntry[]): UsageAccount[] {
|
|
|
702
716
|
totalTokens?: number;
|
|
703
717
|
estimate: ReturnType<typeof estimateRequestCost>;
|
|
704
718
|
}): void => {
|
|
705
|
-
const label = accountLabelForAttribution(input.provider, input.accountLogLabel);
|
|
719
|
+
const label = accountLabelForAttribution(input.provider, input.accountLogLabel, fallbackAccountByProvider);
|
|
706
720
|
if (!label) return;
|
|
707
721
|
let row = byLabel.get(label);
|
|
708
722
|
if (!row) {
|
|
709
723
|
row = {
|
|
710
724
|
accountLogLabel: label,
|
|
725
|
+
provider: baseProviderLabel(input.provider),
|
|
711
726
|
ambiguous: label === LEGACY_AMBIGUOUS_ACCOUNT_LABEL,
|
|
712
727
|
requests: 0,
|
|
713
728
|
attemptCount: 0,
|
|
@@ -808,6 +823,7 @@ export function summarizeUsage(
|
|
|
808
823
|
range: UsageRange,
|
|
809
824
|
now: number,
|
|
810
825
|
surface: UsageSurface = "all",
|
|
826
|
+
fallbackAccountByProvider?: Record<string, string>,
|
|
811
827
|
): UsageSummary {
|
|
812
828
|
const { since } = rangeWindow(range, now);
|
|
813
829
|
const filteredEntries = entries.filter(entry => {
|
|
@@ -837,7 +853,7 @@ export function summarizeUsage(
|
|
|
837
853
|
days: buildDayGrid(range, since, now, filteredEntries),
|
|
838
854
|
models: buildModels(filteredEntries, totals.totalTokens),
|
|
839
855
|
providers: buildProviders(filteredEntries, totals.totalTokens),
|
|
840
|
-
accounts: buildAccounts(filteredEntries),
|
|
856
|
+
accounts: buildAccounts(filteredEntries, fallbackAccountByProvider),
|
|
841
857
|
};
|
|
842
858
|
}
|
|
843
859
|
|
|
@@ -869,12 +885,14 @@ function normalizeFilterValue(input: string | null | undefined): string | null {
|
|
|
869
885
|
*/
|
|
870
886
|
export function projectUsageSummary<T extends UsageSummary>(
|
|
871
887
|
summary: T,
|
|
872
|
-
filter: { provider?: string | null; model?: string | null },
|
|
888
|
+
filter: { provider?: string | null; model?: string | null; account?: string | null },
|
|
873
889
|
entries?: PersistedUsageEntry[],
|
|
890
|
+
fallbackAccountByProvider?: Record<string, string>,
|
|
874
891
|
): T & { filter?: UsageFilterEcho } {
|
|
875
892
|
const provider = normalizeFilterValue(filter.provider);
|
|
876
893
|
const model = normalizeFilterValue(filter.model);
|
|
877
|
-
|
|
894
|
+
const account = normalizeFilterValue(filter.account);
|
|
895
|
+
if (provider === null && model === null && account === null) return summary;
|
|
878
896
|
|
|
879
897
|
// Re-summarise from the entries the summary was built from, rather than
|
|
880
898
|
// projecting over its rows.
|
|
@@ -891,9 +909,13 @@ export function projectUsageSummary<T extends UsageSummary>(
|
|
|
891
909
|
//
|
|
892
910
|
// The entries are already in hand on every path that filters, so the honest
|
|
893
911
|
// computation is also the simple one.
|
|
894
|
-
const matches = (rowProvider: string, rowModel: string): boolean => {
|
|
912
|
+
const matches = (rowProvider: string, rowModel: string, rowAccount?: string | null): boolean => {
|
|
895
913
|
if (provider !== null && baseProviderLabel(rowProvider).toLowerCase() !== provider) return false;
|
|
896
914
|
if (model !== null && rowModel.toLowerCase() !== model) return false;
|
|
915
|
+
if (account !== null && rowAccount !== undefined) {
|
|
916
|
+
const effectiveAccount = accountLabelForAttribution(rowProvider, rowAccount, fallbackAccountByProvider);
|
|
917
|
+
if (!effectiveAccount || effectiveAccount.toLowerCase() !== account) return false;
|
|
918
|
+
}
|
|
897
919
|
return true;
|
|
898
920
|
};
|
|
899
921
|
|
|
@@ -909,10 +931,10 @@ export function projectUsageSummary<T extends UsageSummary>(
|
|
|
909
931
|
const filtered: PersistedUsageEntry[] = [];
|
|
910
932
|
for (const entry of source) {
|
|
911
933
|
if (!entry.attempts?.length) {
|
|
912
|
-
if (matches(entry.provider, antigravityUsageModel(entry.provider, entry.model))) filtered.push(entry);
|
|
934
|
+
if (matches(entry.provider, antigravityUsageModel(entry.provider, entry.model), entry.accountLogLabel)) filtered.push(entry);
|
|
913
935
|
continue;
|
|
914
936
|
}
|
|
915
|
-
const attempts = entry.attempts.filter(a => matches(a.provider, antigravityUsageModel(a.provider, a.model)));
|
|
937
|
+
const attempts = entry.attempts.filter(a => matches(a.provider, antigravityUsageModel(a.provider, a.model), a.accountLogLabel ?? entry.accountLogLabel));
|
|
916
938
|
if (attempts.length === 0) continue;
|
|
917
939
|
// A combo is still counted once per participating model, so a filtered
|
|
918
940
|
// request count can exceed the number of distinct requests. That is the
|
|
@@ -921,7 +943,7 @@ export function projectUsageSummary<T extends UsageSummary>(
|
|
|
921
943
|
filtered.push({ ...entry, attempts });
|
|
922
944
|
}
|
|
923
945
|
|
|
924
|
-
const projected = summarizeUsage(filtered, summary.range, summary.generatedAt, summary.surface);
|
|
946
|
+
const projected = summarizeUsage(filtered, summary.range, summary.generatedAt, summary.surface, fallbackAccountByProvider);
|
|
925
947
|
// matched reflects usage inside the requested WINDOW, not anywhere in the
|
|
926
948
|
// log: summarizeUsage applies the range and surface predicates, and the CLI
|
|
927
949
|
// uses this flag to decide between a table and "no usage recorded".
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
* Never throws; every error string passes redactSecretString.
|
|
10
10
|
*/
|
|
11
11
|
import { fetchWithResetRetry } from "../lib/upstream-retry";
|
|
12
|
-
import { signalWithTimeout } from "../lib/abort";
|
|
12
|
+
import { cancelBodyOnAbort, signalWithTimeout } from "../lib/abort";
|
|
13
|
+
import { readBoundedResponseBytes } from "../lib/bounded-body";
|
|
13
14
|
import { sidecarEnter } from "../lib/sidecar-tracker";
|
|
14
15
|
import { redactSecretString } from "../lib/redact";
|
|
15
|
-
import type
|
|
16
|
+
import { MAX_SIDECAR_RESPONSE_BYTES, type WebSearchSource } from "./parse";
|
|
16
17
|
import type { SidecarOutcome, SidecarSettings } from "./executor";
|
|
17
18
|
|
|
18
19
|
const EXA_SEARCH_URL = "https://api.exa.ai/search";
|
|
@@ -47,14 +48,44 @@ export async function runExaWebSearch(
|
|
|
47
48
|
}),
|
|
48
49
|
{ abortSignal: linkedSignal.signal, label: "exa-web-search-sidecar" },
|
|
49
50
|
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const detachBodyGuard = cancelBodyOnAbort(res.body, linkedSignal.signal);
|
|
52
|
+
try {
|
|
53
|
+
let bounded: Awaited<ReturnType<typeof readBoundedResponseBytes>> | null = null;
|
|
54
|
+
try {
|
|
55
|
+
bounded = await readBoundedResponseBytes(res, {
|
|
56
|
+
maxBytes: MAX_SIDECAR_RESPONSE_BYTES,
|
|
57
|
+
signal: linkedSignal.signal,
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
const reason = linkedSignal.signal.reason;
|
|
61
|
+
if (linkedSignal.signal.aborted && reason instanceof Error && reason.name === "TimeoutError") {
|
|
62
|
+
throw reason;
|
|
63
|
+
}
|
|
64
|
+
// Preserve the previous status-only/shapeless fallback for body read
|
|
65
|
+
// failures; fetch/header failures are still classified by the outer catch.
|
|
66
|
+
}
|
|
67
|
+
if (bounded?.oversized) {
|
|
68
|
+
const prefix = res.ok ? "exa sidecar response" : `exa sidecar HTTP ${res.status} response`;
|
|
69
|
+
return { text: "", sources: [], error: `${prefix} exceeded byte bound` };
|
|
70
|
+
}
|
|
71
|
+
// Response.text()/json() replace malformed UTF-8, so preserve that
|
|
72
|
+
// behavior while moving the byte bound ahead of decoding and parsing.
|
|
73
|
+
const text = bounded ? new TextDecoder().decode(bounded.bytes) : "";
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
// Scrub BEFORE truncating: slicing first can cut the literal key at the
|
|
76
|
+
// boundary, leaving an unscrubbable key prefix in the surviving text.
|
|
77
|
+
return { text: "", sources: [], error: `exa sidecar HTTP ${res.status}: ${scrub(text).slice(0, 200)}` };
|
|
78
|
+
}
|
|
79
|
+
let payload: unknown = null;
|
|
80
|
+
try {
|
|
81
|
+
payload = JSON.parse(text);
|
|
82
|
+
} catch {
|
|
83
|
+
// The mapper owns the stable malformed/empty JSON outcome.
|
|
84
|
+
}
|
|
85
|
+
return mapExaSearchResponse(payload);
|
|
86
|
+
} finally {
|
|
87
|
+
detachBodyGuard();
|
|
55
88
|
}
|
|
56
|
-
const payload = await res.json().catch(() => null);
|
|
57
|
-
return mapExaSearchResponse(payload);
|
|
58
89
|
} catch (e) {
|
|
59
90
|
const kind = e instanceof Error && e.name === "TimeoutError" ? "timeout" : "connect_error";
|
|
60
91
|
console.warn(`[web-search] exa sidecar ${kind} (${Date.now() - t0}ms)`);
|
package/src/web-search/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { validateXaiSearchOptions, type XaiSearchOptions } from "./xai-executor"
|
|
|
9
9
|
import type { OcxWebSearchSidecarConfig } from "../types";
|
|
10
10
|
import { DEFAULT_STALL_TIMEOUT_SEC } from "../stall-timeout";
|
|
11
11
|
import { buildWebSearchTool, extractHostedWebSearch, WEB_SEARCH_TOOL_NAME } from "./synthetic-tool";
|
|
12
|
+
import { estimateInputTokens } from "../server/responses/input-admission";
|
|
12
13
|
|
|
13
14
|
export { runWithWebSearch } from "./loop";
|
|
14
15
|
export { buildWebSearchTool, extractHostedWebSearch, WEB_SEARCH_TOOL_NAME };
|
|
@@ -44,13 +45,19 @@ const STALL_MARGIN_SEC = 30;
|
|
|
44
45
|
* deliberately permissive, so malformed values fall back locally without rejecting or rewriting
|
|
45
46
|
* the caller's config object.
|
|
46
47
|
*/
|
|
47
|
-
export function resolveRoutedModelStallTimeoutMs(value: unknown): number {
|
|
48
|
-
|
|
48
|
+
export function resolveRoutedModelStallTimeoutMs(value: unknown, estimatedInputTokens?: number): number {
|
|
49
|
+
if (typeof value === "number"
|
|
49
50
|
&& Number.isInteger(value)
|
|
50
51
|
&& value >= 1
|
|
51
|
-
&& value <= MAX_ROUTED_MODEL_STALL_TIMEOUT_MS
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
&& value <= MAX_ROUTED_MODEL_STALL_TIMEOUT_MS) {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
const base = DEFAULT_ROUTED_MODEL_STALL_TIMEOUT_MS;
|
|
56
|
+
if (typeof estimatedInputTokens === "number" && Number.isFinite(estimatedInputTokens) && estimatedInputTokens > 100_000) {
|
|
57
|
+
const extraBlocks = Math.ceil((estimatedInputTokens - 100_000) / 100_000);
|
|
58
|
+
return Math.min(MAX_ROUTED_MODEL_STALL_TIMEOUT_MS, base + extraBlocks * 60_000);
|
|
59
|
+
}
|
|
60
|
+
return base;
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
function finiteCeil(value: number | undefined, fallback: number): number {
|
|
@@ -305,9 +312,10 @@ export function planWebSearch(
|
|
|
305
312
|
const cfg = config.webSearchSidecar ?? {};
|
|
306
313
|
if (cfg.enabled === false) return undefined;
|
|
307
314
|
const timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
const
|
|
315
|
+
const safeModelId = typeof modelId === "string" ? modelId : "";
|
|
316
|
+
const estimatedInputTokens = estimateInputTokens(parsed, safeModelId);
|
|
317
|
+
const routedModelStallTimeoutMs = resolveRoutedModelStallTimeoutMs(cfg.routedModelStallTimeoutMs, estimatedInputTokens);
|
|
318
|
+
const connectTimeoutMs = config.connectTimeoutMs ?? Math.max(200_000, routedModelStallTimeoutMs);
|
|
311
319
|
// Shared auth state (#2188): presence only — backend PREFERENCE stays with
|
|
312
320
|
// resolveSidecarBackend's explicit-or-openai contract.
|
|
313
321
|
const auth = resolveSidecarAuth(config);
|
package/src/web-search/loop.ts
CHANGED
|
@@ -318,10 +318,11 @@ export interface WebSearchLoopDeps {
|
|
|
318
318
|
/** Called before each routed-model dispatch in the loop, for attempt telemetry. Same-target 429 replays pass the `rate-limit-429` recovery kind. */
|
|
319
319
|
onAttemptSend?: (recovery?: AttemptRecoveryKind) => void;
|
|
320
320
|
/**
|
|
321
|
-
* 429
|
|
322
|
-
* or null when the pool is exhausted
|
|
321
|
+
* 429 failover hook: rotate the provider's active credential and return a rebuilt adapter,
|
|
322
|
+
* or null when the pool is exhausted. Async hooks support OAuth refresh; existing synchronous
|
|
323
|
+
* key-pool hooks remain valid.
|
|
323
324
|
*/
|
|
324
|
-
on429?: (retryAfterHeader: string | null) => ProviderAdapter | null
|
|
325
|
+
on429?: (retryAfterHeader: string | null) => ProviderAdapter | null | Promise<ProviderAdapter | null>;
|
|
325
326
|
/** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */
|
|
326
327
|
retryOn429Policy?: Required<RateLimitRetryPolicy> | null;
|
|
327
328
|
/** Called only when the final bridged Responses stream reaches completed or incomplete. */
|
|
@@ -529,7 +530,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
529
530
|
// 429 key-failover parity with the normal routed path: rotate pool keys until one responds
|
|
530
531
|
// or the pool is exhausted (deps.on429 returns null — cooldown map guarantees termination).
|
|
531
532
|
while (prepared.response.status === 429 && deps.on429) {
|
|
532
|
-
const rotated = deps.on429(prepared.response.headers.get("retry-after"));
|
|
533
|
+
const rotated = await deps.on429(prepared.response.headers.get("retry-after"));
|
|
533
534
|
if (!rotated) break;
|
|
534
535
|
// Never let a broken body's cancel promise outlive the cumulative header deadline. Observe
|
|
535
536
|
// it, but proceed immediately to the rotated fetch under the SAME deadline signal.
|