@@ -233,10 +233,12 @@ def test_validate_call_params_not_supported():
233233 class DummyResponse (BaseModel ):
234234 a : int
235235
236- # Patch supports_response_schema to simulate an unsupported model.
236+ # Use an unknown provider (not in RESPONSE_FORMAT_SUPPORTED_PROVIDERS) so the
237+ # LiteLLM introspection path is exercised and supports_response_schema can
238+ # report False, which should raise ValueError.
237239 with patch ("crewai.llm.supports_response_schema" , return_value = False ):
238240 llm = LLM (
239- model = "gemini/gemini-1.5-pro " ,
241+ model = "unknown-llm-provider/some-model " ,
240242 response_format = DummyResponse ,
241243 is_litellm = True ,
242244 )
@@ -1211,19 +1213,24 @@ async def _ret(*args, **kwargs):
12111213
12121214
12131215def test_validate_call_params_handles_introspection_error ():
1214- """Verify that _validate_call_params gracefully handles LiteLLM introspection errors without crashing."""
1216+ """Verify _validate_call_params gracefully handles LiteLLM introspection errors without crashing.
1217+
1218+ When the provider is not in the static list, introspection is attempted.
1219+ An exception during introspection must be caught and treated as supported
1220+ so the request can proceed with custom/proxy models.
1221+ """
12151222 llm = LLM (model = "custom/unsupported-model" , is_litellm = True , response_format = {"type" : "json_object" })
12161223
12171224 with patch ("crewai.llm.supports_response_schema" , side_effect = Exception ("Introspection error" )):
1218- # Should not raise exception — permissive fallback applies
1225+ # Should not raise exception -- permissive fallback applies
12191226 llm ._validate_call_params ()
12201227
12211228
12221229def test_validate_call_params_raises_for_confirmed_unsupported_model ():
12231230 """Verify _validate_call_params still raises ValueError when introspection confirms no support.
12241231
1225- This ensures the validation path is not silently skipped — only introspection
1226- * errors* are swallowed; a clear `` False`` return still produces a ValueError.
1232+ This ensures the validation path is not silently skipped -- only introspection
1233+ errors are swallowed; a clear False return still produces a ValueError.
12271234 """
12281235 llm = LLM (model = "my-provider/my-model" , is_litellm = True , response_format = {"type" : "json_object" })
12291236
@@ -1233,17 +1240,44 @@ def test_validate_call_params_raises_for_confirmed_unsupported_model():
12331240
12341241
12351242def test_validate_call_params_skips_check_when_no_response_format ():
1236- """Verify _validate_call_params is a no-op when response_format is not set.
1243+ """Verify _validate_call_params is a no-op for params that require no validation.
1244+
1245+ When no response_format is set, the method must return without ever
1246+ calling the LiteLLM introspection function.
1247+ """
1248+ llm = LLM (model = "gpt-4o" , is_litellm = True , temperature = 0.5 )
1249+
1250+ with patch ("crewai.llm.supports_response_schema" , side_effect = Exception ("Should not be called" )):
1251+ # No exception -- response_format is None so introspection is never invoked
1252+ llm ._validate_call_params ()
1253+
12371254
1238- This covers scenarios where only ``reasoning_effort`` or other parameters
1239- are configured: the method must return immediately so those parameters are
1240- forwarded to the provider without interference.
1255+ def test_validate_call_params_reasoning_effort_supported_provider ():
1256+ """Verify _validate_call_params passes without error for reasoning_effort on a supported provider.
1257+
1258+ openai is in REASONING_EFFORT_SUPPORTED_PROVIDERS, so no warning or
1259+ error should be raised and introspection must not be triggered.
12411260 """
1242- llm = LLM (model = "gpt-4o " , is_litellm = True , reasoning_effort = "medium" )
1261+ llm = LLM (model = "openai/o3-mini " , is_litellm = True , reasoning_effort = "medium" )
12431262
1244- # If supports_response_schema were called, patching it to raise would surface the bug
12451263 with patch ("crewai.llm.supports_response_schema" , side_effect = Exception ("Should not be called" )):
1246- # No exception — response_format is None so introspection is never invoked
1264+ # No response_format set -- introspection is never invoked
1265+ llm ._validate_call_params ()
1266+
1267+
1268+ def test_validate_call_params_reasoning_effort_unknown_provider_logs_debug (caplog ):
1269+ """Verify _validate_call_params logs a debug message for unknown providers with reasoning_effort.
1270+
1271+ Unknown providers are not rejected outright: parameters are forwarded and
1272+ may be silently ignored by the underlying provider. The debug log signals
1273+ this to developers without breaking the call.
1274+ """
1275+ import logging
1276+
1277+ llm = LLM (model = "unknown-provider/some-model" , is_litellm = True , reasoning_effort = "high" )
1278+
1279+ with caplog .at_level (logging .DEBUG , logger = "crewai.llm" ):
12471280 llm ._validate_call_params ()
12481281
1282+ assert any ("reasoning_effort" in record .message for record in caplog .records )
12491283
0 commit comments