Describe the bug
openinference-instrumentation-google-adk does not map ADK tool-call IDs to OpenInference attributes on the result side of a tool turn:
- Tool-result LLM messages —
llm.input_messages with message.role=tool get message.name and message.content, but not message.tool_call_id.
- TOOL spans —
execute_tool {name} spans have ADK's gen_ai.tool.call.id and the ID inside output.value JSON, but not OI tool.id.
Output-side correlation already works (llm.output_messages.*.message.tool_calls.*.tool_call.id is populated). The gap is partial: request side OK, result side missing.
Verified on google-adk 1.2.1 and 1.17.0 with instrumentor v0.1.15 (stub-LLM repro, no API key).
To Reproduce
- Instrument an ADK agent with
GoogleADKInstrumentor.
- Use a stub
BaseLlm that returns a tool call with a known ID, e.g. FunctionCall(id="call_ny_abc123", name="get_weather", args={"city": "New York"}), then a text synthesis response.
- Register a simple tool
get_weather that returns {"status": "success", "report": "..."}.
- Run one turn via
InMemoryRunner and export spans with InMemorySpanExporter.
Observed:
| Location |
Expected |
Actual |
Synthesis call_llm → tool-role message (llm.input_messages.N) |
message.tool_call_id = call_ny_abc123 |
missing |
execute_tool get_weather span |
tool.id = call_ny_abc123 |
missing |
| Same tool span (ADK) |
— |
gen_ai.tool.call.id = call_ny_abc123 ✓ |
Tool span output.value |
— |
{"id":"call_ny_abc123","name":"get_weather",...} ✓ |
Turn-1 call_llm output |
tool_call.id on output tool_calls |
present ✓ |
Expected behavior
Per OpenInference spec (spec/tool_calling.md, spec/semantic_conventions.md):
- Tool-result messages should include
message.tool_call_id linking back to the original tool_call.id.
execute_tool TOOL spans should include tool.id with the same value.
This enables correlating tool calls → tool execution → tool results in multi-hop agent traces (e.g. Phoenix).
Screenshots
N/A for the gap itself. Happy to attach a Phoenix trace screenshot in the PR if maintainers want one after the fix.
Desktop (please complete the following information):
- OS: macOS
- Version: google-adk 1.2.1 (also reproduced on 1.17.0); openinference-instrumentation-google-adk 0.1.15
Additional context
Root cause (src/openinference/instrumentation/google_adk/_wrappers.py):
_get_attributes_from_parts (~504–514): function_response branch emits role/name/content but never reads function_response.id.
_TraceToolCall (~346–358): sets output.value from responses[0].model_dump_json() but never sets SpanAttributes.TOOL_ID.
_get_attributes_from_function_response (~550) is defined but never called (dead code; also emits tool_call.id, not message.tool_call_id, if wired naively).
Proposed fix (~5 lines):
- In
function_response branch: if function_response.id: yield message.tool_call_id
- In
_TraceToolCall: if responses[0].id: span.set_attribute(SpanAttributes.TOOL_ID, responses[0].id)
Constants already exist: SpanAttributes.TOOL_ID (tool.id), MessageAttributes.MESSAGE_TOOL_CALL_ID (message.tool_call_id).
I can submit a small PR with stub-LLM tests once a maintainer confirms this is wanted.
Describe the bug
openinference-instrumentation-google-adkdoes not map ADK tool-call IDs to OpenInference attributes on the result side of a tool turn:llm.input_messageswithmessage.role=toolgetmessage.nameandmessage.content, but notmessage.tool_call_id.execute_tool {name}spans have ADK'sgen_ai.tool.call.idand the ID insideoutput.valueJSON, but not OItool.id.Output-side correlation already works (
llm.output_messages.*.message.tool_calls.*.tool_call.idis populated). The gap is partial: request side OK, result side missing.Verified on
google-adk1.2.1 and 1.17.0 with instrumentor v0.1.15 (stub-LLM repro, no API key).To Reproduce
GoogleADKInstrumentor.BaseLlmthat returns a tool call with a known ID, e.g.FunctionCall(id="call_ny_abc123", name="get_weather", args={"city": "New York"}), then a text synthesis response.get_weatherthat returns{"status": "success", "report": "..."}.InMemoryRunnerand export spans withInMemorySpanExporter.Observed:
call_llm→ tool-role message (llm.input_messages.N)message.tool_call_id = call_ny_abc123execute_tool get_weatherspantool.id = call_ny_abc123gen_ai.tool.call.id = call_ny_abc123✓output.value{"id":"call_ny_abc123","name":"get_weather",...}✓call_llmoutputtool_call.idon output tool_callsExpected behavior
Per OpenInference spec (
spec/tool_calling.md,spec/semantic_conventions.md):message.tool_call_idlinking back to the originaltool_call.id.execute_toolTOOL spans should includetool.idwith the same value.This enables correlating tool calls → tool execution → tool results in multi-hop agent traces (e.g. Phoenix).
Screenshots
N/A for the gap itself. Happy to attach a Phoenix trace screenshot in the PR if maintainers want one after the fix.
Desktop (please complete the following information):
Additional context
Root cause (
src/openinference/instrumentation/google_adk/_wrappers.py):_get_attributes_from_parts(~504–514):function_responsebranch emits role/name/content but never readsfunction_response.id._TraceToolCall(~346–358): setsoutput.valuefromresponses[0].model_dump_json()but never setsSpanAttributes.TOOL_ID._get_attributes_from_function_response(~550) is defined but never called (dead code; also emitstool_call.id, notmessage.tool_call_id, if wired naively).Proposed fix (~5 lines):
function_responsebranch:if function_response.id: yield message.tool_call_id_TraceToolCall:if responses[0].id: span.set_attribute(SpanAttributes.TOOL_ID, responses[0].id)Constants already exist:
SpanAttributes.TOOL_ID(tool.id),MessageAttributes.MESSAGE_TOOL_CALL_ID(message.tool_call_id).I can submit a small PR with stub-LLM tests once a maintainer confirms this is wanted.