Files
claude-mem/context/claude-code/agent-sdk-cost-tracking.md
T
Alex Newman f20bb5bced Add SDK usage tracking to JSONL logs
Features:
- New UsageLogger utility that writes usage metrics to daily JSONL files
- Captures token counts, costs, timing, and cache metrics from SDK result messages
- Usage logs stored in ~/.claude-mem/usage-logs/ (one file per day)
- Added analyze-usage.js script for analyzing usage patterns

Usage data captured:
- Token counts (input, output, cache creation, cache read)
- Total cost in USD per API call
- Duration metrics (total and API time)
- Number of turns per session
- Session and project attribution

Analysis script features:
- Aggregates totals by project and model
- Shows cache hit rates and savings
- Displays cost breakdowns and averages
- npm scripts: usage:analyze and usage:today

Files:
- src/utils/usage-logger.ts (new)
- src/services/worker-service.ts (modified - captures SDK result messages)
- scripts/analyze-usage.js (new)
- package.json (added usage:* npm scripts)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-02 21:53:42 -05:00

2.2 KiB

For tracking costs and tokens in your Agent SDK plugin, you have built-in programmatic access to usage data through the SDK itself(1).

Agent SDK Cost Tracking

The Claude Agent SDK provides detailed token usage information for each interaction(1). Here's how to track it:

TypeScript:

import { query } from "@anthropic-ai/claude-agent-sdk";

const result = await query({
  prompt: "Your task here",
  options: {
    onMessage: (message) => {
      if (message.type === 'assistant' && message.usage) {
        console.log(`Message ID: ${message.id}`);
        console.log(`Usage:`, message.usage);
      }
    }
  }
});

(1)

The final result message contains the total cumulative usage from all steps in the conversation(1):

console.log("Total usage:", result.usage);
console.log("Total cost:", result.usage.total_cost_usd);

(1)

Important: Avoid Double-Counting

When Claude executes tools in parallel, multiple assistant messages may share the same ID and usage data(1). You should only charge once per unique message ID(1):

const processedMessageIds = new Set<string>();

onMessage: (message) => {
  if (message.type === 'assistant' && message.usage) {
    // Skip if already processed
    if (processedMessageIds.has(message.id)) {
      return;
    }
    
    processedMessageIds.add(message.id);
    // Record usage here
  }
}

(1)

Usage Fields

Each usage object contains(1):

  • input_tokens: Base input tokens processed
  • output_tokens: Tokens generated in the response
  • cache_creation_input_tokens: Tokens used to create cache entries
  • cache_read_input_tokens: Tokens read from cache
  • total_cost_usd: Total cost in USD (only in result message)