"""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