@@ -269,7 +269,11 @@ def test_gemini_image_generation():
269
269
assert len (response .choices [0 ].message .images ) > 0
270
270
assert response .choices [0 ].message .images [0 ]["image_url" ] is not None
271
271
assert response .choices [0 ].message .images [0 ]["image_url" ]["url" ] is not None
272
- assert response .choices [0 ].message .images [0 ]["image_url" ]["url" ].startswith ("data:image/png;base64," )
272
+ assert (
273
+ response .choices [0 ]
274
+ .message .images [0 ]["image_url" ]["url" ]
275
+ .startswith ("data:image/png;base64," )
276
+ )
273
277
274
278
275
279
def test_gemini_thinking ():
@@ -661,7 +665,8 @@ def test_system_message_with_no_user_message():
661
665
assert response is not None
662
666
663
667
assert response .choices [0 ].message .content is not None
664
-
668
+
669
+
665
670
def get_current_weather (location , unit = "fahrenheit" ):
666
671
"""Get the current weather in a given location"""
667
672
if "tokyo" in location .lower ():
@@ -778,9 +783,9 @@ def test_gemini_reasoning_effort_minimal():
778
783
779
784
# Test with different Gemini models to verify model-specific mapping
780
785
test_cases = [
781
- ("gemini/gemini-2.5-flash" , 1 ), # Flash: minimum 1 token
782
- ("gemini/gemini-2.5-pro" , 128 ), # Pro: minimum 128 tokens
783
- ("gemini/gemini-2.5-flash-lite" , 512 ), # Flash-Lite: minimum 512 tokens
786
+ ("gemini/gemini-2.5-flash" , 1 ), # Flash: minimum 1 token
787
+ ("gemini/gemini-2.5-pro" , 128 ), # Pro: minimum 128 tokens
788
+ ("gemini/gemini-2.5-flash-lite" , 512 ), # Flash-Lite: minimum 512 tokens
784
789
]
785
790
786
791
for model , expected_min_budget in test_cases :
@@ -793,24 +798,32 @@ def test_gemini_reasoning_effort_minimal():
793
798
"reasoning_effort" : "minimal" ,
794
799
},
795
800
)
796
-
801
+
797
802
# Verify that the thinking config is set correctly
798
803
request_body = raw_request ["raw_request_body" ]
799
- assert "generationConfig" in request_body , f"Model { model } should have generationConfig"
800
-
804
+ assert (
805
+ "generationConfig" in request_body
806
+ ), f"Model { model } should have generationConfig"
807
+
801
808
generation_config = request_body ["generationConfig" ]
802
- assert "thinkingConfig" in generation_config , f"Model { model } should have thinkingConfig"
803
-
809
+ assert (
810
+ "thinkingConfig" in generation_config
811
+ ), f"Model { model } should have thinkingConfig"
812
+
804
813
thinking_config = generation_config ["thinkingConfig" ]
805
- assert "thinkingBudget" in thinking_config , f"Model { model } should have thinkingBudget"
806
-
814
+ assert (
815
+ "thinkingBudget" in thinking_config
816
+ ), f"Model { model } should have thinkingBudget"
817
+
807
818
actual_budget = thinking_config ["thinkingBudget" ]
808
- assert actual_budget == expected_min_budget , \
809
- f"Model { model } should map 'minimal' to { expected_min_budget } tokens, got { actual_budget } "
810
-
819
+ assert (
820
+ actual_budget == expected_min_budget
821
+ ), f"Model { model } should map 'minimal' to { expected_min_budget } tokens, got { actual_budget } "
822
+
811
823
# Verify that includeThoughts is True for minimal reasoning effort
812
- assert thinking_config .get ("includeThoughts" , True ), \
813
- f"Model { model } should have includeThoughts=True for minimal reasoning effort"
824
+ assert thinking_config .get (
825
+ "includeThoughts" , True
826
+ ), f"Model { model } should have includeThoughts=True for minimal reasoning effort"
814
827
815
828
# Test with unknown model (should use generic fallback)
816
829
try :
@@ -822,15 +835,41 @@ def test_gemini_reasoning_effort_minimal():
822
835
"reasoning_effort" : "minimal" ,
823
836
},
824
837
)
825
-
838
+
826
839
request_body = raw_request ["raw_request_body" ]
827
840
generation_config = request_body ["generationConfig" ]
828
841
thinking_config = generation_config ["thinkingConfig" ]
829
842
# Should use generic fallback (128 tokens)
830
- assert thinking_config ["thinkingBudget" ] == 128 , \
831
- "Unknown model should use generic fallback of 128 tokens"
843
+ assert (
844
+ thinking_config ["thinkingBudget" ] == 128
845
+ ), "Unknown model should use generic fallback of 128 tokens"
832
846
except Exception as e :
833
847
# If return_raw_request doesn't work for unknown models, that's okay
834
848
# The important part is that our known models work correctly
835
849
print (f"Note: Unknown model test skipped due to: { e } " )
836
850
pass
851
+
852
+
853
+ def test_gemini_additional_properties_bug ():
854
+ # Simple tool with additionalProperties (simulating the TypedDict issue)
855
+ tools = [
856
+ {
857
+ "type" : "function" ,
858
+ "function" : {
859
+ "name" : "test_tool" ,
860
+ "description" : "Test tool" ,
861
+ "parameters" : {
862
+ "type" : "object" ,
863
+ "properties" : {"param1" : {"type" : "string" }},
864
+ # This causes the error - any non-False value
865
+ "additionalProperties" : True , # Could also be None, {}, etc.
866
+ },
867
+ },
868
+ }
869
+ ]
870
+
871
+ messages = [{"role" : "user" , "content" : "Test message" }]
872
+
873
+ response = litellm .completion (
874
+ model = "gemini/gemini-2.5-flash" , messages = messages , tools = tools
875
+ )
0 commit comments