@bitkyc08/opencodex 2.10.0 → 2.10.1
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/AGENTS_INSTALL.md +77 -0
- package/README.md +4 -10
- package/bin/ocx.mjs +71 -18
- package/gui/dist/assets/index-Cd6_PBKn.css +1 -0
- package/gui/dist/assets/index-ChZQsmBY.js +70 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +8 -4
- package/src/adapters/anthropic.ts +208 -14
- package/src/adapters/base.ts +16 -5
- package/src/adapters/cursor/effort-map.ts +3 -2
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/live-transport.ts +105 -95
- package/src/adapters/cursor/native-exec.ts +32 -6
- package/src/adapters/cursor/protobuf-request.ts +20 -15
- package/src/adapters/cursor/request-builder.ts +21 -7
- package/src/adapters/cursor/types.ts +7 -0
- package/src/adapters/google-antigravity-replay.ts +237 -21
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +50 -9
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +10 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +37 -11
- package/src/adapters/openai-chat.ts +284 -83
- package/src/adapters/openai-responses.ts +182 -24
- package/src/bridge.ts +177 -7
- package/src/chat/outbound.ts +78 -23
- package/src/claude/agents-inject.ts +27 -5
- package/src/claude/inbound.ts +11 -1
- package/src/claude/model-info.ts +13 -10
- package/src/claude/outbound.ts +17 -0
- package/src/cli/account-api.ts +24 -0
- package/src/cli/account-auth.ts +31 -6
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +5 -0
- package/src/cli/claude.ts +2 -1
- package/src/cli/doctor.ts +93 -22
- package/src/cli/export-command.ts +26 -12
- package/src/cli/help.ts +8 -6
- package/src/cli/index.ts +56 -22
- package/src/cli/integrations.ts +84 -1
- package/src/cli/observe.ts +54 -1
- package/src/cli/opencode.ts +2 -1
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +1 -1
- package/src/cli/v2.ts +36 -9
- package/src/clients/config-export.ts +687 -10
- package/src/codex/account-lifecycle.ts +30 -5
- package/src/codex/account-usability.ts +22 -2
- package/src/codex/admission.ts +255 -0
- package/src/codex/auth-api.ts +427 -140
- package/src/codex/auth-context.ts +155 -30
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +62 -0
- package/src/codex/catalog/aggregation.ts +14 -1
- package/src/codex/catalog/bundled.ts +282 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/metadata.ts +51 -6
- package/src/codex/catalog/parsing.ts +6 -3
- package/src/codex/catalog/provider-fetch.ts +576 -41
- package/src/codex/catalog/sync.ts +505 -66
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-write-serialization.ts +241 -0
- package/src/codex/catalog.ts +2 -1
- package/src/codex/codex-write-lock.ts +372 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +441 -0
- package/src/codex/desired-state.ts +177 -0
- package/src/codex/features.ts +52 -8
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +257 -0
- package/src/codex/history-lock.ts +241 -0
- package/src/codex/history-migration-guardian.ts +18 -5
- package/src/codex/history-provider.ts +9 -2
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +176 -0
- package/src/codex/inject-coordination.ts +245 -0
- package/src/codex/inject.ts +605 -124
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +10 -1
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +167 -0
- package/src/codex/native-main-lock-file.ts +158 -0
- package/src/codex/native-main-owner.ts +315 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1512 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +340 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +557 -0
- package/src/codex/project-config-warnings.ts +18 -4
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +86 -3
- package/src/codex/routing.ts +299 -62
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +39 -13
- package/src/codex/subagent-model-fallback.ts +73 -12
- package/src/codex/transition-state.ts +604 -0
- package/src/codex/upstream-host-health.ts +70 -0
- package/src/codex/user-identity.ts +266 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/config.ts +562 -26
- package/src/generated/jawcode-model-metadata.ts +2 -2
- package/src/grok/inject.ts +15 -4
- package/src/grok/inspect.ts +45 -0
- package/src/images/loop.ts +113 -20
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +165 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +101 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/bounded-body.ts +46 -8
- package/src/lib/bun-runtime.ts +110 -1
- package/src/lib/bun-stream-caps.ts +2 -1
- package/src/lib/redact.ts +407 -2
- package/src/lib/shadow-call.ts +24 -0
- package/src/lib/translator-budget.ts +10 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +154 -2
- package/src/lib/windows-secret-acl.ts +212 -11
- package/src/lib/winsw.ts +9 -3
- package/src/oauth/index.ts +61 -3
- package/src/oauth/key-providers.ts +4 -0
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/store.ts +31 -6
- package/src/oauth/token-guardian.ts +9 -3
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/derive.ts +33 -1
- package/src/providers/free-directory.ts +3 -1
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/openai-sidecar.ts +64 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/quota.ts +334 -26
- package/src/providers/registry.ts +284 -16
- package/src/providers/xai-transport.ts +11 -4
- package/src/responses/compaction.ts +8 -1
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +44 -2
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +105 -0
- package/src/responses/spill-store.ts +45 -8
- package/src/responses/state.ts +161 -17
- package/src/router.ts +302 -16
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +204 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +590 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile.ts +423 -0
- package/src/routing/quota.ts +124 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/auth-cors.ts +46 -6
- package/src/server/chat-completions.ts +28 -13
- package/src/server/claude-messages.ts +23 -15
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +10 -1
- package/src/server/index.ts +238 -52
- package/src/server/lifecycle.ts +228 -9
- package/src/server/live.ts +14 -3
- package/src/server/management/agent-settings-routes.ts +64 -14
- package/src/server/management/combo-routes.ts +5 -5
- package/src/server/management/config-routes.ts +1 -1
- package/src/server/management/context.ts +42 -2
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +1 -1
- package/src/server/management/model-routes.ts +32 -113
- package/src/server/management/model-rows.ts +117 -0
- package/src/server/management/native-integration-routes.ts +587 -0
- package/src/server/management/oauth-account-routes.ts +1 -1
- package/src/server/management/provider-routes.ts +218 -117
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +177 -0
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +276 -24
- package/src/server/management/system-routes.ts +4 -0
- package/src/server/management-api.ts +84 -9
- package/src/server/management-auth.ts +43 -5
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +120 -6
- package/src/server/request-log.ts +26 -6
- package/src/server/responses/collaboration.ts +63 -8
- package/src/server/responses/compact.ts +272 -41
- package/src/server/responses/core.ts +730 -132
- package/src/server/responses/fetch-helpers.ts +15 -1
- package/src/server/responses-item-id-repair.ts +32 -3
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/search.ts +51 -6
- package/src/server/sse-payload-rewrite.ts +89 -12
- package/src/server/startup-health-cache.ts +7 -1
- package/src/server/ws-bridge.ts +11 -17
- package/src/service-manager-probe.ts +297 -0
- package/src/service.ts +222 -32
- package/src/tray/windows-tray.ps1 +9 -0
- package/src/tray/windows.ts +15 -7
- package/src/types.ts +194 -14
- package/src/update/index.ts +13 -13
- package/src/update/job.ts +24 -21
- package/src/update/notify.ts +7 -3
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +129 -10
- package/src/usage/log.ts +50 -15
- package/src/usage/summary.ts +4 -4
- package/src/vision/index.ts +6 -1
- package/src/web-search/loop.ts +161 -34
- package/gui/dist/assets/index-OY43ubAq.css +0 -1
- package/gui/dist/assets/index-YwNnKZcL.js +0 -67
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
|
@@ -30,6 +30,9 @@ export interface ExpectedPriceOverlay {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const GEMINI_31_PRO: Cost4 = { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 0 };
|
|
33
|
+
const GPT56_SOL: Cost4 = { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 };
|
|
34
|
+
const GPT56_TERRA: Cost4 = { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 };
|
|
35
|
+
const GPT56_LUNA: Cost4 = { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 };
|
|
33
36
|
const GEMINI_36_FLASH: Cost4 = { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 };
|
|
34
37
|
const MINIMAX_M21_HIGHSPEED: Cost4 = { input: 0.6, output: 2.4, cacheRead: 0.03, cacheWrite: 0.375 };
|
|
35
38
|
const KIMI_K3: Cost4 = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3 };
|
|
@@ -37,7 +40,7 @@ const KIMI_K27_CODE: Cost4 = { input: 0.95, output: 4, cacheRead: 0.19, cacheWri
|
|
|
37
40
|
const KIMI_K27_CODE_HIGHSPEED: Cost4 = { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 1.9 };
|
|
38
41
|
const KIMI_K26: Cost4 = { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0.95 };
|
|
39
42
|
const KIMI_K25: Cost4 = { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0.6 };
|
|
40
|
-
const
|
|
43
|
+
const QWEN38_MAX: Cost4 = { input: 2, output: 6, cacheRead: 0, cacheWrite: 0 };
|
|
41
44
|
// Anthropic official list prices (USD / 1M tokens). Cache write uses the published 5-minute rate.
|
|
42
45
|
const CLAUDE_SONNET_46: Cost4 = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 };
|
|
43
46
|
const CLAUDE_OPUS_46: Cost4 = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 };
|
|
@@ -50,13 +53,19 @@ const ANTHROPIC_PRICING = "https://platform.claude.com/docs/en/about-claude/pric
|
|
|
50
53
|
|
|
51
54
|
const GEMINI_PRICING = "https://ai.google.dev/gemini-api/docs/pricing (2026-07-22); cacheWrite=0: storage is billed per-hour, not per-token";
|
|
52
55
|
const MINIMAX_PRICING = "https://platform.minimax.io/docs/guides/pricing-paygo";
|
|
56
|
+
const OPENAI_GPT56_PRICING = "https://developers.openai.com/api/docs/pricing";
|
|
53
57
|
const DEEPSEEK_PRICING = "https://api-docs.deepseek.com/quick_start/pricing-details-usd; V4 Flash alias transition scheduled 2026-07-24 — re-verify after";
|
|
54
58
|
// Kimi official tables publish input/output/cache-hit only; cacheWrite is mapped to the
|
|
55
59
|
// cache-miss input price (Kimi auto-caches with no separate write billing). 2026-07-20 re-verified.
|
|
56
60
|
const KIMI_PRICING = "https://platform.kimi.ai/docs/pricing (official table; cacheWrite derived = input, Kimi auto-cache has no write billing)";
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
61
|
+
// 260804: Qwen3.8-Max shipped as a stable model and Qwen published a per-token rate, which
|
|
62
|
+
// is the exit condition the previous Routeway reseller overlay named. Two caveats are
|
|
63
|
+
// deliberately in the source string rather than dropped: the figure comes from Qwen's own
|
|
64
|
+
// release announcement, NOT from an Alibaba Model Studio billing table (which still lists
|
|
65
|
+
// qwen3.7-max and qwen3-max but has no qwen3.8-max row), and no cache rate is published
|
|
66
|
+
// anywhere. Cache stays 0 rather than inheriting the reseller's 0.15 — a reseller number
|
|
67
|
+
// under a vendor-price label would be a wrong value wearing a verified badge.
|
|
68
|
+
const QWEN38_MAX_PRICING = "https://qwen.ai/blog?id=qwen3.8 (Qwen release announcement; no Model Studio billing row yet; cache rates unpublished -> 0)";
|
|
60
69
|
|
|
61
70
|
export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
62
71
|
// claude-opus-5 is exposed by three providers but absent from the jawcode bundle, so
|
|
@@ -77,6 +86,14 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
77
86
|
// base model's standard rate per the official Billing FAQ).
|
|
78
87
|
{ provider: "google-antigravity", modelId: "gemini-3.6-flash", cost4: GEMINI_36_FLASH, source: `collapsed base ID ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified" },
|
|
79
88
|
{ provider: "google-antigravity", modelId: "gemini-3.1-pro", cost4: GEMINI_31_PRO, source: `collapsed base ID ${GEMINI_PRICING}`, verifiedAt: "2026-07-22", status: "verified" },
|
|
89
|
+
// OpenAI GPT-5.6 `-pro` virtual selections. The virtual resolver keeps the SELECTED id in
|
|
90
|
+
// the usage log and records the wire model separately, and cost resolution deliberately
|
|
91
|
+
// does not fall back through resolvedModel — so without these rows every `-pro` request
|
|
92
|
+
// resolved to null and rendered no cost estimate at all (#908 audit, runtime-verified).
|
|
93
|
+
// Pro reasoning bills at the base model's published API rate; the suffix is an effort knob.
|
|
94
|
+
{ 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" },
|
|
95
|
+
{ 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" },
|
|
96
|
+
{ 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" },
|
|
80
97
|
{ 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" },
|
|
81
98
|
{ provider: "google-antigravity", modelId: "gemini-3.1-pro-high", cost4: GEMINI_31_PRO, source: `derived: gemini-3.1-pro (<=200k tier) ${GEMINI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
|
|
82
99
|
{ provider: "google-antigravity", modelId: "gemini-pro-agent", cost4: GEMINI_31_PRO, source: `wire id for gemini-3.1-pro high ${GEMINI_PRICING}`, verifiedAt: "2026-07-23", status: "verified-derived" },
|
|
@@ -120,10 +137,10 @@ export const EXPECTED_PRICE_OVERLAYS: readonly ExpectedPriceOverlay[] = [
|
|
|
120
137
|
{ provider: "kimi-code", modelId: "kimi-k2.6", cost4: KIMI_K26, source: KIMI_PRICING, verifiedAt: "2026-07-20", status: "verified-derived" },
|
|
121
138
|
{ provider: "kimi-code", modelId: "kimi-k2.5", cost4: KIMI_K25, source: KIMI_PRICING, verifiedAt: "2026-07-20", status: "verified-derived" },
|
|
122
139
|
{ provider: "kimi-code", modelId: "kimi-for-coding", cost4: KIMI_K27_CODE, source: `derived: kimi-k2.7-code ${KIMI_PRICING}`, verifiedAt: "2026-07-20", status: "verified-derived" },
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
{ provider: "alibaba-token-plan", modelId: "qwen3.8-max
|
|
126
|
-
{ provider: "alibaba-token-plan-intl", modelId: "qwen3.8-max
|
|
140
|
+
// Qwen3.8-Max: vendor-published input/output rate (verified). See QWEN38_MAX_PRICING
|
|
141
|
+
// for what that source does and does not cover.
|
|
142
|
+
{ provider: "alibaba-token-plan", modelId: "qwen3.8-max", cost4: QWEN38_MAX, source: QWEN38_MAX_PRICING, verifiedAt: "2026-08-04", status: "verified" },
|
|
143
|
+
{ provider: "alibaba-token-plan-intl", modelId: "qwen3.8-max", cost4: QWEN38_MAX, source: QWEN38_MAX_PRICING, verifiedAt: "2026-08-04", status: "verified" },
|
|
127
144
|
// Cursor Auto router — Cursor's published fixed token price (verified).
|
|
128
145
|
{ 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" },
|
|
129
146
|
];
|
|
@@ -151,8 +168,11 @@ export function findExpectedPriceOverlay(
|
|
|
151
168
|
*/
|
|
152
169
|
export const PRIORITY_MULTIPLIERS: Readonly<Record<string, number>> = {
|
|
153
170
|
"gpt-5.6-sol": 2,
|
|
154
|
-
|
|
155
|
-
|
|
171
|
+
// Post-price-cut Fast tables (https://openai.com/api-fast-mode/, 2026-08-05):
|
|
172
|
+
// Terra 4/24/0.40/5 and Luna 0.40/2.40/0.04/0.50 are both 2× the corrected
|
|
173
|
+
// standard tuples; the stale bases made these look like 1.6/0.4 (#907).
|
|
174
|
+
"gpt-5.6-terra": 2,
|
|
175
|
+
"gpt-5.6-luna": 2,
|
|
156
176
|
"gpt-5.5": 2.5,
|
|
157
177
|
"gpt-5.4-mini": 2,
|
|
158
178
|
"gpt-5.4": 2,
|
|
@@ -162,3 +182,102 @@ export const PRIORITY_MULTIPLIERS: Readonly<Record<string, number>> = {
|
|
|
162
182
|
export function resolvePriorityMultiplier(modelId: string): number {
|
|
163
183
|
return PRIORITY_MULTIPLIERS[modelId] ?? 1;
|
|
164
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Long-context pricing tiers (#908). Several vendors reprice the ENTIRE request
|
|
188
|
+
* once the prompt crosses a published input-token threshold, so a flat Cost4
|
|
189
|
+
* cannot express it.
|
|
190
|
+
*
|
|
191
|
+
* The threshold is measured on RAW `usage.inputTokens` (total prompt size,
|
|
192
|
+
* including cache reads/writes) — never on normalized billable input, which has
|
|
193
|
+
* already had cache tokens subtracted. A 280k prompt with a 200k cache read has
|
|
194
|
+
* 80k billable input and still crosses OpenAI's 272k boundary; deciding after
|
|
195
|
+
* normalization would under-bill exactly the cache-heavy long requests.
|
|
196
|
+
*
|
|
197
|
+
* Rules are exact provider+model matches. No case folding: the jawcode bundle
|
|
198
|
+
* carries BOTH `minimax-m3` and `MiniMax-M3` at different rates, so folding
|
|
199
|
+
* would select the wrong base row. No model-level fallback: routed resellers
|
|
200
|
+
* (Cursor, OpenRouter) share model slugs but price independently.
|
|
201
|
+
*/
|
|
202
|
+
export interface ContextTier {
|
|
203
|
+
provider: string;
|
|
204
|
+
modelId: string;
|
|
205
|
+
/** Long rates apply once raw input tokens pass this boundary. */
|
|
206
|
+
thresholdInputTokens: number;
|
|
207
|
+
/** true = `>=` threshold (xAI), false = `>` threshold (OpenAI, MiniMax). */
|
|
208
|
+
inclusive: boolean;
|
|
209
|
+
/** Per-field factor from the short rate to the published long rate. */
|
|
210
|
+
multiplier: Cost4;
|
|
211
|
+
source: string;
|
|
212
|
+
verifiedAt: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* OpenAI GPT-5.6: "Prompts with >272K input tokens are priced at 2x input and
|
|
217
|
+
* 1.5x output for the full request." Cached input and cache writes also double,
|
|
218
|
+
* per the published short/long columns.
|
|
219
|
+
*/
|
|
220
|
+
const OPENAI_LONG_CONTEXT: Cost4 = { input: 2, output: 1.5, cacheRead: 2, cacheWrite: 2 };
|
|
221
|
+
/** xAI and MiniMax double every rate uniformly past their thresholds. */
|
|
222
|
+
const UNIFORM_DOUBLE: Cost4 = { input: 2, output: 2, cacheRead: 2, cacheWrite: 2 };
|
|
223
|
+
|
|
224
|
+
const OPENAI_PRICING_DOC = "https://developers.openai.com/api/docs/pricing";
|
|
225
|
+
const OPENAI_GPT56_CONTEXT_MODELS = [
|
|
226
|
+
"gpt-5.6-sol",
|
|
227
|
+
"gpt-5.6-terra",
|
|
228
|
+
"gpt-5.6-luna",
|
|
229
|
+
// Virtual `-pro` selections keep their own id in usage logs (the wire model is
|
|
230
|
+
// recorded separately), so they need their own rows or they silently skip the tier.
|
|
231
|
+
"gpt-5.6-sol-pro",
|
|
232
|
+
"gpt-5.6-terra-pro",
|
|
233
|
+
"gpt-5.6-luna-pro",
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
export const CONTEXT_TIERS: readonly ContextTier[] = [
|
|
237
|
+
...["openai", "openai-apikey"].flatMap(provider =>
|
|
238
|
+
OPENAI_GPT56_CONTEXT_MODELS.map((modelId): ContextTier => ({
|
|
239
|
+
provider,
|
|
240
|
+
modelId,
|
|
241
|
+
thresholdInputTokens: 272_000,
|
|
242
|
+
inclusive: false,
|
|
243
|
+
multiplier: OPENAI_LONG_CONTEXT,
|
|
244
|
+
source: OPENAI_PRICING_DOC,
|
|
245
|
+
verifiedAt: "2026-08-03",
|
|
246
|
+
})),
|
|
247
|
+
),
|
|
248
|
+
{
|
|
249
|
+
provider: "xai",
|
|
250
|
+
modelId: "grok-4.5",
|
|
251
|
+
thresholdInputTokens: 200_000,
|
|
252
|
+
inclusive: true,
|
|
253
|
+
multiplier: UNIFORM_DOUBLE,
|
|
254
|
+
source: "https://docs.x.ai/developers/pricing",
|
|
255
|
+
verifiedAt: "2026-08-03",
|
|
256
|
+
},
|
|
257
|
+
...["minimax", "minimax-cn"].map((provider): ContextTier => ({
|
|
258
|
+
provider,
|
|
259
|
+
modelId: "MiniMax-M3",
|
|
260
|
+
thresholdInputTokens: 512_000,
|
|
261
|
+
inclusive: false,
|
|
262
|
+
multiplier: UNIFORM_DOUBLE,
|
|
263
|
+
source: "https://platform.minimax.io/docs/guides/pricing-paygo",
|
|
264
|
+
verifiedAt: "2026-08-03",
|
|
265
|
+
})),
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
/** Exact provider+model context-tier lookup. No fuzzy matching, no case folding. */
|
|
269
|
+
export function findContextTier(
|
|
270
|
+
provider: string,
|
|
271
|
+
modelId: string,
|
|
272
|
+
tiers: readonly ContextTier[] = CONTEXT_TIERS,
|
|
273
|
+
): ContextTier | undefined {
|
|
274
|
+
return tiers.find(tier => tier.provider === provider && tier.modelId === modelId);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Whether a raw input-token count crosses the tier's published boundary. */
|
|
278
|
+
export function isLongContext(tier: ContextTier, rawInputTokens: number): boolean {
|
|
279
|
+
if (!Number.isFinite(rawInputTokens)) return false;
|
|
280
|
+
return tier.inclusive
|
|
281
|
+
? rawInputTokens >= tier.thresholdInputTokens
|
|
282
|
+
: rawInputTokens > tier.thresholdInputTokens;
|
|
283
|
+
}
|
package/src/usage/log.ts
CHANGED
|
@@ -4,14 +4,20 @@ import { getConfigDir } from "../config";
|
|
|
4
4
|
import { recordOwnedConfigPath } from "../lib/config-ownership";
|
|
5
5
|
import { usageDisplayTotalTokens } from "./totals";
|
|
6
6
|
import type { OcxUsage } from "../types";
|
|
7
|
+
import { normalizeRouteDecisionTrace, type RouteDecisionTraceV1 } from "../routing/trace";
|
|
7
8
|
|
|
8
9
|
export type UsageStatus = "reported" | "unreported" | "unsupported" | "estimated";
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Recovery kinds recorded per attempt in the usage log; the GUI renders localized labels
|
|
13
|
+
* for these wire values.
|
|
14
|
+
*/
|
|
10
15
|
export type AttemptRecoveryKind =
|
|
11
16
|
| "transient-5xx"
|
|
12
17
|
| "connection-reset"
|
|
13
18
|
| "oauth-401"
|
|
14
19
|
| "key-429"
|
|
20
|
+
| "rate-limit-429"
|
|
15
21
|
| "anthropic-oauth-429"
|
|
16
22
|
| "image-413";
|
|
17
23
|
|
|
@@ -35,7 +41,7 @@ export interface PersistedUsageAttempt {
|
|
|
35
41
|
requestedEffort?: string;
|
|
36
42
|
effectiveEffort?: string;
|
|
37
43
|
reasoningWireField?: string;
|
|
38
|
-
reasoningWireValue?: string | number;
|
|
44
|
+
reasoningWireValue?: string | number | boolean;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
export interface PersistedUsageEntry {
|
|
@@ -59,7 +65,7 @@ export interface PersistedUsageEntry {
|
|
|
59
65
|
/** Adapter-normalized tier and exact upstream parameter emitted for this request. */
|
|
60
66
|
effectiveEffort?: string;
|
|
61
67
|
reasoningWireField?: string;
|
|
62
|
-
reasoningWireValue?: string | number;
|
|
68
|
+
reasoningWireValue?: string | number | boolean;
|
|
63
69
|
requestedServiceTier?: string;
|
|
64
70
|
requestedSpeedLabel?: string;
|
|
65
71
|
configuredServiceTier?: string;
|
|
@@ -81,6 +87,12 @@ export interface PersistedUsageEntry {
|
|
|
81
87
|
closeReason?: "terminal" | "client_cancel" | "non_stream" | "body_stall" | "body_overflow";
|
|
82
88
|
/** Already redacted + capped at capture (request-log.ts redactSecretString().slice(0,500)). */
|
|
83
89
|
upstreamError?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Bounded route-decision trace (RI-01): why this provider/model/account was
|
|
92
|
+
* selected. Additive field; old rows without it parse unchanged. Never
|
|
93
|
+
* contains prompts, credentials, or hidden reasoning.
|
|
94
|
+
*/
|
|
95
|
+
routeDecision?: RouteDecisionTraceV1;
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
const KNOWN_USAGE_SURFACES = new Set<NonNullable<PersistedUsageEntry["surface"]>>([
|
|
@@ -173,6 +185,7 @@ const ATTEMPT_RECOVERY_KINDS = new Set<AttemptRecoveryKind>([
|
|
|
173
185
|
"connection-reset",
|
|
174
186
|
"oauth-401",
|
|
175
187
|
"key-429",
|
|
188
|
+
"rate-limit-429",
|
|
176
189
|
"anthropic-oauth-429",
|
|
177
190
|
"image-413",
|
|
178
191
|
]);
|
|
@@ -268,14 +281,29 @@ function normalizeUsageAttempt(raw: unknown): PersistedUsageAttempt | null {
|
|
|
268
281
|
...(typeof attempt.reasoningWireField === "string" && attempt.reasoningWireField
|
|
269
282
|
? { reasoningWireField: capMetadataString(attempt.reasoningWireField) }
|
|
270
283
|
: {}),
|
|
271
|
-
...(
|
|
272
|
-
?
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
284
|
+
...(isValidReasoningWireValue(attempt.reasoningWireField, attempt.reasoningWireValue)
|
|
285
|
+
? typeof attempt.reasoningWireValue === "string"
|
|
286
|
+
? { reasoningWireValue: capMetadataString(attempt.reasoningWireValue) }
|
|
287
|
+
: { reasoningWireValue: attempt.reasoningWireValue }
|
|
288
|
+
: {}),
|
|
276
289
|
};
|
|
277
290
|
}
|
|
278
291
|
|
|
292
|
+
/**
|
|
293
|
+
* Pairing rule for reasoning diagnostics, shared with the live request-log capture path:
|
|
294
|
+
* a non-empty string, a non-negative finite number, or a boolean only for
|
|
295
|
+
* `reasoning.enabled`. The field name itself is validated separately at capture time;
|
|
296
|
+
* persisted rows may carry legacy field names, so this checks only the value shape.
|
|
297
|
+
*/
|
|
298
|
+
export function isValidReasoningWireValue(
|
|
299
|
+
wireField: unknown,
|
|
300
|
+
wireValue: unknown,
|
|
301
|
+
): wireValue is string | number | boolean {
|
|
302
|
+
return (typeof wireValue === "string" && wireValue.length > 0)
|
|
303
|
+
|| (typeof wireValue === "number" && Number.isFinite(wireValue) && wireValue >= 0)
|
|
304
|
+
|| (wireField === "reasoning.enabled" && typeof wireValue === "boolean");
|
|
305
|
+
}
|
|
306
|
+
|
|
279
307
|
function normalizedAttempts(raw: unknown): PersistedUsageAttempt[] {
|
|
280
308
|
if (!Array.isArray(raw)) return [];
|
|
281
309
|
return raw.map(normalizeUsageAttempt)
|
|
@@ -294,6 +322,9 @@ export function normalizeUsageEntryForTest(entry: PersistedUsageEntry): Persiste
|
|
|
294
322
|
|
|
295
323
|
function normalizeUsageEntry(entry: PersistedUsageEntry): PersistedUsageEntry {
|
|
296
324
|
const attempts = normalizedAttempts(entry.attempts);
|
|
325
|
+
const routeDecision = entry.routeDecision
|
|
326
|
+
? normalizeRouteDecisionTrace(entry.routeDecision)
|
|
327
|
+
: undefined;
|
|
297
328
|
return {
|
|
298
329
|
requestId: entry.requestId,
|
|
299
330
|
timestamp: entry.timestamp,
|
|
@@ -323,11 +354,11 @@ function normalizeUsageEntry(entry: PersistedUsageEntry): PersistedUsageEntry {
|
|
|
323
354
|
...(typeof entry.reasoningWireField === "string" && entry.reasoningWireField
|
|
324
355
|
? { reasoningWireField: capMetadataString(entry.reasoningWireField) }
|
|
325
356
|
: {}),
|
|
326
|
-
...(
|
|
327
|
-
?
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
357
|
+
...(isValidReasoningWireValue(entry.reasoningWireField, entry.reasoningWireValue)
|
|
358
|
+
? typeof entry.reasoningWireValue === "string"
|
|
359
|
+
? { reasoningWireValue: capMetadataString(entry.reasoningWireValue) }
|
|
360
|
+
: { reasoningWireValue: entry.reasoningWireValue }
|
|
361
|
+
: {}),
|
|
331
362
|
...(typeof entry.requestedServiceTier === "string" && entry.requestedServiceTier
|
|
332
363
|
? { requestedServiceTier: capMetadataString(entry.requestedServiceTier) }
|
|
333
364
|
: {}),
|
|
@@ -359,6 +390,7 @@ function normalizeUsageEntry(entry: PersistedUsageEntry): PersistedUsageEntry {
|
|
|
359
390
|
...(entry.terminalStatus ? { terminalStatus: entry.terminalStatus } : {}),
|
|
360
391
|
...(entry.closeReason ? { closeReason: entry.closeReason } : {}),
|
|
361
392
|
...(entry.upstreamError ? { upstreamError: entry.upstreamError } : {}),
|
|
393
|
+
...(routeDecision ? { routeDecision } : {}),
|
|
362
394
|
};
|
|
363
395
|
}
|
|
364
396
|
|
|
@@ -623,9 +655,11 @@ export function readRecentUsageEntries(limit: number): PersistedUsageEntry[] {
|
|
|
623
655
|
fd = openSync(path, "r");
|
|
624
656
|
const size = fstatSync(fd).size;
|
|
625
657
|
if (size <= 0) return [];
|
|
626
|
-
//
|
|
627
|
-
|
|
628
|
-
|
|
658
|
+
// Trace-sized rows (up to MAX_TRACE_BYTES, RI-01) need a larger per-row
|
|
659
|
+
// budget than the pre-trace ledger; keep expanding until the window covers
|
|
660
|
+
// the file start or the whole file so a restart never hydrates nothing.
|
|
661
|
+
let windowBytes = Math.min(size, Math.max(64 * 1024, Math.ceil(limit) * 20 * 1024));
|
|
662
|
+
while (true) {
|
|
629
663
|
const start = Math.max(0, size - windowBytes);
|
|
630
664
|
const buf = Buffer.alloc(size - start);
|
|
631
665
|
readSync(fd, buf, 0, buf.length, start);
|
|
@@ -645,6 +679,7 @@ export function readRecentUsageEntries(limit: number): PersistedUsageEntry[] {
|
|
|
645
679
|
// most recent N valid rows (not N physical lines minus corrupt ones).
|
|
646
680
|
const entries = parseUsageLines(lines);
|
|
647
681
|
if (entries.length >= limit || start === 0 || windowBytes >= size) return entries.slice(-limit);
|
|
682
|
+
if (windowBytes >= size) break;
|
|
648
683
|
windowBytes = Math.min(size, windowBytes * 4);
|
|
649
684
|
}
|
|
650
685
|
return [];
|
package/src/usage/summary.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { baseProviderLabel } from "../providers/label";
|
|
|
2
2
|
import { canonicalAntigravityUsageModel } from "../providers/antigravity-models";
|
|
3
3
|
import { usageDisplayTotalTokens } from "./totals";
|
|
4
4
|
import type { PersistedUsageEntry, UsageStatus } from "./log";
|
|
5
|
-
import { estimateComboCost, estimateRequestCost,
|
|
5
|
+
import { estimateComboCost, estimateRequestCost, serviceTierContext } from "./cost";
|
|
6
6
|
|
|
7
7
|
export type UsageRange = "7d" | "30d" | "all";
|
|
8
8
|
export type UsageSurface = "all" | "codex" | "claude" | "grok";
|
|
@@ -286,7 +286,7 @@ function addEstimatedCost(
|
|
|
286
286
|
totals.unmeteredRequests += 1;
|
|
287
287
|
return;
|
|
288
288
|
}
|
|
289
|
-
const tier =
|
|
289
|
+
const tier = serviceTierContext(entry);
|
|
290
290
|
const estimate = entry.attempts?.length
|
|
291
291
|
? estimateComboCost(entry.attempts, undefined, tier)
|
|
292
292
|
: estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
|
|
@@ -415,7 +415,7 @@ function buildModels(entries: PersistedUsageEntry[], totalTokens: number): Usage
|
|
|
415
415
|
}
|
|
416
416
|
// Accumulate per-model estimated cost
|
|
417
417
|
for (const entry of entries) {
|
|
418
|
-
const tier =
|
|
418
|
+
const tier = serviceTierContext(entry);
|
|
419
419
|
const estimate = entry.attempts?.length
|
|
420
420
|
? estimateComboCost(entry.attempts, undefined, tier)
|
|
421
421
|
: estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
|
|
@@ -524,7 +524,7 @@ function buildProviders(entries: PersistedUsageEntry[], totalTokens: number): Us
|
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
526
|
for (const entry of entries) {
|
|
527
|
-
const tier =
|
|
527
|
+
const tier = serviceTierContext(entry);
|
|
528
528
|
const estimate = entry.attempts?.length
|
|
529
529
|
? estimateComboCost(entry.attempts, undefined, tier)
|
|
530
530
|
: estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
|
package/src/vision/index.ts
CHANGED
|
@@ -184,6 +184,11 @@ export function resolveVisionBackend(
|
|
|
184
184
|
return anthropicSidecar ? "anthropic" : "openai";
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/** Native model used by the OpenAI vision helper, including its bounded default. */
|
|
188
|
+
export function resolveOpenAiVisionModel(config: Pick<OcxConfig, "visionSidecar">): string {
|
|
189
|
+
return config.visionSidecar?.model ?? DEFAULT_VISION_MODEL;
|
|
190
|
+
}
|
|
191
|
+
|
|
187
192
|
/** A user/developer/toolResult message can carry images (toolResult: e.g. Codex view_image output). */
|
|
188
193
|
function carriesImages(role: string): boolean {
|
|
189
194
|
return role === "user" || role === "developer" || role === "toolResult";
|
|
@@ -249,7 +254,7 @@ export function planVisionSidecar(
|
|
|
249
254
|
return {
|
|
250
255
|
backend,
|
|
251
256
|
forwardSidecar: openAiSidecar,
|
|
252
|
-
settings: { model:
|
|
257
|
+
settings: { model: resolveOpenAiVisionModel(config), timeoutMs: cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS },
|
|
253
258
|
maxDescriptionsPerTurn,
|
|
254
259
|
};
|
|
255
260
|
}
|