Skip to content

openai: capture Response.tool_usage (hosted tool usage, openai>=3.41) #1040

Closed

Description

Summary

openai-python 3.41.0 added Response.tool_usage (openai/openai-python#4201, "add response tool usage models"). It reports hosted-tool usage separately from the base model usage. Our Responses tracing only reads response.usage, so this data is dropped from spans.

Found while reviewing the weekly dependency bump in #1037 (openai 3.37.0 → 3.42.1).

What the SDK exposes

openai.types.responses.Response.tool_usage: Optional[ToolUsage] (also on types/beta/beta_response.py):

ToolUsage
  image_gen: ToolUsageImageGen
    input_tokens, output_tokens, total_tokens: int
    input_tokens_details: {image_tokens, text_tokens}
    cached_tokens: Optional[int]
    cached_tokens_details: Optional[{cached_image_tokens, cached_text_tokens}]
    output_tokens_details: Optional[{image_tokens, text_tokens}]
  web_search: ToolUsageWebSearch
    num_requests: int

Where our code ignores it

All in integrations/openai/tracing.py:

Design note: metric names

The braintrust-spec token-and-cost-metrics guide says "SDKs MUST NOT invent custom metrics such as tool_use_tokens for provider-specific categories". So:

  • web_search.num_requests: our closest precedent is the anthropic integration. It already emits server_tool_use_* metrics (for example server_tool_use_web_search_requests) in anthropic/_utils.py. Matching that naming would keep providers consistent, but confirm it against the spec first.
  • image_gen token counts: decide whether these belong in metadata (metadata.tool_usage) or in canonical token fields. They are billed separately from model tokens, so do not add them to prompt_tokens / completion_tokens.
  • Fallback: if unsure, log the whole object as metadata.tool_usage and skip new metrics.

Testing (no new recording needed)

The latest cassettes re-recorded in #1037 already contain tool_usage in the responses:

  • Web search: openai/cassettes/latest/test_openai_responses_web_search_tool_spans_stream.yaml ends with "web_search": {"num_requests": 1}.
  • Other tests: test_openai_responses_metrics[sync|async] and others include zeroed tool_usage blocks.

Steps:

  1. Extend test_openai_responses_web_search_tool_spans and its _stream variant (L535) to assert the new field on the LLM span.
  2. Gate the assertions on openai >= 3.41.0. Older matrix pins (1.71.0, 1.77.0, 1.92.0) don't have the field, so the code must tolerate tool_usage being absent or None.
  3. Run cd py && nox -s "test_openai(latest)", then check that the older pins still pass.

Out of scope / related

openai 3.38–3.42 also added untraced resources (beta.agents.automations, admin.organization.external_keys, and new Realtime decision types). File those separately if needed.

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions