Skip to content

Python: [Bug]: the Mistral chat client drops prompt_tokens_details.cached_tokens, so prompt-cache hits are invisible in UsageDetails #7589

Description

Description

Summary

agent_framework_mistral's RawMistralChatClient._parse_usage reads only the three top-level counts from a chat-completion usage payload — prompt_tokens, completion_tokens, total_tokens — and discards prompt_tokens_details. Mistral La Plateforme reports prompt-caching hits there (usage.prompt_tokens_details.cached_tokens, the same field name OpenAI uses), so any application using the Mistral client cannot see how much of a prompt was served from cache: UsageDetails["cache_read_input_token_count"] — the framework's standard key for exactly this figure — is never populated on Mistral responses.

Why it matters

Mistral bills cached prompt tokens at 10% of the standard input rate (see Mistral's prompt caching documentation). Without the mapping, cost accounting and GenAI telemetry built on UsageDetails read cached prompt reads at face value — for a long agentic conversation with a stable prefix that can overstate real input cost by up to 10×. The asymmetry is the surprising part: the framework already maps the equivalent field on every comparable first-party client, so cross-provider usage dashboards silently lose one provider.

  • agent_framework_openai (chat completions): maps usage.prompt_tokens_details.cached_tokenscache_read_input_token_count.
  • agent_framework_openai (responses): maps usage.input_tokens_details.cached_tokenscache_read_input_token_count.
  • agent_framework_gemini: maps cached_content_token_countcache_read_input_token_count.
  • agent_framework_mistral: drops the field.

Notably, the Mistral client already declares prompt_cache_key as a supported chat option — the request half of the caching feature is wired, so a caller can opt in to caching but cannot observe what it got back.

Reproduction

  1. Send two identical chat-completion requests through MistralChatClient with a shared prefix ≥ 64 tokens and the same prompt_cache_key chat option.
  2. The second response's raw payload carries e.g. "usage": {"prompt_tokens": 1000, "completion_tokens": 12, "total_tokens": 1012, "prompt_tokens_details": {"cached_tokens": 896}}.
  3. The parsed UsageDetails on the response contains only input_token_count=1000, output_token_count=12, total_token_count=1012cache_read_input_token_count is absent.

Proposed behavior

In RawMistralChatClient._parse_usage, when the payload carries prompt_tokens_details as a mapping with an integer cached_tokens, set details["cache_read_input_token_count"] to it — mirroring the OpenAI chat-completions client's handling of the identically-named field. The value is documented by Mistral as a subset of prompt_tokens (billed at the discounted rate), matching the semantics cache_read_input_token_count already has for the other providers. Both the non-streaming path and the final streaming chunk's usage go through the same _parse_usage, so one change covers both.

Code Sample

Language/SDK

Python

Metadata

Metadata

Labels

agentsUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions