iiRecord
Agentic AI Atlas · Cost tracking
page:docs-agent-mux-tutorials-cost-trackinga5c.ai
II.
Page JSON

page:docs-agent-mux-tutorials-cost-tracking

Structured · live

Cost tracking json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/agent-mux/tutorials/cost-tracking.mdCluster · wiki
Record JSON
{
  "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"
    }
  ]
}