[Fix] Require JSON booleans for response_format json_schema.strict (#34777)

Co-authored-by: James Liu <jamesl@modal.com>
This commit is contained in:
gilfordting
2026-08-14 16:46:27 -07:00
committed by GitHub
co-authored by James Liu
parent a1844709f1
commit 6f005e4da1
2 changed files with 41 additions and 1 deletions
@@ -53,6 +53,7 @@ from pydantic import (
BaseModel,
ConfigDict,
Field,
StrictBool,
field_serializer,
field_validator,
model_serializer,
@@ -219,7 +220,10 @@ class JsonSchemaResponseFormat(BaseModel):
description: Optional[str] = None
# use alias to workaround pydantic conflict
schema_: Optional[Dict[str, object]] = Field(alias="schema", default=None)
strict: Optional[bool] = None
# The OpenAI wire contract accepts JSON booleans only; StrictBool rejects
# the values lax pydantic would coerce ("yes", "on", 0, 1, ...), matching
# OpenAI's 422 behavior. Omitted (None) keeps its meaning.
strict: Optional[StrictBool] = None
class ResponseFormat(BaseModel):
@@ -114,6 +114,42 @@ class TestCompletionRequest(unittest.TestCase):
class TestChatCompletionRequest(unittest.TestCase):
"""Test ChatCompletionRequest protocol model"""
def test_json_schema_strict_requires_json_boolean(self):
base_request = {
"model": "test-model",
"messages": [{"role": "user", "content": "Hello"}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "answer",
"schema": {"type": "object"},
},
},
}
for strict in (True, False, None):
with self.subTest(strict=strict):
response_format = dict(base_request["response_format"])
response_format["json_schema"] = {
**response_format["json_schema"],
"strict": strict,
}
request = ChatCompletionRequest.model_validate(
{**base_request, "response_format": response_format}
)
self.assertIs(request.response_format.json_schema.strict, strict)
for strict in ("yes", "false", 0, 1):
with self.subTest(strict=strict), self.assertRaises(ValidationError):
response_format = dict(base_request["response_format"])
response_format["json_schema"] = {
**response_format["json_schema"],
"strict": strict,
}
ChatCompletionRequest.model_validate(
{**base_request, "response_format": response_format}
)
def test_basic_chat_completion_request(self):
"""Test basic chat completion request"""
messages = [{"role": "user", "content": "Hello"}]