Remove maxItems=1 restriction when tool_choice is specified (#20208)

This commit is contained in:
Khoa Pham
2026-04-03 02:35:24 +00:00
committed by GitHub
parent 0539c62bc1
commit 2b5aed94f5
6 changed files with 83 additions and 17 deletions
@@ -102,7 +102,7 @@ class TestJsonSchemaConstraint(unittest.TestCase):
self.assertEqual(schema["type"], "array")
self.assertEqual(schema["minItems"], 1)
self.assertEqual(schema["maxItems"], 1)
self.assertNotIn("maxItems", schema)
# Should only have schema for the specific tool
item_schema = schema["items"]
@@ -121,13 +121,72 @@ class TestJsonSchemaConstraint(unittest.TestCase):
self.assertEqual(schema["type"], "array")
self.assertEqual(schema["minItems"], 1)
self.assertEqual(schema["maxItems"], 1)
self.assertNotIn("maxItems", schema)
# Should only have schema for the specific tool
item_schema = schema["items"]
self.assertEqual(item_schema["properties"]["name"]["enum"], ["search"])
self.assertIn("parameters", item_schema["properties"])
def test_specific_tool_choice_allows_multiple_calls(self):
"""Test that specific tool choice schema allows multiple calls.
Regression test for https://github.com/sgl-project/sglang/issues/17998:
maxItems: 1 caused the model to stall on whitespace when the prompt
implied multiple calls to the same function.
"""
tool_choice = ToolChoice(
type="function", function=ToolChoiceFuncName(name="get_weather")
)
schema = get_json_schema_constraint(self.tools, tool_choice)
single_call = [
{"name": "get_weather", "parameters": {"location": "NYC"}},
]
multi_call = [
{"name": "get_weather", "parameters": {"location": "NYC"}},
{"name": "get_weather", "parameters": {"location": "LA"}},
{"name": "get_weather", "parameters": {"location": "Chicago"}},
]
validator = jsonschema.Draft202012Validator(schema)
validator.validate(single_call)
validator.validate(multi_call)
def test_specific_tool_choice_no_parallel(self):
"""Test that parallel_tool_calls=False sets maxItems=1"""
tool_choice = ToolChoice(
type="function", function=ToolChoiceFuncName(name="get_weather")
)
schema = get_json_schema_constraint(
self.tools, tool_choice, parallel_tool_calls=False
)
self.assertIsNotNone(schema)
self.assertEqual(schema["maxItems"], 1)
single_call = [
{"name": "get_weather", "parameters": {"location": "NYC"}},
]
multi_call = [
{"name": "get_weather", "parameters": {"location": "NYC"}},
{"name": "get_weather", "parameters": {"location": "LA"}},
]
validator = jsonschema.Draft202012Validator(schema)
validator.validate(single_call)
with self.assertRaises(jsonschema.ValidationError):
validator.validate(multi_call)
def test_required_tool_choice_no_parallel(self):
"""Test that required + parallel_tool_calls=False sets maxItems=1"""
schema = get_json_schema_constraint(
self.tools, "required", parallel_tool_calls=False
)
self.assertIsNotNone(schema)
self.assertEqual(schema["maxItems"], 1)
def test_nonexistent_tool_choice(self):
"""Test schema generation for nonexistent tool"""
tool_choice = ToolChoice(