Skip to content

[scanner] feat: add process-level LLM usage accumulator (refs #13) - #202

Open
kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
scanner/llm-usage-accumulator
Open

[scanner] feat: add process-level LLM usage accumulator (refs #13)#202
kubestellar-hive[bot] wants to merge 1 commit into
mainfrom
scanner/llm-usage-accumulator

Conversation

@kubestellar-hive

Copy link
Copy Markdown
Contributor

Fix

First, additive slice toward wiring token accounting into the runs table.

scripts/llm.py already logged usage from each response but discarded the counts. This PR adds three module-level helpers:

  • get_usage_totals() — snapshot {prompt_tokens, completion_tokens, calls}
  • reset_usage_totals() — zero the counters (used in tests + between runs)
  • _record_usage(usage) — called from _one_shot() on every response

Every successful call now feeds the accumulator. Missing / non-numeric fields are coerced to 0, so a weird provider response can never fail an otherwise-successful call.

Why this shape

  • Zero signature churn. call_llm() still returns just the parsed dict, so every existing caller (rank.py, write.py, backfill.py, replay_writer.py) keeps working without change.
  • Enables issue Wire up token/cost accounting for runs table #13 in the next step. A follow-up PR can call get_usage_totals() from publish.main() and fill runs.tokens_in / runs.tokens_out — that PR becomes a ~10-line diff instead of a cross-cutting refactor.
  • Serial by design. The pipeline runs one stage at a time (per SPEC.md), so a process-level counter is sufficient; no locking needed.

Test coverage

Adds 8 cases to tests/test_llm_helpers.py:

  • default totals are zero
  • reset_usage_totals() re-zeros after activity
  • multiple _record_usage() calls accumulate
  • _record_usage(None) is a no-op
  • objects missing prompt_tokens/completion_tokens count as 0 (no crash)
  • non-numeric field values coerce to 0
  • get_usage_totals() returns a copy (mutation-safe)
  • _one_shot() feeds the accumulator on a real happy-path

All 29 tests in tests/test_llm_helpers.py pass locally.

Refs #13


Filed by scanner agent (ACMM L5 — hold-gated mode). Hold-gated: human review required.

@kubestellar-hive kubestellar-hive Bot added the hold PR is on hold — do not merge label Jul 16, 2026
Introduces module-level counters and three helpers in scripts/llm.py:

  * get_usage_totals()   → snapshot {prompt_tokens, completion_tokens, calls}
  * reset_usage_totals() → zero the counters
  * _record_usage(usage) → called from _one_shot() on every response

Every successful call now feeds the accumulator with the SDK's
resp.usage counts (missing / non-numeric fields are coerced to 0 so a
weird provider response can never fail an otherwise-successful call).

This is the first, additive slice toward wiring token accounting into
the runs table (issue #13). It changes NO existing signatures — every
caller of call_llm() continues to work unmodified — so follow-up PRs
can consume the totals from rank.py / write.py / publish.py without
another round of refactoring.

Test coverage: 8 new cases in test_llm_helpers.py exercising
reset/accumulate semantics, defensive coercion, snapshot immutability,
and the _one_shot → accumulator hand-off.

Refs #13

Signed-off-by: scanner-agent <scanner@hive.local>
@kubestellar-hive
kubestellar-hive Bot force-pushed the scanner/llm-usage-accumulator branch from 02f3b84 to f0c9d77 Compare July 21, 2026 17:05
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  scripts
  llm.py
Project Total  

This report was generated by python-coverage-comment-action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold PR is on hold — do not merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants