Skip to content

[bot] Mistral: prompt-caching cached_tokens usage metric silently dropped #678

Description

@braintrust-bot

Gap

Mistral's chat completion API supports prompt caching, and reports it via a nested usage.prompt_tokens_details.cached_tokens field. The Braintrust Mistral integration's usage-metrics parser only handles flat numeric fields on the usage object and silently drops any nested *_details dict, so cached_tokens never reaches a span's metrics — even though the provider is reporting it.

What is missing

_parse_usage_metrics (py/src/braintrust/integrations/mistral/tracing.py:415-429) does:

def _parse_usage_metrics(usage: Any) -> dict[str, float]:
    usage_data = _normalized_mistral_dict(usage)
    if usage_data is None:
        return {}
    metrics = {}
    for key, value in usage_data.items():
        if not _is_supported_metric_value(value):
            continue
        metrics[_TOKEN_NAME_MAP.get(key, _camel_to_snake(key))] = float(value)
    ...

_is_supported_metric_value rejects non-numeric values, so when usage_data["prompt_tokens_details"] is itself a dict (e.g. {"cached_tokens": 128}), the whole prompt_tokens_details entry is skipped — there is no recursive/nested-details handling. _normalized_mistral_dict (tracing.py:250) just type-checks/normalizes to a plain dict; it does not flatten nested detail objects either.

This is a materially lower level of detail than comparable usage-metric parsing elsewhere in this repo. The shared OpenAI-shape helper _parse_openai_usage_metrics (py/src/braintrust/integrations/utils.py:649-690) explicitly walks any *_tokens_details dict and emits {prefix}_{nested_name} metrics (e.g. prompt_cached_tokens), and providers that reuse it (LiteLLM, OpenRouter) capture cached/reasoning token details generically. Mistral's parser has no equivalent path.

Braintrust docs status

unclear/docs-drift — the Mistral integration page documents the TypeScript SDK as capturing "cached and reasoning tokens when the provider reports them," but the Python section only lists "Token usage metrics (prompt, completion, total) and request metadata" — no mention of cached or reasoning tokens for Python. This matches the code: the TS side has parity for this field, the Python parser does not.

Upstream sources

Braintrust docs sources

Local repo files inspected

  • py/src/braintrust/integrations/mistral/tracing.py:39-41_TOKEN_NAME_MAP = {"total_tokens": "tokens"}, no details-prefix map
  • py/src/braintrust/integrations/mistral/tracing.py:250-252_normalized_mistral_dict, does not recurse into nested dict values
  • py/src/braintrust/integrations/mistral/tracing.py:415-429_parse_usage_metrics, drops any non-numeric (dict) usage entry, including prompt_tokens_details
  • py/src/braintrust/integrations/utils.py:649-690_parse_openai_usage_metrics, the comparable helper other integrations reuse that does walk *_tokens_details dicts
  • py/src/braintrust/integrations/litellm/tracing.py — imports/uses _parse_openai_usage_metrics (aliased _parse_metrics_from_usage), confirming nested detail capture works generically elsewhere
  • py/src/braintrust/integrations/openrouter/tracing.py:33-52 — explicit prompt_tokens_details/completion_tokens_details prefix mapping, another working comparable

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions