Tutorials · Claude Agent SDK · examples / python / 16_cost_tracking.pyExample code

Example code · python

16_cost_tracking.py

Cost and usage: per-step usage deduplicated by message_id, result totals, cache tokens.

Raw fileDownload all examples (zip)See its output →

Used in Part 3 §2 · Watching the money: cost and usage

"""16: Cost and usage: per-step usage deduplicated by message_id, result totals, cache tokens."""

import asyncio

from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, ResultMessage, query
from demo_util import PROJECT


async def main():
    seen_ids = set()
    input_tokens = 0
    steps = 0

    async for message in query(
        prompt="Read src/utils.py and src/app.py and tell me which one is longer.",
        options=ClaudeAgentOptions(cwd=PROJECT, allowed_tools=["Read"], max_turns=5, effort="low"),
    ):
        if isinstance(message, AssistantMessage) and not message.parent_tool_use_id:
            # Parallel tool calls share one message_id: count each API step once
            if message.message_id not in seen_ids:
                seen_ids.add(message.message_id)
                steps += 1
                u = message.usage or {}
                input_tokens += u.get("input_tokens", 0)
                print(f"step {steps}: message_id={message.message_id[:14]}... "
                      f"input={u.get('input_tokens')} cache_read={u.get('cache_read_input_tokens')} "
                      f"cache_create={u.get('cache_creation_input_tokens')} stop={message.stop_reason}")
        elif isinstance(message, ResultMessage):
            u = message.usage or {}
            print(f"\nresult.usage: input={u.get('input_tokens')} output={u.get('output_tokens')} "
                  f"cache_read={u.get('cache_read_input_tokens')} cache_create={u.get('cache_creation_input_tokens')}")
            print(f"result.total_cost_usd: ${message.total_cost_usd:.4f}  (client-side estimate)")
            print(f"result.duration_ms={message.duration_ms} duration_api_ms={message.duration_api_ms} num_turns={message.num_turns}")
            for model, mu in (message.model_usage or {}).items():
                print(f"result.model_usage[{model}]: cost=${mu['costUSD']:.4f} contextWindow={mu['contextWindow']} "
                      f"costBasis={mu.get('costBasis')}")

    print(f"\nDeduplicated steps: {steps}, summed input tokens: {input_tokens}")


asyncio.run(main())

42 lines · Back to the folder