feat: collect reasoning_tokens from the provider usage payload (issue #6)

Reasoning tokens are already counted inside completion_tokens, so the
cost total was never wrong -- what was missing is the attribution: how
much of a call was spent thinking rather than answering.

LLMResponse and TransportResult each gain a trailing reasoning_tokens
field, and the telemetry port grows from 21 to 22 columns with the new
column appended in both backends so fresh and migrated schemas keep the
same physical order.

None means this particular call did not report the field, not that the
source never reports it: a relay that falls back to a local tokenizer
replaces the whole usage object and drops completion_tokens_details.
Downstream checks must therefore read "in (None, 0)"; no provider was
observed reporting a literal zero.
This commit is contained in:
2026-08-02 05:55:37 -04:00
parent e5871cccd2
commit 89ff916bc8
13 changed files with 159 additions and 6 deletions
+3
View File
@@ -209,11 +209,13 @@ class TestObservabilityPassthrough:
raw={},
cached_prompt_tokens=64,
model_reported="MiniMax-Text-01-250321",
reasoning_tokens=7,
)
mw, *_ = _harness([_src("a")], [result])
resp = await mw(_REQ)
assert resp.cached_prompt_tokens == 64
assert resp.model_reported == "MiniMax-Text-01-250321"
assert resp.reasoning_tokens == 7
# model 仍是配置别名: 真实版本是旁证,不顶替溯源主字段
assert resp.model == "m"
@@ -221,6 +223,7 @@ class TestObservabilityPassthrough:
mw, *_ = _harness([_src("a")], [_ok()])
resp = await mw(_REQ)
assert resp.cached_prompt_tokens is None and resp.model_reported is None
assert resp.reasoning_tokens is None
class TestRetryAndFailover: