feat: per-session usage/cost aggregation helper#4
Open
alexanderkreidich wants to merge 1 commit into
Open
Conversation
Consumers migrating from bespoke chat UIs showed per-session usage
(tokens, cache, cost, context %) by reading Pi session JSONL files from
disk. That path died with the containerized agent-server: sessions now
live inside the container, so every consumer renders zeros.
The data was already on the wire — AssistantMessage.usage arrives via
both getSessionMessages and message_end SSE events — but agent-client
had no notion of usage at all.
Add a pure aggregateSessionUsage(messages, {contextWindow, costRates})
fold over the transcript: token totals, cost (recalculated from
consumer-supplied per-million rates when LiteLLM-routed models report
zero cost), cache-hit rate, and context-window utilization anchored on
the last clean assistant turn (aborted/errored turns still count toward
spend but not context; compaction marks context unknown until the next
assistant turn re-measures it).
Closes appx-org#2.
Co-Authored-By: Claude Fable 5 <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.
Closes #2.
Adds a pure
aggregateSessionUsage(messages, { contextWindow, costRates })fold over the transcript returned bygetSessionMessages(or kept current frommessage_endwire events), plusemptySessionUsageMetricsfor the pre-history state.What it computes
AssistantMessage.usage.cost); when the wire reports zero (custom LiteLLM-routed models), recalculated from a consumer-supplied per-million-tokencostRatesmap. Wire cost wins whenever non-zero.compactionSummaryafter the anchor marks context unknown (null) until the next assistant turn re-measures it.provider/modelref.This is item (1) from #2 — the optional
costRatesmap keeps the rates question decoupled; rates-in-AgentModelRowwill be filed against agent-server separately.The behavior mirrors the reference implementation in create-appx-app (
src/lib/pi-metrics.ts), adapted from JSONL session entries to the contractAgentMessage[](history is already the active branch, so no parentId walking; compaction arrives as acompactionSummarymessage).Verification
src/core/__tests__/usage.test.ts(aggregation, rates fallback, wire-cost precedence, aborted-turn handling, compaction, model ref).npm run typecheckand the fullnpm testsuite (77 tests) pass.🤖 Generated with Claude Code