Skip to content

feat: token and cost details on agents view rows - #2003

Open
snimu wants to merge 3 commits into
fix/agents-view-busy-descendant-indicatorfrom
feat/agents-view-costs
Open

feat: token and cost details on agents view rows#2003
snimu wants to merge 3 commits into
fix/agents-view-busy-descendant-indicatorfrom
feat/agents-view-costs

Conversation

@snimu

@snimu snimu commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Adds token and cost details to every agents view row, in the user-specified format:

↑12k ↓1.2k · $0.42 ($1.10 w/ subagents)

is input/sent tokens, output/received; the parenthesized total renders only when descendants added spend visible at cent rounding — a leaf row reads ↑500 ↓50 · $0.68.

Linear: RES-1258 (https://linear.app/primeintellect/issue/RES-1258)

Stacked on #1986 (base branch fix/agents-view-busy-descendant-indicator); will be retargeted to main after #1986 merges. Draft until then.

What the numbers mean

  • Own cost / tokens: the session's whole-file spend — every branch including forked-away ones, with child_usage_attributed entries subtracted so a child's cost is never counted twice. This is the money answer ("what did this session cost in total"), deliberately broader than /usage, which answers the context question for the current branch. Resident and on-disk rows compute the identical number, so a row never shifts at passivation or revival (pinned by a resident-vs-scan equality test on a file with a forked-away branch).
  • Recursive cost: own cost plus all descendants' own costs, computed in the view by summing the child rows' own values — it rides the same reverse breadth-first traversal as fix: count busy descendants in the agents-view subagents indicator #1986's running-subagent tally (one pass, two facts), so it is overflow-safe on deep chains (pinned at 10k depth).
  • The N turns / message-count detail on inactive rows is gone; the details cell is now usage · age (or just age when a session has no usage data). Tokens abbreviate with the house formatTokenCount (12k, 1.2k), cost with 2 decimals; the arrow glyphs follow the TUI's existing vocabulary and width handling; the details cell width adapts and the existing row truncation applies.

Producers

  • Resident rows: AgentSession.getOwnUsageSummary() computes over the already-in-memory entries via the existing computeOwnAndTotalUsage, memoized on (entry count, tail entry id) so roster flushes recompute only when entries actually changed. Measured cold cost: 0.27 ms per call at 10k entries.
  • On-disk rows: the catalog's existing per-file scan (scanSessionInfo, already line-parsing every entry, cached by size+mtime) accumulates the same total during the same loop — no new IO, no new cache, and old files get costs immediately. Known limit: entries above the scan's max line length keep their existing skip, so a multi-megabyte assistant message can undercount slightly (giant tool results carry no usage and were always skipped).
  • Wire: optional usage field (inputTokens, outputTokens, cost) on session summaries and saved-session rows; DAEMON_SCHEMA_REVISION 26 (schema-id hash re-derived per the sync test). Old daemons simply produce rows without the field and the view shows the age-only details it shows today.

Tests

Fail-unfixed on the stack base (6 pins): exact-format render (and message-count removal), transitive recursive cost with own costs intact, deep-chain traversal with cost, producer pins for active + saved rows, catalog-scan accumulation with attribution subtraction, and resident-vs-scan equality on a forked file.

Validation: agents-view suites, agent-roster, daemon-agent-roster, subagent-summary-line, daemon-session-list, session-manager file-operations, daemon-protocol (schema sync), daemon-mode, daemon-supervisor-process, daemon-stop-confirm, daemon-launch/client/routed-client, package-self-update, agent-connection-daemon — all green in a sanitized env; root npm run check green.


Note

Low Risk
Changes are display and read-only usage aggregation on session metadata; no auth, billing, or write-path behavior. Mixed daemon/client schema revisions only omit usage on older peers.

Overview
The agents view row details column now shows input/output tokens and dollar cost (e.g. ↑12k ↓1.2k · $0.42 ($1.10 w/ subagents)) instead of inactive rows’ message count. Sessions with no usage still show age only.

Own spend is exposed as SessionUsageSummary end-to-end: resident sessions via memoized getOwnUsageSummary() (whole-file totals with attributed child usage subtracted), and saved/catalog rows via the existing scanSessionInfo pass over assistant usage and child_usage_attributed entries. Live and on-disk numbers are meant to stay aligned across passivation.

Recursive totals sum each row’s own cost plus descendants (computeRecursiveCosts / recursiveCost on rows), including filtered-out children so search/scope does not shrink the parenthesized subagent total. The daemon protocol gains optional usage on session and saved-session DTOs (schema revision 26).

Reviewed by Cursor Bugbot for commit 5df8a38. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add token counts and cost details to agents-view rows

  • Adds own-session input/output token counts and dollar cost to each agents-view row, with a parenthetical recursive total when descendant costs differ from own cost
  • Introduces SessionUsageSummary type and sessionUsageSummaryFrom converter that suppresses summaries for zero-spend sessions; daemon protocol schema advances to revision 26 to carry usage on saved-session rows
  • Adds computeRecursiveCosts in agents-view-state.ts to sum own plus descendant costs across the full unified hierarchy, preserving totals even when search filtering removes child rows
  • AgentSession.getOwnUsageSummary computes own usage with child-attribution subtracted; the session metadata scanner in session-manager.ts performs the same attribution for persisted JSONL sessions
  • Behavioral Change: inactive agents-view rows no longer display the message-count detail; rows without recorded spend show age only. Daemon consumers must understand schema revision 26 (DaemonSavedSessionInfo.usage is optional).

Macroscope summarized 5df8a38.

Every agents view row with usage data now reads
`<input>/<output> | $<own> ($<recursive>)` in the details cell, replacing
the message-count detail. Own numbers are the session's whole-file spend
(every branch, forks included, attributed child usage subtracted) - the
money answer, deliberately broader than /usage's current-branch context
answer, and identical for resident and on-disk rows so nothing shifts at
passivation or revival. The recursive total rides the same reverse
breadth-first traversal as the running-subagent tally, summing each
descendant row's own cost exactly once.

Producers: resident summaries compute the total from the already-loaded
entries, memoized until entries change (0.27 ms measured cold at 10k
entries); saved rows accumulate it inside the existing mtime/size-cached
catalog scan, so old files get costs with no new IO and no new cache.
Entries over the scan's max line length keep their existing skip, so a
giant assistant message can undercount slightly. Schema revision 26
publishes the new optional summary and saved-row field.

RES-1258
@snimu
snimu marked this pull request as ready for review September 2, 2026 19:30
Comment thread packages/coding-agent/src/core/session-manager.ts
Comment thread packages/coding-agent/src/modes/agents-view/agents-view-state.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b5e3afe. Configure here.

Comment thread packages/coding-agent/src/core/session-manager.ts Outdated
Comment thread packages/coding-agent/src/modes/daemon/daemon-session-list.ts
Details cell now reads `↑12k ↓1.2k · $0.42 ($1.10 w/ subagents)`; the
parenthesized total renders only when descendants added spend visible at
cent rounding, so leaf rows read `↑500 ↓50 · $0.68`. Arrow glyphs follow
the existing TUI vocabulary (keybinding hints, token status) and the
width pipeline already treats them as single cells.

RES-1258
Review round on the usage feature:

- The catalog scan subtracted attributed child usage from disk values
  that (in append-only files) still carry the assistant's ORIGINAL
  model-response usage, double-subtracting and shifting numbers at
  passivation. Full-file rewrites (migrations, forks) can also persist
  the already-folded aggregates, so raw summation is wrong for those
  files instead. The scan now mirrors the loader exactly: fold each
  attribution's aggregate onto its target, then subtract the child usage
  - both disk representations cancel to the same own spend the resident
  computation reports. The equality pin now goes through a real v3
  flushed-then-attributed fixture (the old fixture had no attribution,
  which is why it never caught this).
- Recursive cost was computed over search-filtered rows, so a matching
  parent showed an incomplete "w/ subagents" total. The rollup now comes
  from the unfiltered record hierarchy (computeRecursiveCosts over the
  unified index) and filtering can no longer change the number.
- Zero-spend sessions published 0/0/$0.00 live and nothing once
  passivated; sessionUsageSummaryFrom now returns undefined for zero
  totals, shared by both producers, so rows stay age-only until real
  spend exists.

RES-1258
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant