open-telemetry / open-telemetry/opentelemetry-python-genai

[openai] Responses API drops function_call and function_call_output from gen_ai.input.messages

Open
#651 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
39
Forks
63
Avg merge
1d 15h
Merged PRs (30d)
175

Description

Describe your environment

OS: Linux
Python version: Python 3.14.7
Package version: opentelemetry-instrumentation-genai-openai 1.2b0.dev
GenAI library and version: openai 2.47.0

What happened?

On the Responses API path, get_input_messages skips any input item without a string role. Responses input arrives as a flat item list, so function_call and function_call_output items carry no role and never reach gen_ai.input.messages.

A model call that follows a tool call therefore records only the original user message, and no tool_call_response part is emitted anywhere. The recorded conversation is not just incomplete, it misleads: the span shows the model answering with no visible tool result, and the recorded input token count contradicts the recorded message list.

Steps to Reproduce

Run a two-turn tool loop with the plain openai SDK, no agent framework, with content capture enabled:

first = client.responses.create(
model="gpt-4o-mini",
input=[{"role": "user", "content": "What's the weather in Seattle?"}],
tools=[weather_tool],
)

history = [{"role": "user", "content": "What's the weather in Seattle?"}]
history.extend(first.output) # the function_call item
history.append({
"type": "function_call_output",
"call_id": first.output[0].call_id,
"output": "Sunny, 18C",
})

client.responses.create(model="gpt-4o-mini", input=history, tools=[weather_tool])

Then compare the second request body against the second span's gen_ai.input.messages.

Expected Result

Three messages, matching the three items sent on the wire: the user turn, an assistant message holding a tool_call part, and a tool message holding a tool_call_response part whose id matches the tool_call.

This is the shape the semantic conventions show for a tool loop, and opentelemetry-instrumentation-genai-anthropic already records it that way given an equivalent history.

Actual Result

One message. Both tool items are dropped:

wire request #2: input items=3 types=['user', 'function_call', 'function_call_output']
span : gen_ai.input.messages = 1 msg
[{"role":"user","parts":[{"content":"What's the weather in Seattle?","type":"text"}]}]
gen_ai.usage.input_tokens = 129

129 input tokens against a single short user message.

Additional context

No response

Would you like to implement a fix?

Yes

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at get_input_messages on the Responses API path and reproduce the two-turn tool loop with the plain OpenAI SDK and content capture enabled. Compare the second request body with gen_ai.input.messages; done means the user, function_call, and function_call_output items are recorded as three messages with tool_call and tool_call_response parts, including the matching id.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
observability
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.