feat: record token counts on tasks for energy-per-token reporting - #1362
Open
davidberenstein1957 wants to merge 5 commits into
Open
feat: record token counts on tasks for energy-per-token reporting#1362davidberenstein1957 wants to merge 5 commits into
davidberenstein1957 wants to merge 5 commits into
Conversation
Add input_tokens, output_tokens and n_requests to TaskEmissionsData, with energy_per_output_token and emissions_per_request derived from them, so LLM inference can be reported per token instead of per run. Counts are accumulated on the task via tracker.record_tokens(), which can also read them straight from an OpenAI-compatible, Ollama or vLLM response by duck typing, without importing any inference library. Closes #1347 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1362 +/- ##
==========================================
+ Coverage 91.39% 91.62% +0.22%
==========================================
Files 49 49
Lines 5056 5074 +18
==========================================
+ Hits 4621 4649 +28
+ Misses 435 425 -10 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The cross-link from reference/output.md targeted an anchor that never existed: the section was bold text, not a heading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- drop energy_per_output_token / emissions_per_request: properties never reach TaskEmissionsData.values, so they delivered nothing - assert the warning and the untouched counters when no task is active - debug hint when a response carries no usage (streamed OpenAI chunks) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidberenstein1957
marked this pull request as ready for review
August 12, 2026 19:14
extract_token_counts() guessed token counts out of OpenAI, Ollama and vLLM response shapes. Vendor payloads drift, and each drift becomes a silent zero in core codecarbon plus a bug report. Only the explicit record_tokens(input_tokens=..., output_tokens=...) entry point remains; the caller reads its own client's usage fields, which it already knows how to do. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Start the section at the API call and drop the justification for not inspecting the response object. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
Energy per run is not a comparable number for an LLM: it depends entirely on how many prompts happened to be sent. Energy per output token is. CodeCarbon already measures the power draw over a task; the only missing ingredient was the token counter, which only the caller knows.
This PR lets the caller hand that counter over, and carries it through the existing task machinery to the output handlers.
User-facing surface
Three new fields on
TaskEmissionsData, all defaulting to0:input_tokens,output_tokens,n_requests. They are plain stored counters. No derived properties are exposed — an earlier version of this description claimedenergy_per_output_tokenandemissions_per_requestwere added, and that was wrong.TaskEmissionsData.valuesis built from__dict__, so a property reaches no output method, and both figures are one division away from the columns above. See the comment atcodecarbon/output_methods/emissions_data.py:115-117.One recording entry point, on the tracker and mirrored on
TaskEmissionsTracker:That is the whole API. CodeCarbon does not inspect the response object: the caller reads its own client's usage fields, which it already knows how to do, and no inference library is imported or added as a dependency. (A
response=argument that duck-typed OpenAI / Ollama / vLLM payloads was in an earlier revision and has been removed — vendor response shapes drift, and each drift would land here as a silent zero.)Counts accumulate over the life of one task; recording with no active task logs a warning and is otherwise a no-op.
The three fields flow through
Task.out()and appear as three extra columns in the per-task CSV. Note that the task CSV is rewritten in full on each run (FileOutput.task_outwrites a fresh dataframe to a per-run-id path), so there is no header-migration concern for existing files.Verification
tests/test_token_tracking.py: accumulation across severalrecord_tokenscalls in one task, recording with no active task, and an end-to-end check that the columns land in the task CSV with the right values.tests/test_tracking_inference.pyandtest_docs_examples.pystill pass.ruff format/ruff checkare clean on the touched files (the repo-widetask lint/task formatwere not run — they currently churn ~120 unrelated files).Deliberately left out
measure_power_secs, so per-request tasks would be dominated by measurement noise.EmissionsData, since a run may mix inference with other work.Docs updated: an "LLM inference, energy per token" section in
docs/tutorials/python-api.mdand the three task columns indocs/reference/output.md.Closes #1347
🤖 Generated with Claude Code