[Bugfix][Frontend] Reject Cohere REQUIRED tool choice without tools (#61825)
Signed-off-by: Kevin <jia__kuan@163.com>
This commit is contained in:
@@ -598,6 +598,21 @@ class TestCohereErrorEnvelope:
|
||||
assert "message" in body
|
||||
assert isinstance(body["message"], str) and body["message"]
|
||||
|
||||
@pytest.mark.parametrize("path", ["/cohere/v2/chat", "/cohere/v2/chat/render"])
|
||||
def test_required_tool_choice_without_tools_returns_400(self, path):
|
||||
"""Reject an impossible tool choice before reaching either handler."""
|
||||
app = _build_app_with_vllm_handlers(handler=None)
|
||||
with TestClient(app) as client:
|
||||
response = client.post(
|
||||
path,
|
||||
json={**_minimal_request_body(), "tool_choice": "REQUIRED"},
|
||||
)
|
||||
assert response.status_code == HTTPStatus.BAD_REQUEST
|
||||
body = response.json()
|
||||
assert "error" not in body
|
||||
assert "REQUIRED" in body["message"]
|
||||
assert "tools" in body["message"]
|
||||
|
||||
def test_http_error_body_is_cohere_shaped(self):
|
||||
# A raised ``HTTPException`` from anywhere in the request cycle
|
||||
# is routed through ``http_exception_handler`` (producing the
|
||||
|
||||
@@ -95,6 +95,27 @@ class TestCohereChatV2Request:
|
||||
tool_choice="ANY", # not REQUIRED/NONE
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("tool_fields", [{}, {"tools": None}, {"tools": []}])
|
||||
def test_required_tool_choice_requires_tools(self, tool_fields):
|
||||
with pytest.raises(VLLMValidationError, match="REQUIRED.*tools") as exc_info:
|
||||
CohereChatV2Request(
|
||||
model="m",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
tool_choice="REQUIRED",
|
||||
**tool_fields,
|
||||
)
|
||||
assert exc_info.value.parameter == "tool_choice"
|
||||
|
||||
@pytest.mark.parametrize("tool_choice", [None, "NONE"])
|
||||
def test_nonrequired_tool_choice_allows_empty_tools(self, tool_choice):
|
||||
request = CohereChatV2Request(
|
||||
model="m",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
tool_choice=tool_choice,
|
||||
tools=[],
|
||||
)
|
||||
assert request.tool_choice == tool_choice
|
||||
|
||||
def test_stop_sequences_bounded_by_env_limit(self):
|
||||
messages = [{"role": "user", "content": "hi"}]
|
||||
limit = envs.VLLM_MAX_STOP_STRINGS
|
||||
|
||||
@@ -44,7 +44,7 @@ from cohere.types import (
|
||||
ToolV2,
|
||||
UserChatMessageV2,
|
||||
)
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
|
||||
import vllm.envs as envs
|
||||
from vllm.exceptions import VLLMValidationError
|
||||
@@ -211,6 +211,16 @@ class CohereChatV2Request(BaseModel):
|
||||
)
|
||||
return v
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _validate_tool_choice(self) -> CohereChatV2Request:
|
||||
if self.tool_choice == "REQUIRED" and not self.tools:
|
||||
raise VLLMValidationError(
|
||||
'tool_choice="REQUIRED" requires at least one tool in tools.',
|
||||
parameter="tool_choice",
|
||||
value=self.tool_choice,
|
||||
)
|
||||
return self
|
||||
|
||||
@field_validator("messages", mode="before")
|
||||
@classmethod
|
||||
def _normalize_message_roles(cls, v: Any) -> Any:
|
||||
|
||||
Reference in New Issue
Block a user