mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Fix invalid function schema error for tools with None parameters
Normalize tool function parameters before forwarding to OpenAI API.
When parameters is None or missing, default to a valid empty object
schema {"type": "object", "properties": {}}. This prevents the
BadRequestError reported in #22016.
Fixes https://github.com/galaxyproject/galaxy/issues/22016
This commit is contained in:
@@ -238,6 +238,9 @@ class FastAPIPlugins:
|
||||
if len(original_tools) <= MAX_TOOLS:
|
||||
for tool in original_tools:
|
||||
tool_dict = tool.model_dump()
|
||||
func = tool_dict.get("function", {})
|
||||
if func.get("parameters") is None:
|
||||
func["parameters"] = {"type": "object", "properties": {}}
|
||||
size = len(json.dumps(tool_dict, separators=(",", ":")).encode("utf-8"))
|
||||
if size > MAX_TOOL_BYTES:
|
||||
return self._create_error("Tool schema too large.")
|
||||
|
||||
@@ -216,6 +216,65 @@ class TestVisualizationPluginsApi(IntegrationTestCase):
|
||||
forwarded_tools = call_kwargs["tools"]
|
||||
assert forwarded_tools[0]["function"]["description"] == "Select a processing step"
|
||||
|
||||
@patch("galaxy.webapps.galaxy.api.plugins.AsyncOpenAI")
|
||||
def test_tool_with_none_parameters_normalized(self, mock_client):
|
||||
mock_response = MagicMock()
|
||||
mock_response.model_dump.return_value = {"id": "test", "choices": []}
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.chat.completions.create = AsyncMock(return_value=mock_response)
|
||||
mock_client.return_value = mock_instance
|
||||
payload = _create_chat_payload(
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "choose_process",
|
||||
"description": "Select a processing step",
|
||||
"parameters": None,
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
response = self._post_payload(payload)
|
||||
self._assert_status_code_is(response, 200)
|
||||
call_kwargs = mock_instance.chat.completions.create.call_args.kwargs
|
||||
forwarded_tools = call_kwargs["tools"]
|
||||
assert forwarded_tools[0]["function"]["parameters"] == {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
}
|
||||
|
||||
@patch("galaxy.webapps.galaxy.api.plugins.AsyncOpenAI")
|
||||
def test_tool_with_missing_parameters_normalized(self, mock_client):
|
||||
mock_response = MagicMock()
|
||||
mock_response.model_dump.return_value = {"id": "test", "choices": []}
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.chat.completions.create = AsyncMock(return_value=mock_response)
|
||||
mock_client.return_value = mock_instance
|
||||
payload = _create_chat_payload(
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "choose_process",
|
||||
"description": "Select a processing step",
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
response = self._post_payload(payload)
|
||||
self._assert_status_code_is(response, 200)
|
||||
call_kwargs = mock_instance.chat.completions.create.call_args.kwargs
|
||||
forwarded_tools = call_kwargs["tools"]
|
||||
assert forwarded_tools[0]["function"]["parameters"] == {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
}
|
||||
|
||||
@patch("galaxy.webapps.galaxy.api.plugins.AsyncOpenAI")
|
||||
def test_provider_error_body_forwarded(self, mock_client):
|
||||
class MockOpenAIError(APIError):
|
||||
|
||||
Reference in New Issue
Block a user