mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-12 03:48:56 +00:00
fix(decisions): cap OpenAI-format questions at the System One limit
Backport of the #45184 follow-up to stable/1.104.x.
Cherry-picked from 7ef132947a (litellm_systemone_endpoint).
This commit is contained in:
parent
77d57c3948
commit
5f4588dec4
2 changed files with 35 additions and 2 deletions
|
|
@ -8,6 +8,7 @@ from litellm.types.llms.base import LiteLLMPydanticObjectBase
|
|||
|
||||
DecisionsJSON: TypeAlias = str | Mapping[str, object] | Sequence[object]
|
||||
NoulCriteria: TypeAlias = Mapping[Literal["true", "false"], DecisionsJSON | None]
|
||||
MAX_DECISION_QUESTIONS: Final = 128
|
||||
|
||||
|
||||
class NoulQuestion(LiteLLMPydanticObjectBase):
|
||||
|
|
@ -47,7 +48,7 @@ DecisionQuestion: TypeAlias = Annotated[
|
|||
|
||||
DecisionQuestionMap: TypeAlias = Annotated[
|
||||
Mapping[Annotated[str, Field(min_length=1)], DecisionQuestion],
|
||||
Field(min_length=1, max_length=128),
|
||||
Field(min_length=1, max_length=MAX_DECISION_QUESTIONS),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -199,7 +200,7 @@ OpenAIDecisionQuestion: TypeAlias = Annotated[
|
|||
|
||||
class OpenAIDecisionRequestBody(LiteLLMPydanticObjectBase):
|
||||
input: str | Sequence[OpenAIDecisionInputMessage]
|
||||
questions: Annotated[Sequence[OpenAIDecisionQuestion], Field(min_length=1, max_length=200)]
|
||||
questions: Annotated[Sequence[OpenAIDecisionQuestion], Field(min_length=1, max_length=MAX_DECISION_QUESTIONS)]
|
||||
safety_identifier: str | None = None
|
||||
|
||||
model_config = ConfigDict(extra="allow", frozen=True)
|
||||
|
|
|
|||
32
tests/unit/decisions/test_openai_transformation.py
Normal file
32
tests/unit/decisions/test_openai_transformation.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from collections.abc import Mapping
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
from pydantic import TypeAdapter, ValidationError
|
||||
|
||||
from litellm.decisions.openai_transformation import to_systemone_request
|
||||
from litellm.types.decisions import MAX_DECISION_QUESTIONS, DecisionsRequestBody, OpenAIDecisionRequestBody
|
||||
|
||||
_OPENAI_BODY: Final[TypeAdapter[OpenAIDecisionRequestBody]] = TypeAdapter(OpenAIDecisionRequestBody)
|
||||
_SYSTEMONE_BODY: Final[TypeAdapter[DecisionsRequestBody]] = TypeAdapter(DecisionsRequestBody)
|
||||
|
||||
|
||||
def _openai_request(question_count: int) -> Mapping[str, object]:
|
||||
return {
|
||||
"model": "decider",
|
||||
"input": "The package arrived with a broken screen.",
|
||||
"questions": [{"type": "predicate", "instructions": f"Question {index}?"} for index in range(question_count)],
|
||||
}
|
||||
|
||||
|
||||
def test_the_largest_openai_request_accepted_translates_to_a_valid_systemone_request() -> None:
|
||||
raw: Final = _openai_request(MAX_DECISION_QUESTIONS)
|
||||
|
||||
translated: Final = _SYSTEMONE_BODY.validate_python(to_systemone_request(raw, _OPENAI_BODY.validate_python(raw)))
|
||||
|
||||
assert len(translated.questions) == MAX_DECISION_QUESTIONS
|
||||
|
||||
|
||||
def test_an_openai_request_with_more_questions_than_systemone_takes_is_rejected_before_translation() -> None:
|
||||
with pytest.raises(ValidationError, match="questions"):
|
||||
_OPENAI_BODY.validate_python(_openai_request(MAX_DECISION_QUESTIONS + 1))
|
||||
Loading…
Add table
Reference in a new issue