@@ -441,6 +441,91 @@ def test_history_with_invalid_turns():
441441 assert chat .get_history (curated = True ) == curated_history
442442
443443
444+ def _multi_content_user_turn ():
445+ return [
446+ types .Content (
447+ role = 'user' ,
448+ parts = [types .Part .from_text (text = 'what is the weather' )],
449+ ),
450+ types .Content (
451+ role = 'user' ,
452+ parts = [
453+ types .Part .from_function_response (
454+ name = 'get_weather' , response = {'c' : 21 }
455+ )
456+ ],
457+ ),
458+ ]
459+
460+
461+ def test_history_with_multi_content_user_turn_and_invalid_model_output ():
462+ """An invalid model output drops every user content of its turn."""
463+ history = _multi_content_user_turn () + [
464+ types .Content (role = 'model' , parts = []),
465+ ]
466+
467+ models_module = models .Models (mock_api_client )
468+ chats_module = chats .Chats (modules = models_module )
469+ chat = chats_module .create (model = 'gemini-2.5-flash' , history = history )
470+
471+ assert chat .get_history () == history
472+ assert chat .get_history (curated = True ) == []
473+
474+
475+ def test_history_with_valid_turn_then_invalid_multi_content_user_turn ():
476+ """Dropping the rejected user turn stops at the previous valid output."""
477+ valid_turn = [
478+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'u1' )]),
479+ types .Content (role = 'model' , parts = [types .Part .from_text (text = 'm1' )]),
480+ ]
481+ history = (
482+ valid_turn
483+ + _multi_content_user_turn ()
484+ + [types .Content (role = 'model' , parts = [])]
485+ )
486+
487+ models_module = models .Models (mock_api_client )
488+ chats_module = chats .Chats (modules = models_module )
489+ chat = chats_module .create (model = 'gemini-2.5-flash' , history = history )
490+
491+ assert chat .get_history () == history
492+ assert chat .get_history (curated = True ) == valid_turn
493+
494+
495+ def test_history_with_invalid_multi_content_user_turn_then_valid_turn ():
496+ """No content of a rejected user turn attaches to the next valid turn."""
497+ valid_turn = [
498+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'u2' )]),
499+ types .Content (role = 'model' , parts = [types .Part .from_text (text = 'm2' )]),
500+ ]
501+ history = (
502+ _multi_content_user_turn ()
503+ + [types .Content (role = 'model' , parts = [])]
504+ + valid_turn
505+ )
506+
507+ models_module = models .Models (mock_api_client )
508+ chats_module = chats .Chats (modules = models_module )
509+ chat = chats_module .create (model = 'gemini-2.5-flash' , history = history )
510+
511+ assert chat .get_history () == history
512+ assert chat .get_history (curated = True ) == valid_turn
513+
514+
515+ def test_async_chat_create_with_invalid_multi_content_user_turn ():
516+ """The async chat drops the whole rejected user turn too."""
517+ history = _multi_content_user_turn () + [
518+ types .Content (role = 'model' , parts = []),
519+ ]
520+
521+ models_module = models .AsyncModels (mock_api_client )
522+ chats_module = chats .AsyncChats (modules = models_module )
523+ chat = chats_module .create (model = 'gemini-2.5-flash' , history = history )
524+
525+ assert chat .get_history () == history
526+ assert chat .get_history (curated = True ) == []
527+
528+
444529def test_chat_with_empty_text_part (mock_generate_content_with_empty_text_part ):
445530 models_module = models .Models (mock_api_client )
446531 chats_module = chats .Chats (modules = models_module )
0 commit comments