Skip to content

Commit f5db310

Browse files
AkshayShah03copybara-github
authored andcommitted
fix: keep text sent alongside a function response in ApigeeLlm
Merge #7476 Fixes #7475 PiperOrigin-RevId: 996681319
1 parent 6a60d6a commit f5db310

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

‎src/google/adk/models/apigee_llm.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,10 +820,16 @@ def _content_to_messages(
820820
_function_response_media_content_parts(part.function_response)
821821
)
822822
if function_responses:
823-
if response_media_parts:
823+
# Any other parts in the same content (e.g. text the user sent with the
824+
# tool result) cannot go in a tool-role message either, so they follow
825+
# the tool results together with the media.
826+
follow_up_parts = response_media_parts + content_parts
827+
if len(follow_up_parts) == 1 and follow_up_parts[0]['type'] == 'text':
824828
function_responses.append(
825-
{'role': 'user', 'content': response_media_parts}
829+
{'role': 'user', 'content': follow_up_parts[0]['text']}
826830
)
831+
elif follow_up_parts:
832+
function_responses.append({'role': 'user', 'content': follow_up_parts})
827833
return function_responses
828834

829835
message: dict[str, Any] = {'role': role}

‎tests/unittests/models/test_apigee_llm.py‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,73 @@ def test_content_conversion_carries_function_response_media() -> None:
12091209
]
12101210

12111211

1212+
def test_content_conversion_keeps_text_alongside_function_response() -> None:
1213+
"""Text sent with a tool result follows the tool message as a user turn."""
1214+
part = types.Part.from_function_response(
1215+
name='lookup', response={'status': 'ok'}
1216+
)
1217+
assert part.function_response is not None
1218+
part.function_response.id = 'call_1'
1219+
content = types.Content(
1220+
role='user',
1221+
parts=[part, types.Part.from_text(text='Summarize it in French.')],
1222+
)
1223+
1224+
client = CompletionsHTTPClient(base_url='http://test')
1225+
messages = client._content_to_messages(content)
1226+
1227+
assert messages == [
1228+
{
1229+
'role': 'tool',
1230+
'tool_call_id': 'call_1',
1231+
'content': '{"status": "ok"}',
1232+
},
1233+
{'role': 'user', 'content': 'Summarize it in French.'},
1234+
]
1235+
1236+
1237+
def test_content_conversion_keeps_text_alongside_function_response_media() -> (
1238+
None
1239+
):
1240+
"""Tool media and accompanying text share one follow-up user message."""
1241+
part = types.Part.from_function_response(
1242+
name='draw_chart',
1243+
response={'title': 'Revenue'},
1244+
parts=[
1245+
types.FunctionResponsePart.from_bytes(
1246+
data=b'chart', mime_type='image/png'
1247+
)
1248+
],
1249+
)
1250+
assert part.function_response is not None
1251+
part.function_response.id = 'call_1'
1252+
content = types.Content(
1253+
role='user',
1254+
parts=[part, types.Part.from_text(text='Describe the chart.')],
1255+
)
1256+
1257+
client = CompletionsHTTPClient(base_url='http://test')
1258+
messages = client._content_to_messages(content)
1259+
1260+
assert messages == [
1261+
{
1262+
'role': 'tool',
1263+
'tool_call_id': 'call_1',
1264+
'content': '{"title": "Revenue"}',
1265+
},
1266+
{
1267+
'role': 'user',
1268+
'content': [
1269+
{
1270+
'type': 'image_url',
1271+
'image_url': {'url': 'data:image/png;base64,Y2hhcnQ='},
1272+
},
1273+
{'type': 'text', 'text': 'Describe the chart.'},
1274+
],
1275+
},
1276+
]
1277+
1278+
12121279
def test_content_conversion_without_function_response_media() -> None:
12131280
"""A response carrying no media still converts to a lone tool message."""
12141281
part = types.Part.from_function_response(

0 commit comments

Comments
 (0)