claude-code-sdk-python/examples/max_budget_usd.py
Ashwin Bhat ae800c5ec8
feat: add max_budget_usd option to Python SDK (#293)
Add support for limiting API costs using the max_budget_usd option,
mirroring the TypeScript SDK functionality. When the budget is exceeded,
query execution stops and returns a result with subtype
'error_max_budget_usd'.

- Add max_budget_usd field to ClaudeAgentOptions
- Pass --max-budget-usd flag to Claude Code CLI
- Add test coverage for budget limit behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-30 16:45:35 -07:00

95 lines
3 KiB
Python

#!/usr/bin/env python3
"""Example demonstrating max_budget_usd option for cost control."""
import anyio
from claude_agent_sdk import (
AssistantMessage,
ClaudeAgentOptions,
ResultMessage,
TextBlock,
query,
)
async def without_budget():
"""Example without budget limit."""
print("=== Without Budget Limit ===")
async for message in query(prompt="What is 2 + 2?"):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage):
if message.total_cost_usd:
print(f"Total cost: ${message.total_cost_usd:.4f}")
print(f"Status: {message.subtype}")
print()
async def with_reasonable_budget():
"""Example with budget that won't be exceeded."""
print("=== With Reasonable Budget ($0.10) ===")
options = ClaudeAgentOptions(
max_budget_usd=0.10, # 10 cents - plenty for a simple query
)
async for message in query(prompt="What is 2 + 2?", options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage):
if message.total_cost_usd:
print(f"Total cost: ${message.total_cost_usd:.4f}")
print(f"Status: {message.subtype}")
print()
async def with_tight_budget():
"""Example with very tight budget that will likely be exceeded."""
print("=== With Tight Budget ($0.0001) ===")
options = ClaudeAgentOptions(
max_budget_usd=0.0001, # Very small budget - will be exceeded quickly
)
async for message in query(
prompt="Read the README.md file and summarize it", options=options
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Claude: {block.text}")
elif isinstance(message, ResultMessage):
if message.total_cost_usd:
print(f"Total cost: ${message.total_cost_usd:.4f}")
print(f"Status: {message.subtype}")
# Check if budget was exceeded
if message.subtype == "error_max_budget_usd":
print("⚠️ Budget limit exceeded!")
print(
"Note: The cost may exceed the budget by up to one API call's worth"
)
print()
async def main():
"""Run all examples."""
print("This example demonstrates using max_budget_usd to control API costs.\n")
await without_budget()
await with_reasonable_budget()
await with_tight_budget()
print(
"\nNote: Budget checking happens after each API call completes,\n"
"so the final cost may slightly exceed the specified budget.\n"
)
if __name__ == "__main__":
anyio.run(main)