Remove maxItems=1 restriction when tool_choice is specified (#20208)
This commit is contained in:
@@ -585,6 +585,7 @@ class ChatCompletionRequest(BaseModel):
|
||||
tool_choice: Union[ToolChoice, Literal["auto", "required", "none"]] = Field(
|
||||
default="auto", examples=["none"]
|
||||
) # noqa
|
||||
parallel_tool_calls: bool = True
|
||||
return_hidden_states: bool = False
|
||||
return_routed_experts: bool = False
|
||||
return_cached_tokens_details: bool = False
|
||||
|
||||
@@ -352,14 +352,17 @@ class OpenAIServingChat(OpenAIServingBase):
|
||||
if self.tool_call_parser:
|
||||
parser = FunctionCallParser(request.tools, self.tool_call_parser)
|
||||
tool_call_constraint = parser.get_structure_constraint(
|
||||
request.tool_choice
|
||||
request.tool_choice,
|
||||
parallel_tool_calls=request.parallel_tool_calls,
|
||||
)
|
||||
# Handle JSON schema constraint directly for required or named tool choice
|
||||
if request.tool_choice == "required" or isinstance(
|
||||
request.tool_choice, ToolChoice
|
||||
):
|
||||
json_schema = get_json_schema_constraint(
|
||||
request.tools, request.tool_choice
|
||||
request.tools,
|
||||
request.tool_choice,
|
||||
parallel_tool_calls=request.parallel_tool_calls,
|
||||
)
|
||||
tool_call_constraint = ("json_schema", json_schema)
|
||||
|
||||
|
||||
@@ -184,7 +184,9 @@ class FunctionCallParser:
|
||||
)
|
||||
|
||||
def get_structure_constraint(
|
||||
self, tool_choice: Union[ToolChoice, Literal["auto", "required"]]
|
||||
self,
|
||||
tool_choice: Union[ToolChoice, Literal["auto", "required"]],
|
||||
parallel_tool_calls: bool = True,
|
||||
) -> Optional[ToolCallConstraint]:
|
||||
"""
|
||||
Returns the appropriate structure constraint for tool calls based on the tool_choice.
|
||||
@@ -210,5 +212,7 @@ class FunctionCallParser:
|
||||
tag = self.get_structure_tag()
|
||||
return ("structural_tag", tag)
|
||||
elif tool_choice == "required" or isinstance(tool_choice, ToolChoice):
|
||||
json_schema = get_json_schema_constraint(self.tools, tool_choice)
|
||||
json_schema = get_json_schema_constraint(
|
||||
self.tools, tool_choice, parallel_tool_calls=parallel_tool_calls
|
||||
)
|
||||
return ("json_schema", json_schema)
|
||||
|
||||
@@ -205,13 +205,16 @@ def infer_type_from_json_schema(schema: Dict[str, Any]) -> Optional[str]:
|
||||
|
||||
|
||||
def get_json_schema_constraint(
|
||||
tools: List[Tool], tool_choice: Union[ToolChoice, Literal["required"]]
|
||||
tools: List[Tool],
|
||||
tool_choice: Union[ToolChoice, Literal["required"]],
|
||||
parallel_tool_calls: bool = True,
|
||||
) -> Optional[dict]:
|
||||
"""
|
||||
Get the JSON schema constraint for the specified tool choice.
|
||||
|
||||
Args:
|
||||
tool_choice: The tool choice specification
|
||||
parallel_tool_calls: If False, constrain to exactly one tool call (maxItems=1)
|
||||
|
||||
Returns:
|
||||
JSON schema dict, or None if no valid tools found
|
||||
@@ -222,12 +225,14 @@ def get_json_schema_constraint(
|
||||
fn_name = tool_choice.function.name
|
||||
for tool in tools:
|
||||
if tool.function.name == fn_name:
|
||||
return {
|
||||
schema = {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 1,
|
||||
"items": _get_tool_schema(tool),
|
||||
}
|
||||
if not parallel_tool_calls:
|
||||
schema["maxItems"] = 1
|
||||
return schema
|
||||
return None
|
||||
elif tool_choice == "required":
|
||||
json_schema = {
|
||||
@@ -238,6 +243,8 @@ def get_json_schema_constraint(
|
||||
"anyOf": [_get_tool_schema(tool) for tool in tools],
|
||||
},
|
||||
}
|
||||
if not parallel_tool_calls:
|
||||
json_schema["maxItems"] = 1
|
||||
json_schema_defs = _get_tool_schema_defs(tools)
|
||||
if json_schema_defs:
|
||||
json_schema["$defs"] = json_schema_defs
|
||||
|
||||
Reference in New Issue
Block a user