fix: keep session token/cost counters monotonic across compaction - #557
Open
synth-mania wants to merge 1 commit into
Open
fix: keep session token/cost counters monotonic across compaction#557synth-mania wants to merge 1 commit into
synth-mania wants to merge 1 commit into
Conversation
The top-bar token (in/out/cache) and cost counters were computed by summing usage over the current context messages only. After compaction, pi's buildContextEntries() drops the summarized pre-compaction entries, so loadSession() replaced the message list and the counters visibly reset (and cost dropped with them). The SDK's own getSessionStats() instead aggregates over ALL session-file entries (including usage recorded on compaction/branch-summary entries), because compaction only appends a summary — it never deletes history. - lib/session-stats.ts: computeSessionStats() mirrors that all-entries aggregation (assistant + tool-result messages, compaction and branch summary usage). - GET /api/sessions/[id] now returns a cumulative `stats` block computed over all entries. - useAgentSession merges file stats into the live per-message sum with a per-field max(), so counters only ever increase — across compaction, page reloads, and branch navigation — while still tracking live streaming usage before it is persisted. - types.ts: shared AgentUsage type; usage? on compaction/branch-summary/ tool-result entries. Adds unit tests (incl. a monotonicity check against the SDK's real buildContextEntries) and a real-world check on a compacted session.
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.
Problem
The top-bar tokens in/out (and cache read/write) counters — and the cost figure — appear to be reset by pi-web's compaction process. After a session compacts, the numbers visibly drop.
Root cause
Those counters are computed in
hooks/useAgentSession.tsby summingusageover the current context messages only. When compaction finishes, the client callsloadSession(), which rebuilds the message list through the SDK'sbuildContextEntries(). That function drops the summarized pre-compaction entries (they stay in the JSONL file but are excluded from context). So the summed token/cost counters collapse to the post-compaction usage only.The SDK's own
AgentSession.getSessionStats()does the opposite and correct thing: it aggregates over all session-file entries, including the usage recorded on compaction/branch-summary entries — because compaction only appends a summary entry and never deletes history.Fix
Make the reported stats use the same all-entries aggregation the SDK uses, while still tracking live streaming usage:
lib/session-stats.ts(new):computeSessionStats(entries)mirrors the SDK's aggregation — assistant + tool-result message usage, plus usage oncompactionandbranch_summaryentries.app/api/sessions/[id]/route.ts:GETnow returns a cumulativestatsblock computed over all entries.hooks/useAgentSession.ts: the per-message live sum is merged with the filestatsusing a per-fieldmax(). This keeps counters monotonic across compaction, page reloads, and branch navigation, and still reflects in-flight streaming usage before it's persisted.lib/types.ts: sharedAgentUsagetype; addsusage?to compaction/branch-summary/tool-result entries.Because session entries are only ever appended,
max()guarantees the counters can only ever increase.Verification
lib/session-stats.test.mjs(6), including a monotonicity check against the SDK's realbuildContextEntries.web-auth.test.mjs— it depends onPI_WEB_PASSWORDbeing unset, which isn't true in my env; it fails identically on a clean tree.)tsc --noEmitandeslint .clean.