Skip to content

Commit 5510595

Browse files
yyyu-googlecopybara-github
authored andcommitted
fix: remove redundant contents in Automatic Function Calling history
PiperOrigin-RevId: 723151823
1 parent db83c1b commit 5510595

2 files changed

Lines changed: 143 additions & 16 deletions

File tree

google/genai/models.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4702,15 +4702,18 @@ def generate_content(
47024702
)
47034703
if not func_response_parts:
47044704
break
4705-
contents = t.t_contents(self._api_client, contents)
4706-
contents.append(response.candidates[0].content)
4707-
contents.append(
4708-
types.Content(
4709-
role='user',
4710-
parts=func_response_parts,
4711-
)
4705+
func_call_content = response.candidates[0].content
4706+
func_response_content = types.Content(
4707+
role='user',
4708+
parts=func_response_parts,
47124709
)
4713-
automatic_function_calling_history.extend(contents)
4710+
contents = t.t_contents(self._api_client, contents)
4711+
if not automatic_function_calling_history:
4712+
automatic_function_calling_history.extend(contents)
4713+
contents.append(func_call_content)
4714+
contents.append(func_response_content)
4715+
automatic_function_calling_history.append(func_call_content)
4716+
automatic_function_calling_history.append(func_response_content)
47144717
if _extra_utils.should_append_afc_history(config):
47154718
response.automatic_function_calling_history = (
47164719
automatic_function_calling_history
@@ -5700,15 +5703,18 @@ async def generate_content(
57005703
)
57015704
if not func_response_parts:
57025705
break
5703-
contents = t.t_contents(self._api_client, contents)
5704-
contents.append(response.candidates[0].content)
5705-
contents.append(
5706-
types.Content(
5707-
role='user',
5708-
parts=func_response_parts,
5709-
)
5706+
func_call_content = response.candidates[0].content
5707+
func_response_content = types.Content(
5708+
role='user',
5709+
parts=func_response_parts,
57105710
)
5711-
automatic_function_calling_history.extend(contents)
5711+
contents = t.t_contents(self._api_client, contents)
5712+
if not automatic_function_calling_history:
5713+
automatic_function_calling_history.extend(contents)
5714+
contents.append(func_call_content)
5715+
contents.append(func_response_content)
5716+
automatic_function_calling_history.append(func_call_content)
5717+
automatic_function_calling_history.append(func_response_content)
57125718

57135719
if _extra_utils.should_append_afc_history(config):
57145720
response.automatic_function_calling_history = (

google/genai/tests/chats/test_send_message.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,33 @@ def square_integer(given_integer: int) -> int:
5050
return given_integer*given_integer
5151

5252

53+
def power_disco_ball(power: bool) -> bool:
54+
"""Powers the spinning disco ball."""
55+
print(f"Disco ball is {'spinning!' if power else 'stopped.'}")
56+
return True
57+
58+
def start_music(energetic: bool, loud: bool, bpm: int) -> str:
59+
"""Play some music matching the specified parameters.
60+
61+
Args:
62+
energetic: Whether the music is energetic or not.
63+
loud: Whether the music is loud or not.
64+
bpm: The beats per minute of the music.
65+
66+
Returns: The name of the song being played.
67+
"""
68+
print(f"Starting music! {energetic=} {loud=}, {bpm=}")
69+
return "Never gonna give you up."
70+
71+
def dim_lights(brightness: float) -> bool:
72+
"""Dim the lights.
73+
74+
Args:
75+
brightness: The brightness of the lights, 0.0 is off, 1.0 is full.
76+
"""
77+
print(f"Lights are now set to {brightness:.0%}")
78+
return True
79+
5380
def test_text(client):
5481
chat = client.chats.create(model='gemini-1.5-flash')
5582
chat.send_message(
@@ -165,6 +192,100 @@ def test_with_afc_history(client):
165192
assert '51' in chat_history[3].parts[0].text
166193

167194

195+
def test_with_afc_multiple_remote_calls(client):
196+
197+
house_fns = [power_disco_ball, start_music, dim_lights]
198+
config = {
199+
'tools': house_fns,
200+
# Force the model to act (call 'any' function), instead of chatting.
201+
'tool_config': {
202+
'function_calling_config': {
203+
'mode': 'ANY',
204+
}
205+
},
206+
'automatic_function_calling': {
207+
'maximum_remote_calls': 3,
208+
}
209+
}
210+
chat = client.chats.create(model='gemini-1.5-flash', config=config)
211+
chat.send_message('Turn this place into a party!')
212+
curated_history = chat._curated_history
213+
214+
assert len(curated_history) == 8
215+
assert curated_history[0].role == 'user'
216+
assert curated_history[0].parts[0].text == 'Turn this place into a party!'
217+
assert curated_history[1].role == 'model'
218+
assert len(curated_history[1].parts) == 3
219+
for part in curated_history[1].parts:
220+
assert part.function_call
221+
assert curated_history[2].role == 'user'
222+
assert len(curated_history[2].parts) == 3
223+
for part in curated_history[2].parts:
224+
assert part.function_response
225+
assert curated_history[3].role == 'model'
226+
assert len(curated_history[3].parts) == 1
227+
assert curated_history[3].parts[0].function_call
228+
assert curated_history[4].role == 'user'
229+
assert len(curated_history[4].parts) == 1
230+
assert curated_history[4].parts[0].function_response
231+
assert curated_history[5].role == 'model'
232+
assert len(curated_history[5].parts) == 1
233+
assert curated_history[5].parts[0].function_call
234+
assert curated_history[6].role == 'user'
235+
assert len(curated_history[6].parts) == 1
236+
assert curated_history[6].parts[0].function_response
237+
assert curated_history[7].role == 'model'
238+
assert len(curated_history[7].parts) == 1
239+
assert curated_history[7].parts[0].function_call
240+
241+
242+
def test_with_afc_multiple_remote_calls_async(client):
243+
244+
house_fns = [power_disco_ball, start_music, dim_lights]
245+
config = {
246+
'tools': house_fns,
247+
# Force the model to act (call 'any' function), instead of chatting.
248+
'tool_config': {
249+
'function_calling_config': {
250+
'mode': 'ANY',
251+
}
252+
},
253+
'automatic_function_calling': {
254+
'maximum_remote_calls': 3,
255+
}
256+
}
257+
chat = client.chats.create(model='gemini-1.5-flash', config=config)
258+
chat.send_message('Turn this place into a party!')
259+
curated_history = chat._curated_history
260+
261+
assert len(curated_history) == 8
262+
assert curated_history[0].role == 'user'
263+
assert curated_history[0].parts[0].text == 'Turn this place into a party!'
264+
assert curated_history[1].role == 'model'
265+
assert len(curated_history[1].parts) == 3
266+
for part in curated_history[1].parts:
267+
assert part.function_call
268+
assert curated_history[2].role == 'user'
269+
assert len(curated_history[2].parts) == 3
270+
for part in curated_history[2].parts:
271+
assert part.function_response
272+
assert curated_history[3].role == 'model'
273+
assert len(curated_history[3].parts) == 1
274+
assert curated_history[3].parts[0].function_call
275+
assert curated_history[4].role == 'user'
276+
assert len(curated_history[4].parts) == 1
277+
assert curated_history[4].parts[0].function_response
278+
assert curated_history[5].role == 'model'
279+
assert len(curated_history[5].parts) == 1
280+
assert curated_history[5].parts[0].function_call
281+
assert curated_history[6].role == 'user'
282+
assert len(curated_history[6].parts) == 1
283+
assert curated_history[6].parts[0].function_response
284+
assert curated_history[7].role == 'model'
285+
assert len(curated_history[7].parts) == 1
286+
assert curated_history[7].parts[0].function_call
287+
288+
168289
def test_with_afc_disabled(client):
169290
chat = client.chats.create(
170291
model='gemini-1.5-flash',

0 commit comments

Comments
 (0)