Repository navigation
fix(speed): count a response copied into a forked subagent once - #820
Open
eric-engberg wants to merge 4 commits into
Open
eric-engberg wants to merge 4 commits into
eric-engberg wants to merge 4 commits into
Conversation
A forked subagent's transcript opens with a copy of the response that spawned it: same message.id, same usage. Speed metrics dedup message ids within each file only, so the copy counted as a second request. Right as a fork starts, the windowed speeds read about twice the real rate (more with several forks). Merge requests that share a message.id across the main transcript and its subagent files, keeping the larger token counts, the latest timestamp and every interval. Each file still dedups its own rows first, since the interval handling depends on row order. The subagent aggregation test now gives each file's response its own id when ids are on; a shared id across files is the copy case, covered by its own test.
Keeps mergeCollectedSpeedMetrics to the loop: requests without an id pass straight through, a repeated id folds into the first copy.
# Conflicts: # src/utils/jsonl-metrics.ts
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
Input, Output and Total Speed no longer count a forked subagent's opening copy of the response that started it. That copy made a second request out of the same API response. Right as a fork starts, the windowed speeds read 2–3x the real rate, and the session average stayed too high afterwards.
Why (evidence)
A forked subagent's transcript opens with a copy of the assistant row that spawned it: same
message.id, same usage. After #622, #725 and #735, the speed metrics count a response once per transcript file but never across files, so each copy adds the response's tokens again. Token totals don't have this problem, since they only read the main transcript.I scored
mainagainst a standalone reference (each response counted once across the main transcript and its subagent files) on 19 transcripts: 14 of my own recent sessions (Claude Code 2.1.267–2.1.314), two of them cut mid-response, and 3 synthetic ones.maincounts 3,417 requests instead of 3,410, and 33.9k output tokens too many. Another session with 6 copies of 3 responses counts 6 extra requests and 31.5k extra tokens.mainAt 5 of the 7 moments,
mainreads 1.9–3x the reference. A response that starts several forks at once is counted again for each copy.How
mergeCollectedSpeedMetricsfolds requests that share amessage.idacross files into one: the larger input and output counts (a copy carries the same usage), the later timestamp, and every interval. Intervals are merged when the speed is built, as before.message.idare kept as they are.aggregates subagents independently with message id shared-id(from fix: count each API response once in speed and token metrics #622) expected three requests when three files share one id. In real transcripts, an id is only shared across files when a fork copies a response. That case now has its own test, built on the fork file's real shape (afork-context-refrow, the copy, then the fork's prompt). The old test now gives each file's response its own id when ids are on, so it still checks that separate responses in separate files stay separate.Demo
Three Output Speed widgets (session average, 30 s and 60 s windows) on a fake transcript where every response runs at 50 t/s. An 8 s response spawns a forked subagent, rendered right as the fork starts and again after it answered in 4 s.
Powerline
Before:
After:
Plain
Before:
After:
Testing
mainand passes here.mainas of 2.2.34 (0c94df7): it merges cleanly.bun run lintis clean, andbun teston Linux CI gives 4404 pass, 0 fail (4403 onmain). The built CLI under Bun 1.4.4 and Node 26.13.0 agrees across runtimes and matchesmainin plain and Powerline mode, and the TUI opens and exits cleanly under both. It adds no JavaScript or Node API newer than Node 14, the build's target.main: 67/67).mainand this branch. The remaining differences are session durations, which this PR doesn't change:mainmerges a response's rows into one interval, so a parallel tool result logged between them counts as active time (+0.03% to +0.79%).distunder Node 26.10 and Bun 1.4.2: the demo transcript reads 50.0 t/s everywhere on this branch, and 100.0 and 83.3 t/s onmain, under both runtimes.