Uh oh!
There was an error while loading. Please reload this page.
fix(core): roll up subagent cost into parent session and fix fork double-counting - #43645
Open
AndyS77 wants to merge 5 commits into
Open
fix(core): roll up subagent cost into parent session and fix fork double-counting#43645AndyS77 wants to merge 5 commits into
AndyS77 wants to merge 5 commits into
Conversation
…ble-counting - Zero out cost/tokens on cloned step-finish parts in fork() to prevent double-counting pre-fork spend in forked sessions (anomalyco#31032, anomalyco#36944) - Add Session.totalCost(sessionID) that BFS-walks descendant sessions via children() and aggregates cost + tokens (anomalyco#39740) - Add GET /session/:id/cost endpoint exposing aggregated cost - Add E2E tests: subagent cost rollup, fork with subagent history, nested child sessions, multiple child sessions Closesanomalyco#39740, anomalyco#31032, anomalyco#36944 Supersedes anomalyco#25712 Co-Authored-By: zai-glm-52 <noreply@ai.local> Agent: @bug-fix Scope: cost-subagent-rollup
- Add totalCost field to SessionData, updated via refreshCost effect - Footer formatUsage uses totalCost when available, falls back to info.cost - Context % remains per-session (info.tokens) — correct for context window - refreshCost fires on message.updated for parent session and on bootstrap - Calls GET /session/:id/cost endpoint (requires SDK regeneration) Co-Authored-By: zai-glm-52 <noreply@ai.local> Agent: @bug-fix Scope: cost-subagent-rollup
- stats: use totalCost() for top-level sessions (no parentID), skip child sessions to avoid double-counting - acp: sendUpdate fetches aggregated cost via session.cost endpoint, falls back to totalSessionCost(messages) if unavailable - messageLoaderFromSDK: add cost() method to MessageLoaderInterface Co-Authored-By: zai-glm-52 <noreply@ai.local> Agent: @bug-fix Scope: cost-subagent-rollup
…tent SDK cost method - Rename totalCost to subagentCost in SessionData (clarity: this is the aggregated child session cost, not the parent's own cost) - Footer cost = info.cost (parent) + data.subagentCost (children) - refreshCost uses existing session.children SDK endpoint instead of non-existent session.cost (requires Protocol registration for SDK gen) - stats: catch NotFoundError from totalCost - acp: revert to totalSessionCost(messages) until SDK supports cost - handler: map NotFoundError to ApiNotFoundError Co-Authored-By: zai-glm-52 <noreply@ai.local> Agent: @bug-fix Scope: cost-subagent-rollup
… layer - Add session.cost and session.children endpoints to protocol session group - Add children() and totalCost() to SessionV2 Interface + implementation - Add handlers in protocol SessionHandler - Regenerate both SDKs (client + legacy js) - Switch TUI refreshCost to SDK session.cost() endpoint - Switch ACP sendUpdate to SDK session.cost() with fallback - Rename SessionData.subagentCost to totalCost (holds server-aggregated total) - Footer uses totalCost when > 0, falls back to info.cost - Add E2E tests: aggregated cost across nested children, 404 for missing session - Update ACP usage test mock with cost method Co-Authored-By: zai-glm-52 <noreply@ai.local> Agent: @bug-fix Scope: cost-subagent-rollup
Contributor
The following comment was made by an LLM, it may be inaccurate: Found Potential Duplicates/Related PRs
These are the most relevant matches. PR #25712 is particularly important as it appears to be the companion UI PR that would consume the cost aggregation API being implemented in #43645. |
Contributor
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
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 freeto 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.
Issue for this PR
Closes#39740
Closes#31032
Closes#36944
Type of change
What does this PR do?
Subagent session costs were not rolled up to the parent session (#39740), and forked sessions double-counted pre-fork costs (#31032, #36944). This PR fixes both issues and exposes the aggregated cost through the protocol layer so the TUI, stats, and ACP can display it.
Fork double-counting fix: When a session is forked, the cloned step-finish parts now have their cost and tokens zeroed out. The forked session starts with zero cost and only accumulates cost from its own LLM calls, not the parent's pre-fork history.
Cost rollup: Added
children()andtotalCost()to both V1Session.Serviceand V2SessionV2.Interface.totalCost()does a BFS walk across all descendant sessions, summing cost and tokens.Protocol endpoint: Added
session.costandsession.childrento the protocol session group (/api/session/:sessionID/cost,/api/session/:sessionID/children) with handlers in both the protocol handler (packages/server) and the server handler (packages/opencode). Both SDKs were regenerated.TUI:
refreshCosteffect instream.transport.tscallssdk.session.cost()onmessage.updatedand bootstrap.SessionData.totalCostfield; footerformatUsageusestotalCostwhen > 0, falls back toinfo.cost.Stats + ACP: Stats uses
totalCost()for top-level sessions. ACPsendUpdateusessdk.session.cost()withtotalSessionCost(messages)fallback.How did you verify your code works?
cost-rollup.test.ts): fork zeroing, own cost, child cost, nested children, multiple childrenusage.test.ts): mock updated withcostmethodhttpapi-session.test.ts): aggregated cost across nested children (parent -> child -> grandchild, verifying 0.06 = 0.01 + 0.02 + 0.03), 404 for missing sessionbun typecheckclean (0 source-code errors)bun run generateRelated PRs (used as reference)
Checklist