From ad07e681baea30fcec5507ecc879d9ef104d5225 Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 4 Nov 2026 01:05:31 -0600 Subject: [PATCH] Accept independent Grok reasoning counters in prompt receipts Co-Authored-By: Paperclip --- .../src/drivers/acpx/grok-usage.test.ts | 19 ++++++++++++++++++- .../src/drivers/acpx/grok-usage.ts | 3 +-- tests/runner-e2e/README.md | 6 ++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/paperclip-runner/src/drivers/acpx/grok-usage.test.ts b/packages/paperclip-runner/src/drivers/acpx/grok-usage.test.ts index d056c688153..5ce3acd199b 100644 --- a/packages/paperclip-runner/src/drivers/acpx/grok-usage.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/grok-usage.test.ts @@ -21,12 +21,29 @@ describe("Grok terminal prompt usage", () => { it.each([ { usageIsIncomplete: true }, { usageIsIncomplete: "false" }, { cachedReadTokens: 505796 }, - { inputTokens: -1 }, { outputTokens: 1.5 }, { reasoningTokens: 5764 }, { totalTokens: 1 }, + { inputTokens: -1 }, { outputTokens: 1.5 }, { reasoningTokens: -1 }, { reasoningTokens: 1.5 }, { totalTokens: 1 }, { modelCalls: undefined }, { inputTokens: Number.MAX_SAFE_INTEGER + 1 }, ])("refuses incomplete or invalid token authority: %j", patch => { expect(grokPromptUsage({ ...meta, usage: { ...usage, ...patch } }, "session-1")).toBeNull(); }); + it("settles a real Grok prompt whose reasoning counter exceeds its output counter", () => { + const collector = createGrokPromptUsageCollector(); + collector.begin("runner-1", "session-1"); + collector.observe("outbound", request); + collector.observe("inbound", { ...response, result: { _meta: { ...meta, usage: { + inputTokens: 517350, outputTokens: 7969, totalTokens: 525319, cachedReadTokens: 458624, + cacheCreationTokens: 0, reasoningTokens: 9859, modelCalls: 15, costUsdTicks: 4537320000, + } } } }); + const state = { lastRequestId: "runner-1", terminalPromptUsage: collector.snapshot() }; + expect(persistedAcpxTurnUsage({}, state, "runner-1")).toEqual({ + type: "status", tag: "usage_update", text: "terminal prompt usage", + cost: { amount: 0.453732, currency: "USD", basis: "turn" }, + breakdown: { inputTokens: 58726, outputTokens: 7969, totalTokens: 525319, + cachedReadTokens: 458624, cachedWriteTokens: 0, thoughtTokens: 0 }, + }); + }); + it.each([{ costUsdTicks: undefined }, { costUsdTicks: -1 }, { costIsPartial: true }, { costIsPartial: "false" }])( "preserves complete tokens without inventing cost: %j", patch => { const result = grokPromptUsage({ ...meta, usage: { ...usage, ...patch } }, "session-1"); diff --git a/packages/paperclip-runner/src/drivers/acpx/grok-usage.ts b/packages/paperclip-runner/src/drivers/acpx/grok-usage.ts index 7552f44f1eb..12e337b8fce 100644 --- a/packages/paperclip-runner/src/drivers/acpx/grok-usage.ts +++ b/packages/paperclip-runner/src/drivers/acpx/grok-usage.ts @@ -16,8 +16,7 @@ export function grokPromptUsage(metaValue: unknown, sessionId: string): Omit Number(inputTokens) - || Number(reasoningTokens) > Number(outputTokens)) return null; + || Number(cachedReadTokens) + Number(cacheCreationTokens) > Number(inputTokens)) return null; const costKnown = integer(usage.costUsdTicks) && (usage.costIsPartial === undefined || usage.costIsPartial === false); return { promptId: meta.promptId, diff --git a/tests/runner-e2e/README.md b/tests/runner-e2e/README.md index bc76e5bf606..4974e9ed25f 100644 --- a/tests/runner-e2e/README.md +++ b/tests/runner-e2e/README.md @@ -2188,6 +2188,12 @@ an API-key pass must not be reported as subscription evidence. See [`doc/grok-native-runner.md`](../../doc/grok-native-runner.md) for installation, credential boundaries and repetition requirements. +Grok accounting uses the complete prompt ledger bound to the matching ACP +response. Its reasoning counter can exceed its output counter; it is not a +validation bound or an extra term in the ledger's input-plus-output total. +Reported cost remains authoritative. See the upstream +[`UsageTotals` ledger](https://github.com/xai-org/grok-build/blob/2bdd1d6a6369de0e8c68132ea4539e9abd9e14a8/crates/codegen/xai-chat-state/src/usage.rs). + ### Kimi Code qualification `kimi-qualification` is a separate explicit-only candidate suite for maintained