Compare commits
2 commits
main
...
fix/image-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61c23e5e7a | ||
|
|
d6c39467dd |
2 changed files with 20 additions and 8 deletions
|
|
@ -396,7 +396,10 @@ class ChatMessage(BaseModel):
|
||||||
if self.name is not None and self.role != "tool":
|
if self.name is not None and self.role != "tool":
|
||||||
raise ValueError('"name" is only valid on role="tool" messages.')
|
raise ValueError('"name" is only valid on role="tool" messages.')
|
||||||
|
|
||||||
# Per-role content requirements.
|
# Per-role content requirements. OpenAI-compatible clients may send
|
||||||
|
# ``content=""`` for image-only turns when the image travels in a
|
||||||
|
# companion field such as Studio's ``image_base64`` extension, so treat
|
||||||
|
# empty strings as present content for user/system messages.
|
||||||
if self.role == "tool":
|
if self.role == "tool":
|
||||||
if not self.tool_call_id:
|
if not self.tool_call_id:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
|
|
@ -411,9 +414,9 @@ class ChatMessage(BaseModel):
|
||||||
'role="assistant" messages require either "content" or "tool_calls".'
|
'role="assistant" messages require either "content" or "tool_calls".'
|
||||||
)
|
)
|
||||||
else: # "user" | "system"
|
else: # "user" | "system"
|
||||||
if not self.content:
|
if self.content is None or self.content == []:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f'role="{self.role}" messages require non-empty "content".'
|
f'role="{self.role}" messages require "content".'
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,13 +144,14 @@ class TestChatMessageToolRoles:
|
||||||
|
|
||||||
# ── Role-aware content requirements ────────────────────────────
|
# ── Role-aware content requirements ────────────────────────────
|
||||||
|
|
||||||
def test_user_empty_content_rejected(self):
|
@pytest.mark.parametrize("role", ["user", "system"])
|
||||||
with pytest.raises(ValidationError):
|
def test_empty_string_content_allowed(self, role):
|
||||||
ChatMessage(role = "user", content = "")
|
msg = ChatMessage(role = role, content = "")
|
||||||
|
assert msg.content == ""
|
||||||
|
|
||||||
def test_system_empty_content_rejected(self):
|
def test_user_missing_content_rejected(self):
|
||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
ChatMessage(role = "system", content = "")
|
ChatMessage(role = "user")
|
||||||
|
|
||||||
def test_user_empty_list_content_rejected(self):
|
def test_user_empty_list_content_rejected(self):
|
||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
|
|
@ -226,6 +227,14 @@ class TestChatCompletionRequestToolFields:
|
||||||
assert len(req.tools) == 1
|
assert len(req.tools) == 1
|
||||||
assert req.tools[0]["function"]["name"] == "get_weather"
|
assert req.tools[0]["function"]["name"] == "get_weather"
|
||||||
|
|
||||||
|
def test_image_base64_allows_empty_user_text(self):
|
||||||
|
req = ChatCompletionRequest(
|
||||||
|
messages = [{"role": "user", "content": ""}],
|
||||||
|
image_base64 = "aW1hZ2U=",
|
||||||
|
)
|
||||||
|
assert req.messages[0].content == ""
|
||||||
|
assert req.image_base64 == "aW1hZ2U="
|
||||||
|
|
||||||
def test_tool_choice_string_auto(self):
|
def test_tool_choice_string_auto(self):
|
||||||
assert self._make(tool_choice = "auto").tool_choice == "auto"
|
assert self._make(tool_choice = "auto").tool_choice == "auto"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue