fix: normalize Codex token usage for Langfuse - #39
Conversation
There was a problem hiding this comment.
LGTM — the inclusive-to-OpenAI-schema mapping and validation logic are correct and well covered by tests.
Extended reasoning...
Overview
This PR changes toUsageDetails in plugins/tracing/src/trace.ts (plus the mirrored built dist/index.mjs) to map Codex's inclusive token-count fields (input_tokens, output_tokens, total_tokens, cached_input_tokens, reasoning_output_tokens) into Langfuse's OpenAI-compatible usage schema (prompt_tokens, completion_tokens, total_tokens, nested prompt_tokens_details.cached_tokens / completion_tokens_details.reasoning_tokens). It adds a new isTokenCount guard (non-negative safe integer) and rejects the whole usage object when the counts are internally inconsistent (total !== input + output, or cached > input / reasoning > output). A doc comment was added to TokenUsage in types.ts, and the test suite was updated to assert the exact normalized shape instead of a loose substring check.
Security risks
None. This is pure data transformation for telemetry/observability data (token counts), with no user input reaching auth, file system, network, or eval paths. Malformed/out-of-range values are dropped rather than propagated.
Level of scrutiny
Low-to-moderate is appropriate: this is an isolated, pure function in the tracing plugin (not a critical runtime path), the change is self-contained to one function plus its type, and it ships with updated unit tests that assert the exact expected output shape (including edge cases like zero-valued cached/reasoning tokens). The built dist/index.mjs output was checked against the src/trace.ts diff and the two are consistent.
Other factors
The validation logic is sound given the documented invariant (Codex's top-level counts are inclusive of the cached/reasoning sub-counts): dropping usage entirely when the invariant is violated is a defensible choice to avoid sending malformed data to Langfuse, consistent with this plugin's existing pattern of never blocking uploads on bad data. The bug-hunting pass raised and then ruled out a concern about this silent-drop path lacking a debug log; that's a minor nit at most (and matches the file's existing convention of not logging this specific fallback), not a correctness issue, so it doesn't change my assessment.
There was a problem hiding this comment.
Pull request overview
This PR normalizes Codex token usage reporting to match Langfuse’s OpenAI-compatible usage schema, adds validation to avoid emitting inconsistent/unsafe token values, and updates tracing tests to assert against the normalized payload shape.
Changes:
- Convert Codex token usage into OpenAI-style
prompt_tokens/completion_tokens/total_tokenswith nested*_tokens_details. - Validate token counts (non-negative integers, consistent totals, cached/reasoning bounds) and drop invalid usage payloads.
- Update tracing tests to parse and assert the normalized
usage_detailsJSON payload.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| plugins/tracing/src/trace.ts | Validates and maps Codex token usage into Langfuse’s OpenAI-compatible usage schema. |
| plugins/tracing/src/types.ts | Documents Codex’s inclusive token counting semantics on TokenUsage. |
| plugins/tracing/test/trace.test.ts | Updates usage assertions to validate the normalized OpenAI-style usage payload. |
| plugins/tracing/dist/index.mjs | Updates built output to reflect the new token normalization/validation logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Also addresses #22 |
Summary