mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(types): unquote resolvable forward refs so Message builds on python 3.10/3.11
Quoted refs inside TypedDicts embedded in pydantic models are resolved against the embedding model's module namespace, so ModelResponse() raised PydanticUserError: `Message` is not fully defined on python < 3.12. Fixes #36384 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
f6b9518ddb
commit
9fa5a872d3
2 changed files with 45 additions and 3 deletions
|
|
@ -534,7 +534,7 @@ class ChatCompletionReasoningItem(TypedDict, total=False):
|
|||
type: Required[Literal["reasoning"]]
|
||||
id: str
|
||||
encrypted_content: str | None
|
||||
summary: list["ChatCompletionReasoningSummaryTextBlock"]
|
||||
summary: list[ChatCompletionReasoningSummaryTextBlock]
|
||||
|
||||
|
||||
class WebSearchOptionsUserLocationApproximate(TypedDict, total=False):
|
||||
|
|
@ -1135,7 +1135,7 @@ class ResponsesAPIOptionalRequestParams(TypedDict, total=False):
|
|||
background: bool | None
|
||||
stream: bool | None
|
||||
temperature: float | None
|
||||
text: Optional["ResponseText"]
|
||||
text: ResponseText | None
|
||||
tool_choice: ToolChoice | None
|
||||
tools: list[ALL_RESPONSES_API_TOOL_PARAMS] | None
|
||||
top_p: float | None
|
||||
|
|
@ -1243,7 +1243,7 @@ class ResponsesAPIResponse(BaseLiteLLMOpenAIResponseObject):
|
|||
previous_response_id: str | None = None
|
||||
reasoning: dict[str, Any] | None = None
|
||||
status: str | None = None
|
||||
text: Union["ResponseText", dict[str, Any]] | None = None
|
||||
text: ResponseText | dict[str, Any] | None = None
|
||||
truncation: Literal["auto", "disabled"] | None = None
|
||||
usage: ResponseAPIUsage | None = None
|
||||
user: str | None = None
|
||||
|
|
|
|||
|
|
@ -453,3 +453,45 @@ def test_openai_file_object_accepts_pending_status():
|
|||
status="pending",
|
||||
)
|
||||
assert file_obj.status == "pending"
|
||||
|
||||
|
||||
def test_typed_dicts_have_no_resolvable_quoted_forward_refs():
|
||||
"""A quoted ref inside a TypedDict is resolved against the namespace of the
|
||||
pydantic model embedding it, not this module, so it breaks model building on
|
||||
python < 3.12 (issue #36384)."""
|
||||
from typing import ForwardRef, get_args
|
||||
|
||||
from typing_extensions import is_typeddict
|
||||
|
||||
import litellm.types.llms.openai as openai_types
|
||||
|
||||
def string_refs(annotation: object) -> tuple[str, ...]:
|
||||
return tuple(
|
||||
ref
|
||||
for arg in get_args(annotation)
|
||||
for ref in (
|
||||
(arg,)
|
||||
if isinstance(arg, str)
|
||||
else (arg.__forward_arg__,)
|
||||
if isinstance(arg, ForwardRef)
|
||||
else string_refs(arg)
|
||||
)
|
||||
)
|
||||
|
||||
stale = tuple(
|
||||
f"{cls.__name__}.{field} -> {ref!r}"
|
||||
for cls in vars(openai_types).values()
|
||||
if is_typeddict(cls) and cls.__module__ == openai_types.__name__
|
||||
for field, annotation in cls.__annotations__.items()
|
||||
for ref in string_refs(annotation)
|
||||
if ref != cls.__name__ and getattr(openai_types, ref, None) is not None
|
||||
)
|
||||
assert not stale, f"unquote these forward refs: {stale}"
|
||||
|
||||
|
||||
def test_model_response_constructs_with_reasoning_items_annotation():
|
||||
from litellm.types.utils import ModelResponse
|
||||
|
||||
ModelResponse().choices[0].message.reasoning_items = [
|
||||
{"type": "reasoning", "id": "rs_1", "summary": [{"type": "summary_text", "text": "hi"}]}
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue