mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-07 07:58:09 +00:00
This commit is contained in:
parent
b1d8ee7191
commit
a12100b33b
3 changed files with 41 additions and 12 deletions
|
|
@ -584,6 +584,12 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
if block.get("type") == "text" and isinstance(text := block.get("text"), str) and text
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_output_format_strict(strict: bool | None) -> bool:
|
||||
if strict is None:
|
||||
return True
|
||||
return strict
|
||||
|
||||
def translate_request(
|
||||
self,
|
||||
anthropic_request: AnthropicMessagesRequest,
|
||||
|
|
@ -693,7 +699,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
"type": "json_schema",
|
||||
"name": "structured_output",
|
||||
"schema": schema,
|
||||
"strict": output_format.get("strict", False),
|
||||
"strict": self._resolve_output_format_strict(output_format.get("strict")),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ Tests for LiteLLMAnthropicToResponsesAPIAdapter
|
|||
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, Final, List
|
||||
from collections.abc import Mapping
|
||||
from typing import Any, Dict, Final, List, Literal
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
|
@ -24,6 +25,9 @@ from litellm.litellm_core_utils.prompt_templates.common_utils import (
|
|||
from litellm.litellm_core_utils.prompt_templates.reasoning_utils import (
|
||||
encrypted_reasoning_signature,
|
||||
)
|
||||
from litellm.llms.anthropic.messages.adapters.transformation import (
|
||||
LiteLLMAnthropicMessagesAdapter,
|
||||
)
|
||||
from litellm.llms.anthropic.messages.responses_adapters.transformation import (
|
||||
LiteLLMAnthropicToResponsesAPIAdapter,
|
||||
)
|
||||
|
|
@ -141,21 +145,23 @@ class TestOutputConfigStructuredOutput:
|
|||
}
|
||||
|
||||
def test_output_config_format_json_schema_converted(self):
|
||||
"""output_config.format.json_schema is converted to OpenAI text.format, defaulting strict to False."""
|
||||
"""output_config.format.json_schema becomes strict OpenAI text.format."""
|
||||
req = _make_request(output_config={"format": {"type": "json_schema", "schema": self._SCHEMA}})
|
||||
kwargs = _ADAPTER.translate_request(req)
|
||||
assert "text" in kwargs
|
||||
fmt = kwargs["text"]["format"]
|
||||
assert fmt["type"] == "json_schema"
|
||||
assert fmt["schema"] == self._SCHEMA
|
||||
assert fmt["strict"] is False
|
||||
assert fmt["strict"] is True
|
||||
assert fmt["name"] == "structured_output"
|
||||
|
||||
def test_output_config_format_explicit_strict_true_is_preserved(self):
|
||||
"""Nested output_config.format with explicit strict=True is preserved."""
|
||||
req = _make_request(output_config={"format": {"type": "json_schema", "schema": self._SCHEMA, "strict": True}})
|
||||
kwargs = _ADAPTER.translate_request(req)
|
||||
assert kwargs["text"]["format"]["strict"] is True
|
||||
@pytest.mark.parametrize("strict", (True, False))
|
||||
def test_output_config_format_explicit_strict_is_preserved(self, strict: bool) -> None:
|
||||
req: Final = _make_request(
|
||||
output_config={"format": {"type": "json_schema", "schema": self._SCHEMA, "strict": strict}}
|
||||
)
|
||||
kwargs: Final = _ADAPTER.translate_request(req)
|
||||
assert kwargs["text"]["format"]["strict"] is strict
|
||||
|
||||
def test_output_config_without_format_does_not_set_text(self):
|
||||
"""output_config with only non-format keys doesn't produce text.format."""
|
||||
|
|
@ -164,12 +170,12 @@ class TestOutputConfigStructuredOutput:
|
|||
assert "text" not in kwargs
|
||||
|
||||
def test_output_format_still_works(self):
|
||||
"""The original output_format field still takes precedence when present, defaulting strict to False."""
|
||||
"""The original output_format field still defaults to strict mode."""
|
||||
req = _make_request(output_format={"type": "json_schema", "schema": self._SCHEMA})
|
||||
kwargs = _ADAPTER.translate_request(req)
|
||||
assert "text" in kwargs
|
||||
assert kwargs["text"]["format"]["type"] == "json_schema"
|
||||
assert kwargs["text"]["format"]["strict"] is False
|
||||
assert kwargs["text"]["format"]["strict"] is True
|
||||
|
||||
def test_output_format_explicit_strict_false_is_preserved(self):
|
||||
"""output_format with an explicit strict=False is preserved as False."""
|
||||
|
|
@ -183,6 +189,23 @@ class TestOutputConfigStructuredOutput:
|
|||
kwargs = _ADAPTER.translate_request(req)
|
||||
assert kwargs["text"]["format"]["strict"] is True
|
||||
|
||||
@pytest.mark.parametrize("format_field", ("output_format", "output_config"))
|
||||
@pytest.mark.parametrize("strict_options", ({}, {"strict": None}))
|
||||
def test_default_strict_matches_messages_to_chat_adapter(
|
||||
self,
|
||||
format_field: Literal["output_format", "output_config"],
|
||||
strict_options: Mapping[str, None],
|
||||
) -> None:
|
||||
output_format: Final = {"type": "json_schema", "schema": self._SCHEMA, **strict_options}
|
||||
request: Final = _make_request(
|
||||
**{format_field: output_format if format_field == "output_format" else {"format": output_format}}
|
||||
)
|
||||
chat, _ = LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(request)
|
||||
responses: Final = _ADAPTER.translate_request(request)
|
||||
|
||||
assert chat["response_format"]["json_schema"]["strict"] is True
|
||||
assert responses["text"]["format"]["strict"] is chat["response_format"]["json_schema"]["strict"]
|
||||
|
||||
def test_output_format_takes_precedence_over_output_config(self):
|
||||
"""output_format takes precedence over output_config.format, for both schema and strict."""
|
||||
other_schema = {"type": "object", "properties": {"id": {"type": "integer"}}}
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ async def test_anthropic_format_counts_the_structured_output_schema(monkeypatch:
|
|||
assert sent == {
|
||||
"model": "gpt-4o",
|
||||
"input": [{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "Answer in JSON."}]}],
|
||||
"text": {"format": {"type": "json_schema", "name": "structured_output", "schema": schema, "strict": False}},
|
||||
"text": {"format": {"type": "json_schema", "name": "structured_output", "schema": schema, "strict": True}},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue