Skip to content

fix(google-adk): map tool call IDs to OI message.tool_call_id and tool.id #3261

Description

@DavidsArista

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:

  1. Tool-result LLM messagesllm.input_messages with message.role=tool get message.name and message.content, but not message.tool_call_id.
  2. TOOL spansexecute_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

  1. Instrument an ADK agent with GoogleADKInstrumentor.
  2. 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.
  3. Register a simple tool get_weather that returns {"status": "success", "report": "..."}.
  4. 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):

  1. In function_response branch: if function_response.id: yield message.tool_call_id
  2. 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.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

Status
No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions