Repository navigation
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:
- Non-streaming:
ResponseWrapper._parse_event_from_resultreads onlyresult.usage. - Streaming:
ResponseWrapper._postprocess_streaming_resultsreads onlyusagefrom the terminalresponse.completed/response.incomplete/response.failedevent. - Metadata:
_RESPONSES_RESULT_METADATA_KEYSis where response-level fields are copied into metadata. - Metrics parsing:
_parse_metrics_from_usageis shared by every endpoint. Don't change it for this.
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 emitsserver_tool_use_*metrics (for exampleserver_tool_use_web_search_requests) inanthropic/_utils.py. Matching that naming would keep providers consistent, but confirm it against the spec first.image_gentoken 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 toprompt_tokens/completion_tokens.- Fallback: if unsure, log the whole object as
metadata.tool_usageand 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.yamlends with"web_search": {"num_requests": 1}. - Other tests:
test_openai_responses_metrics[sync|async]and others include zeroedtool_usageblocks.
Steps:
- Extend
test_openai_responses_web_search_tool_spansand its_streamvariant (L535) to assert the new field on the LLM span. - 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 toleratetool_usagebeing absent orNone. - 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.
Activity