II.
Page JSON
Structured · livepage:docs-agent-mux-tutorials-cost-tracking
Cost tracking json
Inspect the normalized record payload exactly as the atlas UI reads it.
{
"id": "page:docs-agent-mux-tutorials-cost-tracking",
"_kind": "Page",
"_file": "wiki/docs/agent-mux/tutorials/cost-tracking.md",
"_cluster": "wiki",
"attributes": {
"nodeKind": "Page",
"sourcePath": "docs/agent-mux/tutorials/cost-tracking.md",
"sourceKind": "repo-docs",
"title": "Cost tracking",
"displayName": "Cost tracking",
"slug": "docs/agent-mux/tutorials/cost-tracking",
"articlePath": "wiki/docs/agent-mux/tutorials/cost-tracking.md",
"article": "\n# Cost tracking\n\nagent-mux emits a `cost` event whenever an adapter reports usage. You can\nread it in two ways: **live** (during `client.run`) or **retroactively**\n(from a stored session).\n\n## Live: per-run budget meter\n\n```ts\nimport { createClient } from '@a5c-ai/agent-mux';\n\nconst client = createClient();\nconst handle = client.run({ agent: 'claude-code', prompt: '…' });\n\nlet spent = 0;\nfor await (const ev of handle.events()) {\n if (ev.type === 'cost') {\n spent = ev.cost.totalUsd ?? spent;\n if (spent > 0.50) { await handle.stop('budget exceeded'); break; }\n }\n}\nawait handle.done;\n```\n\nThe final total is also available as `(await handle.done).cost`.\n\n## Retroactive: aggregate a stored session\n\n`client.sessions(agent).read(id)` returns the replayed event list — the\nsame events the live stream produced. Fold them with the exported helper:\n\n```ts\nimport { createClient, sumCost } from '@a5c-ai/agent-mux';\n\nconst sessions = createClient().sessions('claude-code');\nconst { events } = await sessions.read(sessionId);\nconst totals = sumCost(events);\nconsole.log(`$${totals.totalUsd.toFixed(4)} · ${totals.totalTokens} tok`);\n```\n\n`sumCost` accepts any `Iterable<AgentEvent>`. The async variant\n`sumCostAsync` works directly on `handle.events()`:\n\n```ts\nimport { sumCostAsync } from '@a5c-ai/agent-mux';\nconst totals = await sumCostAsync(handle.events());\n```\n\n## Filter helpers\n\n`filterEvents(events, type)` returns a narrowed iterator — useful when you\nwant every tool result, every thinking delta, etc., without writing the\nswitch yourself:\n\n```ts\nimport { filterEvents } from '@a5c-ai/agent-mux';\n\nfor (const tool of filterEvents(events, 'tool_result')) {\n // tool.toolName, tool.output, tool.durationMs are all typed\n}\n```\n\n## CLI\n\n```bash\n# Sum cost across every stored session for an agent\namux sessions list --agent claude-code --json \\\n | jq -r '.[].sessionId' \\\n | while read sid; do\n amux sessions read --agent claude-code --id \"$sid\" --json \\\n | jq '[.events[]|select(.type==\"cost\")|.cost.totalUsd]|add // 0'\n done \\\n | paste -sd+ | bc\n```\n\n## Caveats\n\n- Not every adapter reports USD. Adapters without pricing data emit\n `cost` events with `totalUsd: 0` and token counts only.\n- Cached-token pricing is adapter-specific; `sumCost` exposes\n `cachedTokens` separately so you can apply your own multiplier.\n- `cost` events may fire multiple times in one run (turn-level and\n run-level). `sumCost` adds them all — that's by design: the sum is the\n run total. If you only want the final event, use\n `(await handle.done).cost`.\n",
"documents": []
},
"outgoingEdges": [],
"incomingEdges": [
{
"from": "page:docs-agent-mux-tutorials",
"to": "page:docs-agent-mux-tutorials-cost-tracking",
"kind": "contains_page"
}
]
}