Skip to content

fix(openai): use call_id as the Responses tool call id - #4632

Open
pcbeingused333 wants to merge 2 commits into
traceloop:mainfrom
pcbeingused333:fix/openai-responses-tool-call-id
Open

pcbeingused333 wants to merge 2 commits into
traceloop:mainfrom
pcbeingused333:fix/openai-responses-tool-call-id

Conversation

@pcbeingused333

@pcbeingused333 pcbeingused333 commented Oct 17, 2026 •

Copy link
Copy Markdown

What

A Responses API function_call has two ids: the item id (fc_...) and the call_id (call_...). The function_call_output sent back to the model refers to the call by call_id, and the instrumentation already records call_id as the tool_call_response part id. But the tool call part itself was recorded with the item id:

  • gen_ai.output.messages: "id": block_dict.get("id"), so always fc_....
  • gen_ai.input.messages: "id": block_dict.get("id") or block_dict.get("call_id"), so fc_... whenever the replayed item keeps its id (it does when you pass response.output back).

So a tool call and its response never had matching ids. In the GenAI semantic conventions they're meant to carry the same tool call id, so traces can't pair them.

Change

responses_wrappers.py now uses call_id for the tool call part id on both sides, falling back to the item id when call_id is absent.

Tests

  • test_responses_tool_calls now also checks the output tool call ids against the existing cassette's real call_ids (call_tYDv1b…, call_lC079U…; the items are fc_685ff894…). It fails on main and passes with the change.
  • New test_responses_input_tool_call_id_matches_tool_call_response: a follow-up turn whose input has the function_call item (with both ids) and its function_call_output. The tool call and tool call response ids must match. It fails on main and passes with the change.
  • packages/opentelemetry-instrumentation-openai tests: 297 passed, 1 skipped. 2 failures in test_responses_with_raw_response_streaming_does_not_crash (sync/async) are a typing.Union / __discriminator__ error from openai 1.99.7 in this local environment and fail the same way on main.
  • ruff check clean.

Also seen on a real streamed Responses call to gpt-oss on Bedrock's OpenAI-compatible endpoint: the function call item has id: fc_a723… and call_id: call_95e0…, so the same mismatch.

This PR was made with Claude Code (Anthropic); the tests above were run on main and on this branch.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Function-call traces now consistently use the call ID for both input and output messages, falling back to the item ID when no call ID is available.

Responses function_call items have an item id (fc_...) and a call_id
(call_...). The function_call_output sent back to the model refers to the
call by call_id, and the instrumentation already records that as the
tool_call_response id, but the tool call itself was recorded with the item
id in gen_ai.output.messages, and with the item id first in
gen_ai.input.messages. The ids of a tool call and its response never
matched. Use call_id for the tool call id, falling back to the item id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Oct 17, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4b1c89e4-e961-47fa-bd0b-661cc7fdf4be
📥 Commits

Reviewing files that changed from the base of the PR and between bd1fd9a and 94f3a05.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b7f49edf-0b87-4340-80e3-c1fa93858a94
📥 Commits

Reviewing files that changed from the base of the PR and between 94d3f04 and bd1fd9a.

📒 Files selected for processing: 2
  • packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/v1/responses_wrappers.py
  • packages/opentelemetry-instrumentation-openai/tests/traces/test_responses.py

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.

📝 Walkthrough

Function-call input and output serialization now use call_id as the tool-call ID when available, with id as a fallback. Tests verify the recorded IDs for traced tool calls and replayed function-call input and output.

Changes: Function-call tool-call IDs

Layer / File(s) Summary
Function-call ID serialization and validation
packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/v1/responses_wrappers.py, packages/opentelemetry-instrumentation-openai/tests/traces/test_responses.py
Input and output serialization prefer call_id over id. Tests check that traced tool calls and matching replayed input and output use the call ID.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: max-deygin-traceloop

Merge Risk: ⚪ Minimal · up to bd1fd

No actionable merge-blocking risk is identified; the change is ready for normal merge checks.

Security architecture risk: ⚪ Minimal · up to bd1fd

The change aligns traced tool calls with their responses while retaining the item-ID fallback. Inspection found no introduced tool-execution authority, access-control change, or material security risk.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated exposure change is limited to correlation identifiers in existing trace-message attributes. In the inspected path, supplied call identifiers become telemetry metadata rather than execution targets, credentials, or authorization identities.

Trust Boundaries and Controls

  • observed — The existing set_data_attributes caller invokes message serialization under should_send_prompts. This gate and the span-attribute destinations are unchanged by the PR; the identifier preference does not bypass that existing control.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: using call_id as the OpenAI Responses tool call ID.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants