Skip to content

Commit 2a281d8

Browse files
committed
fix(oci): preserve all parallel tool results in OCI GenAI messages
Closes #6589. _content_to_oci_message only forwarded tool_results[0] to OCI GenAI, silently dropping every other parallel tool result. Return one ToolMessage per function_response part (mirroring _content_to_message_param in lite_llm.py) and flatten the messages in _build_chat_details. Adds regression tests for the multi-result path.
1 parent b1c6f44 commit 2a281d8

2 files changed

Lines changed: 69 additions & 8 deletions

File tree

src/google/adk/integrations/oci/_oci_genai_llm.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,25 @@ def _content_to_oci_message(content: types.Content) -> Any:
196196

197197
role = _to_oci_role(content.role)
198198

199-
# Tool results map to ToolMessage (one per result)
199+
# Tool results map to ToolMessage (one per result). Multiple parallel tool
200+
# results are returned as a list of ToolMessages so none are dropped;
201+
# mirror _content_to_message_param in lite_llm.py.
200202
if tool_results:
201-
call_id, result_text = tool_results[0]
202-
return oci_models.ToolMessage(
203-
role=oci_models.ToolMessage.ROLE_TOOL,
204-
tool_call_id=call_id,
205-
content=[oci_models.TextContent(type="TEXT", text=result_text)],
206-
)
203+
if len(tool_results) == 1:
204+
call_id, result_text = tool_results[0]
205+
return oci_models.ToolMessage(
206+
role=oci_models.ToolMessage.ROLE_TOOL,
207+
tool_call_id=call_id,
208+
content=[oci_models.TextContent(type="TEXT", text=result_text)],
209+
)
210+
return [
211+
oci_models.ToolMessage(
212+
role=oci_models.ToolMessage.ROLE_TOOL,
213+
tool_call_id=call_id,
214+
content=[oci_models.TextContent(type="TEXT", text=result_text)],
215+
)
216+
for call_id, result_text in tool_results
217+
]
207218

208219
if role == "ASSISTANT":
209220
oci_content: list[Any] = []
@@ -451,7 +462,13 @@ def _build_chat_details(
451462
"""Build OCI ChatDetails from an LlmRequest."""
452463
import oci.generative_ai_inference.models as oci_models
453464

454-
messages = [_content_to_oci_message(c) for c in llm_request.contents or []]
465+
messages: list[Any] = []
466+
for c in llm_request.contents or []:
467+
msg = _content_to_oci_message(c)
468+
if isinstance(msg, list):
469+
messages.extend(msg)
470+
else:
471+
messages.append(msg)
455472

456473
# Prepend SystemMessage when a system instruction is present
457474
if llm_request.config and llm_request.config.system_instruction:

tests/unittests/integrations/oci/test_oci_genai_llm.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,50 @@ def test_content_to_oci_message_function_response():
227227
assert msg.content[0].text
228228

229229

230+
def test_content_to_oci_message_multiple_function_responses():
231+
import oci.generative_ai_inference.models as oci_models
232+
233+
part_a = Part.from_function_response(
234+
name="get_weather", response={"temp": 22}
235+
)
236+
part_a.function_response.id = "call_A"
237+
part_b = Part.from_function_response(
238+
name="get_price", response={"price": 150}
239+
)
240+
part_b.function_response.id = "call_B"
241+
content = Content(role="user", parts=[part_a, part_b])
242+
msg = _content_to_oci_message(content)
243+
assert isinstance(msg, list)
244+
assert len(msg) == 2
245+
assert all(isinstance(m, oci_models.ToolMessage) for m in msg)
246+
assert msg[0].tool_call_id == "call_A"
247+
assert msg[1].tool_call_id == "call_B"
248+
assert msg[0].content[0].text
249+
assert msg[1].content[0].text
250+
251+
252+
def test_build_chat_details_flattens_multiple_tool_messages(oci_llm):
253+
import oci.generative_ai_inference.models as oci_models
254+
255+
part_a = Part.from_function_response(
256+
name="get_weather", response={"temp": 22}
257+
)
258+
part_a.function_response.id = "call_A"
259+
part_b = Part.from_function_response(
260+
name="get_price", response={"price": 150}
261+
)
262+
part_b.function_response.id = "call_B"
263+
request = LlmRequest(
264+
model="google.gemini-2.5-flash",
265+
contents=[Content(role="user", parts=[part_a, part_b])],
266+
)
267+
chat_details = oci_llm._build_chat_details(request)
268+
messages = chat_details.chat_request.messages
269+
assert len(messages) == 2
270+
assert all(m.role == oci_models.ToolMessage.ROLE_TOOL for m in messages)
271+
assert [m.tool_call_id for m in messages] == ["call_A", "call_B"]
272+
273+
230274
# ---------------------------------------------------------------------------
231275
# _oci_response_to_llm_response
232276
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)