Skip to content

feat: expose cache efficiency metrics in cozempic diagnose (cache hit rate, server tool costs) #45

Description

@junaidtitan

Discovery

Every assistant message in the JSONL contains a usage object with full cache and server tool metrics:

{
  "cache_creation": {
    "ephemeral_1h_input_tokens": 45000,
    "ephemeral_5m_input_tokens": 12000
  },
  "cache_read_input_tokens": 38000,
  "input_tokens": 2100,
  "output_tokens": 450,
  "server_tool_use": {
    "web_search_requests": 3,
    "web_fetch_requests": 5
  }
}

Currently cozempic diagnose only shows total token count and context %. It ignores cache efficiency entirely.

New Metrics for diagnose

Cache Efficiency:
  Cache hit rate:      73.2%   (38K of 52K input tokens from cache)
  Cache creation:      12.0K   (ephemeral 5-min) + 4.5K (ephemeral 1-hour)
  Effective cost:      ~0.31x  (cache reads cost ~0.1x vs full input tokens)

Server Tool Costs:
  Web searches:        47      (billed per search)
  Web fetches:         23      (billed per fetch)

Turn-by-Turn Cache Health:
  Turn 1:  0% cache (cold start)
  Turn 5:  45% cache
  Turn 12: 78% cache
  Turn 20: 82% cache ← stable

Why It Matters

Low cache hit rate = the session prompt is changing significantly each turn, destroying cache efficiency. This is often caused by:

  • Dynamic content in system prompt (timestamps, git status that changes)
  • CLAUDE.md files that change frequently
  • Large tool results with timestamps/UUIDs that vary

A Cozempic treatment that stabilizes cache-busting content could save 60-80% of token costs without reducing context size.

Implementation

Add cache_efficiency(messages) to diagnosis.py:

def cache_efficiency(messages):
    total_cache_read = 0
    total_cache_create = 0
    total_input = 0
    total_server_searches = 0
    total_server_fetches = 0
    
    for _, msg, _ in messages:
        if msg.get("type") != "assistant":
            continue
        usage = msg.get("message", {}).get("usage", {})
        total_cache_read += usage.get("cache_read_input_tokens", 0)
        total_cache_create += (
            usage.get("cache_creation_input_tokens", 0) +
            usage.get("cache_creation", {}).get("ephemeral_1h_input_tokens", 0) +
            usage.get("cache_creation", {}).get("ephemeral_5m_input_tokens", 0)
        )
        total_input += usage.get("input_tokens", 0)
        server = usage.get("server_tool_use", {})
        total_server_searches += server.get("web_search_requests", 0)
        total_server_fetches += server.get("web_fetch_requests", 0)
    ...

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions