From 427ee244a39b033dba39376ac053b34e8986ad22 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Sat, 11 Jul 2026 04:33:09 -0300 Subject: [PATCH] fix(usage): honor xAI provider-reported exact cost (#6711) OmniRoute's calculateCost() always estimated request cost from token counts x static pricing, discarding xAI's exact provider-reported cost when present. xAI's chat-completions usage object reports the precise billed cost via cost_in_usd_ticks (docs.x.ai/developers/cost-tracking and the API reference's usage schema: "TICKS_IN_USD_CENT: i64 = 100_000_000" => 1e10 ticks/USD, e.g. 37756000 ticks ~= $0.0038). calculateCost()/computeCostFromPricing() now short-circuit to this exact figure when present -- before any pricing DB lookup, so it also works for models without a local pricing row -- and still fall back to the token-based estimate when it is absent. The field is threaded through both the streaming (extractUsage/normalizeUsage) and non-streaming (extractUsageFromResponse) usage-extraction paths. Corrected divisor vs upstream: the upstream PR used /1e12 (a 100x under-report, e.g. reporting $0.00123 as the doc's $0.123 example); this port uses the doc-verified /1e10 instead, confirmed against both the cost-tracking guide and the API reference's usage-object schema. Inspired-by: https://github.com/decolua/9router/pull/2453 Co-authored-by: ryanngit <74137224+ryanngit@users.noreply.github.com> --- CHANGELOG.md | 1 + open-sse/handlers/usageExtractor.ts | 7 ++ open-sse/utils/usageTracking.ts | 5 + src/lib/usage/costCalculator.ts | 40 ++++++- tests/unit/xai-exact-cost-2453.test.ts | 138 +++++++++++++++++++++++++ 5 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 tests/unit/xai-exact-cost-2453.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 44daec6851..2028f645f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3370,6 +3370,7 @@ And thank you to the OmniRoute community for the bug reports, reproductions, and ### Fixed +- **usage:** use xAI's exact provider-reported cost when present instead of always estimating from token counts. (thanks @ryanngit) - **memory:** the `recent` retrieval strategy no longer drops recent memories whose text doesn't overlap the current prompt. It was internally mapped to the `exact` path, which relevance-filtered by the forwarded prompt (`score > 0`), so diff --git a/open-sse/handlers/usageExtractor.ts b/open-sse/handlers/usageExtractor.ts index 92affd1c39..d68013e720 100644 --- a/open-sse/handlers/usageExtractor.ts +++ b/open-sse/handlers/usageExtractor.ts @@ -31,6 +31,13 @@ export function extractUsageFromResponse(responseBody, provider) { responseBody.usage.completion_tokens_details?.reasoning_tokens ?? responseBody.usage.output_tokens_details?.reasoning_tokens ?? responseBody.usage.reasoning_tokens, + // xAI's exact provider-reported cost (port of decolua/9router#2453, capability A — + // @ryanngit). Only set the key when present so non-xAI OpenAI-shaped usage + // (Codex, DeepSeek, etc.) is unaffected. Ticks → USD conversion happens in + // costCalculator.ts, not here. + ...(Number.isFinite(Number(responseBody.usage.cost_in_usd_ticks)) + ? { cost_in_usd_ticks: Number(responseBody.usage.cost_in_usd_ticks) } + : {}), }; } diff --git a/open-sse/utils/usageTracking.ts b/open-sse/utils/usageTracking.ts index 8b67cc793a..6aaacb04c5 100644 --- a/open-sse/utils/usageTracking.ts +++ b/open-sse/utils/usageTracking.ts @@ -269,6 +269,9 @@ export function normalizeUsage(usage) { assignNumber("cache_creation_input_tokens", usage?.cache_creation_input_tokens); assignNumber("cached_tokens", usage?.cached_tokens); assignNumber("reasoning_tokens", usage?.reasoning_tokens); + // xAI's exact provider-reported cost (port of decolua/9router#2453, capability A — + // @ryanngit). Ticks → USD conversion happens in costCalculator.ts, not here. + assignNumber("cost_in_usd_ticks", usage?.cost_in_usd_ticks); if (Object.keys(normalized).length === 0) return null; return normalized; @@ -387,6 +390,8 @@ export function extractUsage(chunk) { chunk.usage.completion_tokens_details?.reasoning_tokens ?? chunk.usage.output_tokens_details?.reasoning_tokens ?? chunk.usage.reasoning_tokens, + // xAI's exact provider-reported cost (port of decolua/9router#2453, capability A). + cost_in_usd_ticks: chunk.usage.cost_in_usd_ticks, }); } diff --git a/src/lib/usage/costCalculator.ts b/src/lib/usage/costCalculator.ts index 59d16c5244..94fc8668fe 100644 --- a/src/lib/usage/costCalculator.ts +++ b/src/lib/usage/costCalculator.ts @@ -37,6 +37,34 @@ export type CostCalculationOptions = { flatRateAsZero?: boolean; }; +/** + * xAI reports the exact provider-billed cost of a request in the chat-completions + * `usage` object via `cost_in_usd_ticks` (port of decolua/9router#2453, capability + * A — @ryanngit). Per the official docs — both + * https://docs.x.ai/developers/cost-tracking and the API reference's usage schema + * ("TICKS_IN_USD_CENT: i64 = 100_000_000") — there are 10_000_000_000 (1e10) ticks + * per USD. Example from the docs: 37756000 ticks ≈ $0.0038. + * + * NOTE: this divisor is intentionally 1e10, not the 1e12 used by the upstream PR + * (which under-reports cost 100x) — verified directly against the xAI docs. + */ +const USD_TICKS_PER_DOLLAR = 10_000_000_000; + +/** + * Extract an exact, provider-reported USD cost from a token/usage record when one + * is present, so callers can trust it over the token × pricing estimate. Currently + * only xAI's `cost_in_usd_ticks` field is handled — see comment above. + */ +function extractExactCostUsd( + tokens: Record | null | undefined +): number | null { + const ticks = tokens?.cost_in_usd_ticks; + if (typeof ticks === "number" && Number.isFinite(ticks) && ticks >= 0) { + return ticks / USD_TICKS_PER_DOLLAR; + } + return null; +} + function toNumber(value: unknown, fallback = 0): number { if (typeof value === "number" && Number.isFinite(value)) return value; if (typeof value === "string" && value.trim().length > 0) { @@ -95,7 +123,12 @@ export function computeCostFromPricing( tokens: Record | null | undefined, options: CostCalculationOptions = {} ): number { - if (!pricing || !tokens) return 0; + if (!tokens) return 0; + // Trust an exact, provider-reported cost over the token × pricing estimate + // when one is present — works even when no local pricing row exists yet. + const exactCostUsd = extractExactCostUsd(tokens); + if (exactCostUsd !== null) return exactCostUsd; + if (!pricing) return 0; // Flat-rate (subscription / cookie-web) providers don't bill per token — their // per-token pricing rows exist only for estimation, so display surfaces opt in // to show $0 instead of an inflated estimate (#5552). @@ -138,6 +171,11 @@ export async function calculateCost( ): Promise { if (!tokens || !provider || !model) return 0; + // Short-circuit before any pricing DB lookup when an exact, provider-reported + // cost is present (currently xAI's `cost_in_usd_ticks` — see extractExactCostUsd). + const exactCostUsd = extractExactCostUsd(tokens); + if (exactCostUsd !== null) return exactCostUsd; + try { const { getPricingForModel } = await import("@/lib/localDb"); diff --git a/tests/unit/xai-exact-cost-2453.test.ts b/tests/unit/xai-exact-cost-2453.test.ts new file mode 100644 index 0000000000..8bca0fa08f --- /dev/null +++ b/tests/unit/xai-exact-cost-2453.test.ts @@ -0,0 +1,138 @@ +/** + * xAI exact provider-reported cost passthrough (port of decolua/9router#2453, + * capability A — @ryanngit). + * + * xAI's chat-completions `usage` object reports the exact billed cost of a + * request via `cost_in_usd_ticks`. Per the official docs + * (https://docs.x.ai/developers/cost-tracking and the API reference's usage + * schema): "TICKS_IN_USD_CENT: i64 = 100_000_000" ⇒ 10_000_000_000 (1e10) + * ticks per USD. Example given in the docs: 37756000 ticks ≈ $0.0038. + * + * NOTE: the upstream PR used a /1e12 divisor (100x under-report) — this port + * uses the doc-verified /1e10 divisor instead. + * + * OmniRoute previously always estimated cost from token counts × static + * pricing, discarding this exact figure. This test proves calculateCost()/ + * computeCostFromPricing() now trust the exact figure when present, and + * still fall back to the token-based estimate when it is absent (control). + */ + +import test from "node:test"; +import assert from "node:assert/strict"; +import { calculateCost, computeCostFromPricing } from "../../src/lib/usage/costCalculator.ts"; +import { extractUsageFromResponse } from "../../open-sse/handlers/usageExtractor.ts"; +import { extractUsage, normalizeUsage } from "../../open-sse/utils/usageTracking.ts"; + +// $1/1M input, $2/1M output → 1M+1M tokens would estimate to $3 at the +// metered rate. Chosen so the exact-cost value (~$0.0038) is unmistakably +// NOT the token-based estimate — proves the early return actually fires. +const PRICING = { input: 1, output: 2 }; +const TOKENS_1M_EACH = { input: 1_000_000, output: 1_000_000 }; + +// Doc example: 37756000 ticks ≈ $0.0038 (docs.x.ai/developers/cost-tracking). +const DOC_EXAMPLE_TICKS = 37_756_000; +const DOC_EXAMPLE_USD = 0.0037756; // 37756000 / 1e10, exact + +test("computeCostFromPricing: xAI exact cost_in_usd_ticks overrides the token-based estimate", () => { + const cost = computeCostFromPricing(PRICING, { + ...TOKENS_1M_EACH, + cost_in_usd_ticks: DOC_EXAMPLE_TICKS, + }); + assert.ok( + Math.abs(cost - DOC_EXAMPLE_USD) < 1e-9, + `expected ${DOC_EXAMPLE_USD}, got ${cost}` + ); + assert.notEqual(cost, 3, "must not fall back to the $3 token-based estimate"); +}); + +test("computeCostFromPricing: xAI exact cost works even with no pricing record at all", () => { + const cost = computeCostFromPricing(null, { + ...TOKENS_1M_EACH, + cost_in_usd_ticks: DOC_EXAMPLE_TICKS, + }); + assert.ok(Math.abs(cost - DOC_EXAMPLE_USD) < 1e-9); +}); + +test("computeCostFromPricing CONTROL: no cost_in_usd_ticks still falls back to the token-based estimate", () => { + assert.equal(computeCostFromPricing(PRICING, TOKENS_1M_EACH), 3); +}); + +test("calculateCost: xAI exact cost_in_usd_ticks overrides whatever the token-based estimate would be", async () => { + // Baseline: the token-based estimate calculateCost would otherwise compute + // for this provider/model/token-count (whatever xai/grok-4.3's local + // pricing table says — not hardcoded here, so this test doesn't break if + // pricing data changes). + const baseline = await calculateCost("xai", "grok-4.3", { input: 500, output: 500 }); + + const cost = await calculateCost("xai", "grok-4.3", { + input: 500, + output: 500, + cost_in_usd_ticks: DOC_EXAMPLE_TICKS, + }); + + assert.ok(Math.abs(cost - DOC_EXAMPLE_USD) < 1e-9, `expected ${DOC_EXAMPLE_USD}, got ${cost}`); + assert.notEqual(cost, baseline, "exact cost must override the token-based estimate"); +}); + +test("calculateCost CONTROL: no cost_in_usd_ticks still falls back to the token-based estimate (unchanged)", async () => { + const before = await calculateCost("xai", "grok-4.3", { input: 500, output: 500 }); + const after = await calculateCost("xai", "grok-4.3", { input: 500, output: 500 }); + assert.equal(after, before, "identical calls without the exact field must stay deterministic"); + assert.notEqual(after, DOC_EXAMPLE_USD, "must not coincidentally match the exact-cost value"); +}); + +test("normalizeUsage: passes through a finite cost_in_usd_ticks", () => { + const normalized = normalizeUsage({ prompt_tokens: 10, cost_in_usd_ticks: DOC_EXAMPLE_TICKS }); + assert.equal(normalized.cost_in_usd_ticks, DOC_EXAMPLE_TICKS); +}); + +test("normalizeUsage: drops a non-finite cost_in_usd_ticks", () => { + const normalized = normalizeUsage({ prompt_tokens: 10, cost_in_usd_ticks: "not-a-number" }); + assert.equal(normalized.cost_in_usd_ticks, undefined); +}); + +test("extractUsageFromResponse: xAI OpenAI-shaped usage carries cost_in_usd_ticks through", () => { + const usage = extractUsageFromResponse( + { + usage: { + prompt_tokens: 12, + completion_tokens: 8, + cost_in_usd_ticks: DOC_EXAMPLE_TICKS, + }, + }, + "xai" + ); + assert.equal(usage.cost_in_usd_ticks, DOC_EXAMPLE_TICKS); +}); + +test("extractUsageFromResponse CONTROL: non-xAI OpenAI usage without the field stays unchanged (no stray key)", () => { + const usage = extractUsageFromResponse( + { + usage: { + prompt_tokens: 12, + completion_tokens: 8, + prompt_tokens_details: { cached_tokens: 3 }, + completion_tokens_details: { reasoning_tokens: 2 }, + }, + }, + "openai" + ); + assert.deepEqual(usage, { + prompt_tokens: 12, + completion_tokens: 8, + cached_tokens: 3, + reasoning_tokens: 2, + }); + assert.ok(!("cost_in_usd_ticks" in usage), "must not add a stray undefined key"); +}); + +test("extractUsage (streaming): xAI OpenAI-format chunk carries cost_in_usd_ticks through", () => { + const usage = extractUsage({ + usage: { + prompt_tokens: 12, + completion_tokens: 8, + cost_in_usd_ticks: DOC_EXAMPLE_TICKS, + }, + }); + assert.equal(usage.cost_in_usd_ticks, DOC_EXAMPLE_TICKS); +});