Skip name-only namespace tools

This commit is contained in:
kigland 2026-06-09 09:03:35 +08:00
parent 3ebfa8fa41
commit f42804995b
4 changed files with 51 additions and 16 deletions

View file

@ -683,7 +683,11 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
elif tool.get("type") == "namespace" and (
not tool.get("description") or not tool.get("parameters")
):
raise ValueError("Namespace tools require description and parameters")
verbose_logger.warning(
"Skipping namespace tool without description or parameters: %s",
tool.get("name"),
)
continue
# Handle tools with 'type' field (OpenAI spec compliance) Ignore this field -> https://github.com/BerriAI/litellm/issues/14644#issuecomment-3342061838
elif "type" in tool:
tool = {k: tool[k] for k in tool if k != "type"}

View file

@ -1392,9 +1392,7 @@ class LiteLLMCompletionResponsesConfig:
not typed_tool.get("description")
or not typed_tool.get("parameters")
):
raise ValueError(
"Namespace tools require description and parameters"
)
continue
# Ensure parameters has "type": "object" as required by providers like Anthropic
parameters = dict(typed_tool.get("parameters", {}) or {})
if not parameters or "type" not in parameters:

View file

@ -2917,14 +2917,15 @@ def test_vertex_ai_function_declarations_with_other_tools_separate():
assert func_tool["function_declarations"][0]["name"] == "get_weather"
def test_vertex_ai_namespace_tool_without_schema_raises():
def test_vertex_ai_namespace_tool_without_schema_skips():
v = VertexGeminiConfig()
with pytest.raises(ValueError, match="Namespace tools require description"):
v._map_function(
value=[{"type": "namespace", "name": "mcp__node_repl"}],
optional_params={},
)
tools = v._map_function(
value=[{"type": "namespace", "name": "mcp__node_repl"}],
optional_params={},
)
assert tools == []
def test_vertex_ai_single_tool_type_still_works():

View file

@ -1228,17 +1228,49 @@ class TestToolTransformation:
)
assert result_tool["function"]["parameters"] == namespace_tool["parameters"]
def test_transform_namespace_tools_without_schema_raises(self):
"""Name-only namespace tools cannot be converted into usable functions."""
def test_transform_namespace_tools_without_schema_skips(self):
"""Name-only namespace tools are skipped instead of becoming hollow functions."""
namespace_tool = {
"type": "namespace",
"name": "mcp__node_repl",
}
with pytest.raises(ValueError, match="Namespace tools require description"):
LiteLLMCompletionResponsesConfig.transform_responses_api_tools_to_chat_completion_tools(
tools=[namespace_tool]
)
(
result_tools,
web_search_options,
) = LiteLLMCompletionResponsesConfig.transform_responses_api_tools_to_chat_completion_tools(
tools=[namespace_tool]
)
assert result_tools == []
assert web_search_options is None
def test_transform_namespace_tools_without_schema_keeps_other_tools(self):
"""Skipping name-only namespace tools should not abort the whole request."""
function_tool = {
"type": "function",
"name": "get_weather",
"description": "Get weather",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string"}},
},
}
namespace_tool = {
"type": "namespace",
"name": "mcp__node_repl",
}
(
result_tools,
web_search_options,
) = LiteLLMCompletionResponsesConfig.transform_responses_api_tools_to_chat_completion_tools(
tools=[namespace_tool, function_tool]
)
assert web_search_options is None
assert len(result_tools) == 1
assert result_tools[0]["function"]["name"] == "get_weather"
def test_transform_code_execution_tools(self):
"""Test that code_execution tools are passed through as-is"""