diff --git a/agent/usage_pricing.py b/agent/usage_pricing.py index 5cacdb04a9..1b4a5e2fb7 100644 --- a/agent/usage_pricing.py +++ b/agent/usage_pricing.py @@ -1283,8 +1283,16 @@ def normalize_usage( ) input_tokens = max(0, input_total - cache_read_tokens - cache_write_tokens) else: - prompt_total = _to_int(getattr(response_usage, "prompt_tokens", 0)) - output_tokens = _to_int(getattr(response_usage, "completion_tokens", 0)) + # OpenAI-style names first; fall back to Anthropic-style + # (input_tokens/output_tokens). Local OpenAI-compatible servers like + # mlx_vlm.server emit the Anthropic names in chat_completions responses, + # and the OpenAI Python client preserves them as extra attributes. + prompt_total = _to_int(getattr(response_usage, "prompt_tokens", 0)) or _to_int( + getattr(response_usage, "input_tokens", 0) + ) + output_tokens = _to_int(getattr(response_usage, "completion_tokens", 0)) or _to_int( + getattr(response_usage, "output_tokens", 0) + ) details = getattr(response_usage, "prompt_tokens_details", None) # Primary: OpenAI-style prompt_tokens_details. Fallback: Anthropic-style # top-level fields that some OpenAI-compatible proxies (OpenRouter, Vercel