fabro/lib
Bryan Helmkamp 2b6fcdbb80
Bill subagent spend to stages and make live usage loss-proof
Stage billing previously counted only the parent session's own LLM
calls. SubAgentResult carried no usage, so when a stage completed, the
authoritative billing replaced the live event-accumulated total with a
main-session-only number and every child session's spend vanished. On a
real run this collapsed a ~$175 total to ~$10.

Fix, part 1 — child spend reaches the parent's totals:
- SubAgentSupervisor keeps a spend ledger (SessionSpend). The child
  runner records last_input_usage/last_input_cost after every
  generation, including failed turns.
- The parent session drains the ledger into its input totals before
  publishing them, so AgentApiBackend::record_input_usage bills the
  whole session tree. Nested subagents compose: grandchildren drain
  into the child, whose runner records into the parent.

Fix, part 2 — the live number rides the same data:
- Each session emits a monotonic lifetime counter of its own spend
  (session_spend on AssistantMessage, session_billing on agent.message
  events, spec'd in fabro-api.yaml).
- The projection keeps the latest counter per session at the run level
  and attributes only the delta to the stage a message belongs to, so
  dropped or replayed events can no longer lose or double-count spend,
  and sessions reused across stages (shared threads) bill each stage
  for exactly its own turns. Legacy events without the counter fall
  back to per-message summing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 18:27:56 -04:00
..
apps Bill subagent spend to stages and make live usage loss-proof 2026-08-06 18:27:56 -04:00
components Bill subagent spend to stages and make live usage loss-proof 2026-08-06 18:27:56 -04:00
foundation Bill subagent spend to stages and make live usage loss-proof 2026-08-06 18:27:56 -04:00
packages/fabro-api-client Bill subagent spend to stages and make live usage loss-proof 2026-08-06 18:27:56 -04:00