Files
Jiayuan Zhang ba129b1963 feat(issues): show per-run token usage on the execution log (MUL-5762) (#6440)
* feat(issues): show per-run token usage on the execution log (MUL-5762)

The execution log already lists every agent run on an issue; it just
never said what any of them cost. task_usage has held per-task token
counts since migration 032 — nothing surfaced them per run.

Three placements, one data source:

- Execution-log header carries the issue total ("2.1M · $4.92") and
  opens the breakdown.
- Each row carries its own token figure. This takes the slot the
  relative timestamp held: the sidebar is 288px and a third column
  would come out of the trigger text, which is what people scan. The
  list is sorted newest-first, so ordinal recency is already free; the
  timestamp moves into the row tooltip alongside duration and model,
  neither of which was surfaced there before.
- The transcript dialog gets the same figure in its header, with the
  input/output/cache split in the run-info popover.

Backend: ListIssueTaskUsage returns per-(task, provider, model) rows in
one query, joined onto the existing task-runs response. The model
dimension stays on the wire because cost is priced client-side per
model — a row that collapsed two models cannot be priced at all.

Cost reuses estimateCost from the runtime usage page, so the issue and
the workspace never disagree; the new summarizeTaskUsage helpers live
next to it rather than starting a second cost formula.

No usage recorded stays distinguishable from zero end to end — omitted
on the wire, undefined in the schema, null from the summarizer, an em
dash in the UI. A run from before usage reporting was not free.

Removes the standalone "Token usage" sidebar section: it showed the
same issue totals minus the cost and minus any way to attribute them,
and every field it had is in the dialog. The /api/issues/:id/usage
endpoint it read stays — the CLI's `issue usage` still uses it.

Co-authored-by: multica-agent <github@multica.ai>

* fix(issues): address review on per-run token usage (MUL-5762)

Three findings from @Emacs, all confirmed against the code:

1. Drop the token figure from active rows. The daemon reports usage
   once, after `runner.run` returns (internal/daemon/daemon.go), and
   ReportTaskUsage publishes no realtime event — so a running task has
   no usage to show and would not learn of it mid-run if it did. The
   branch was only ever exercised by a hand-written fixture, which is a
   test asserting a scenario production cannot produce. The row keeps
   its timer; restore the figure in the same change that adds
   incremental reporting + cache invalidation.

2. Subscribe the usage surfaces to the custom-pricing store. estimateCost
   reads custom rates imperatively via getCustomPricing(), so nothing
   re-rendered these after a saved rate change — the header total, the
   dialog's totals and per-run costs, the cost-by-agent split, and the
   "unmapped model" notice all kept quoting the old price until the task
   list happened to refetch. Same subscription the runtime usage page
   already carries, plus the snapshot in every memo that prices usage.
   Regression test pinned: it fails without the subscription.

3. Give the dialog's status glyph an sr-only label. TaskStatusIcon is
   aria-hidden, so a screen reader could not tell a failed run from a
   completed one — the execution log rows already pair the two.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Lambda <lambda@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
2026-08-05 19:14:33 +08:00
..