← Back to PRs

#10006: feat: add append-only spend ledger for token usage tracking

by oldeucryptoboi open 2026-02-06 00:46 View on GitHub →
gateway commands stale
## Summary - Adds an append-only JSONL spend ledger (`~/.openclaw/state/spend.jsonl`) that records one line per LLM call, replacing the need to re-scan all session transcripts for usage queries - Maintains an in-memory `SpendAggregator` with daily, per-provider, and per-model breakdowns that rebuilds from the ledger on gateway startup and stays current as new entries append - Adds a new `usage.spend` gateway endpoint with `days`, `provider`, `model`, `agentId`, and `groupBy` query params for instant aggregated results - Hooks both code paths that make LLM calls: channel-routed messages (`agent-runner.ts`) and CLI agent commands (`commands/agent.ts`) via a shared `recordSpendFromResult` helper ## Changed files **New:** - `src/infra/spend-ledger.ts` — Core ledger module (SpendEntry, append/load, SpendAggregator, recordSpendFromResult) - `src/infra/spend-ledger.test.ts` — 13 unit tests - `src/auto-reply/reply/agent-runner.spend-ledger.test.ts` — 2 integration tests (channel path) - `src/commands/agent.spend-ledger.test.ts` — 3 integration tests (CLI path) **Modified:** - `src/auto-reply/reply/agent-runner.ts` — Record spend on channel-routed messages - `src/commands/agent.ts` — Record spend on CLI agent commands - `src/gateway/server-methods/usage.ts` — Add `usage.spend` endpoint - `src/gateway/server.impl.ts` — Init spend aggregator on gateway startup ## Test plan - [x] `pnpm build` passes - [x] `pnpm check` (tsgo + oxlint + oxfmt) passes with 0 errors - [x] 18 new tests pass across 3 test files - [x] Full test suite passes (pre-existing `src/memory/` failures on Node 20 only) - [x] Manual e2e: started gateway, sent 3 messages via Anthropic API, verified `spend.jsonl` entries and `usage.spend` endpoint returns correct aggregations 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR introduces an append-only JSONL spend ledger and an in-memory `SpendAggregator` that rebuilds from the ledger on gateway startup, plus a new `usage.spend` gateway method for querying aggregated spend by time/provider/model/agent. Spend recording is hooked into both main LLM execution paths (`src/auto-reply/reply/agent-runner.ts` and `src/commands/agent.ts`) via a shared `recordSpendFromResult()` helper, and tests cover both module behavior and the two integration call sites. <h3>Confidence Score: 3/5</h3> - This PR is close, but has a few correctness issues that should be fixed before merge. - Core approach (append-only ledger + in-memory aggregator + endpoint + call-site hooks) is straightforward and well-tested, but there are clear functional issues: directory creation is cached globally across paths, `groupBy=day` is accepted but not implemented, and the resolved ledger path appears inconsistent with the documented location depending on what `resolveStateDir()` returns. - src/infra/spend-ledger.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs