Include inner interactive-toolkit cost in session cost - #13
Open
josephschorr wants to merge 6 commits into
Open
josephschorr wants to merge 6 commits into
josephschorr wants to merge 6 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
josephschorr
force-pushed
the
feat/subagent-cost-accounting
branch
from
October 2, 2026 22:49
7cd4d7c to
e0f36f8
Compare
This branch was successfully deployed
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.
Motivation
A session's
status.estimatedCostunder-reports total spend — potentially bymore than an order of magnitude — because it only prices the orchestrator
model's tokens and ignores the cost of inner interactive toolkits the agent
drives.
A passthrough coding agent that drives Claude Code, for example, can spend the
large majority of its cost inside those sub-runs. That spend is already recorded
per invocation in the
tool_sessionaudit Kind'scontent.costUsd, but itnever reaches the cost reporter — so the stamped total reflects only the
orchestrator model and omits the inner toolkit spend entirely.
Summary of changes
Rolls each interactive toolkit's provider-reported cost into the session total,
itemized so provenance stays visible. Generic — keyed by outer tool name, no
per-toolkit branching.
pkg/platform/pipeline,pkg/apis/v1alpha1): newToolUsageandToolCostBucket;SessionEndInfo.ByToolandEstimatedSessionCost.ByTool.Regenerated deepcopy, CRDs,
install.yaml, and the CRD reference doc.pkg/agent/runner):Loop.AddToolCostmirrors the existingaddModelUsage(sameusageMu, first-seen ordering, negative-cost guard,single round at the USD→micro-USD boundary). Fed in-process from the runner's
interactive-tool result callback, regardless of the
ToolSessionLogpersistgate. Surfaced through
SessionEndInfo.ByToolatfireSessionEnd.pkg/agent/postsession/cost): grand total is nowΣ ByModel + Σ ByTool; tool cost is always provider-reported (nevertable-priced) so top-level
PricingKnownis unchanged for existing sessions.The
AmountMicroUSD/PricingKnowndoc contract is updated: when a servedmodel is unpriced, the total is now a documented lower bound (the priced
components) rather than forced to 0. The closing cost notice gains a
Sub-agent toolsline.pkg/web/admind): the session-detail breakdown carriesbyTool;the budget breakdown and the Overview headline spend panel add each session's
tool cost on top of the token-repriced estimate, over the same session scope
that feeds the per-model rollup (no double-count).
Report-only: there is no cost-budget enforcement, and no payer/passthrough
marker (the inner spend is billed to the user's own subscription under
passthrough — a follow-up could annotate this).
Alternatives considered
amountMicroUSD— rejected: it breaks the"
byModelbuckets sum to the total" invariant and loses the provenance of anon-model cost. Itemizing under
byToolkeeps one headline number whileshowing where it came from.
for v1 in favor of a single itemized total; the split can be reintroduced as a
billedTomarker later without a schema break.tool_sessionrecords at SessionEnd instead of in-processaccumulation — rejected: the result callback fires regardless of the
ToolSessionLogpersist gate, so in-process accumulation is strictly morereliable and matches the existing
addModelUsageidiom.Provenance
magetargets forcodegen and the test gate
Ship gate
mage test:unitmage test:integrationmage test:e2eResults:
Regeneration
pkg/apis/v1alpha1/*_types.go→ ranmage gen:apiandmage manifestsconfig/**directly → n/a (only viagen:api)mage docs:crdmage fmt:checkcleanCoverage
accumulator, the SessionEnd wiring, the cost reporter (grand total,
itemization, unknown-model lower bound, no-tool regression), and the three
admind surfaces (session-detail, budget, Overview). Not a new agent-facing
tool call, so no bronzethread bundle is required; the whole e2e + steel
suites remain green.
touched;
estimatedCostis controller-owned status)Before requesting review
(
zz_generated.deepcopy.go,install.yaml,config/**,site/content/docs/crd-agentsession.mdx) are mechanical — re-runmage gen:api && mage manifests && mage docs:crdand confirm the outputis identical rather than reading them line by line.
Known follow-ups (deferred, non-blocking)
byModelbudget axis total excludes tool cost (tool spend has no servedmodel to attribute under) while the other axes include it — a deliberate
asymmetry worth a doc note or a synthetic "sub-agent tools" row.
{tool, $0, pricingKnown: true}bucket instatus.byTool(the parsercollapses "reported 0" and "reported nothing"); no displayed total is affected
since all surfaces gate on
> 0. AcostUSD > 0gate or a threaded "reported"bool would tidy the raw status.