Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions litellm/llms/openai_like/dynamic_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,31 @@ def get_complete_url(
return api_base

def get_supported_openai_params(self, model: str) -> list:
"""Get supported OpenAI params from base class"""
return super().get_supported_openai_params(model=model)
"""Get supported OpenAI params, excluding tool-related params for models
that don't support function calling."""
from litellm._logging import verbose_logger
from litellm.utils import supports_function_calling

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline imports should be at module level

Per CLAUDE.md, imports should be placed at the top of the file rather than inside methods. verbose_logger is already imported at the top of the sibling json_loader.py file, confirming it's safe at module level. The supports_function_calling import from litellm.utils is used inline in a few other provider files (bedrock, sambanova) — likely to avoid circular imports — so that one may be justified. Consider moving at least verbose_logger to the top-level imports.

Suggested change
from litellm._logging import verbose_logger
from litellm.utils import supports_function_calling
from litellm.utils import supports_function_calling

Context Used: Context from dashboard - CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Moved verbose_logger to the top-level imports. Kept supports_function_calling as an inline import to avoid circular imports (same pattern used in other provider files like bedrock and sambanova). Fixed in 83f4d30.


supported_params = super().get_supported_openai_params(model=model)

try:
_supports_fc = supports_function_calling(
model=model, custom_llm_provider=provider.slug
)
except Exception:
_supports_fc = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant try/except — supports_function_calling already handles errors

The underlying _supports_factory function in litellm/utils.py already has a comprehensive try/except block that catches all exceptions and returns False when a model isn't found (lines 2526-2537 of utils.py). This outer try/except is therefore redundant. It's not harmful, but it obscures the fact that the utility function is designed to handle missing models gracefully.

If you want to keep defensive coding here for safety, that's fine — but be aware that the except Exception: _supports_fc = False path should never actually be reached under normal conditions.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right _supports_factory already catches all exceptions and returns False for missing models, so the outer try/except was unnecessary. Removed it. Fixed in 83f4d30.


if not _supports_fc:
tool_params = ["tools", "tool_choice", "function_call", "functions", "parallel_tool_calls"]
for param in tool_params:
if param in supported_params:
supported_params.remove(param)
verbose_logger.debug(
f"Model {model} on provider {provider.slug} does not support "
f"function calling — removed tool-related params from supported params."
)

return supported_params

def map_openai_params(
self,
Expand Down
41 changes: 41 additions & 0 deletions tests/test_litellm/llms/openai_like/test_json_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,47 @@ def test_supported_params(self):
assert isinstance(supported, list)
assert len(supported) > 0

def test_tool_params_excluded_when_function_calling_not_supported(self):
"""Test that tool-related params are excluded for models that don't support
function calling. Regression test for https://github.com/BerriAI/litellm/issues/21125"""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry

provider = JSONProviderRegistry.get("publicai")
config_class = create_config_class(provider)
config = config_class()

# Mock supports_function_calling to return False
with patch("litellm.utils.supports_function_calling", return_value=False):
supported = config.get_supported_openai_params("some-model-without-fc")

tool_params = ["tools", "tool_choice", "function_call", "functions", "parallel_tool_calls"]
for param in tool_params:
assert param not in supported, (
f"'{param}' should not be in supported params when function calling is not supported"
)

# Non-tool params should still be present
assert "temperature" in supported
assert "max_tokens" in supported
assert "stop" in supported

def test_tool_params_included_when_function_calling_supported(self):
"""Test that tool-related params are included for models that support function calling."""
from litellm.llms.openai_like.dynamic_config import create_config_class
from litellm.llms.openai_like.json_loader import JSONProviderRegistry

provider = JSONProviderRegistry.get("publicai")
config_class = create_config_class(provider)
config = config_class()

# Mock supports_function_calling to return True
with patch("litellm.utils.supports_function_calling", return_value=True):
supported = config.get_supported_openai_params("some-model-with-fc")

assert "tools" in supported
assert "tool_choice" in supported

def test_provider_resolution(self):
"""Test that provider resolution finds JSON providers"""
from litellm.litellm_core_utils.get_llm_provider_logic import (
Expand Down
Loading