mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
fix(proxy): serialize model block responses
Signed-off-by: samzong <samzong.lu@gmail.com>
This commit is contained in:
parent
d44d281d1d
commit
26e71ddc54
3 changed files with 55 additions and 26 deletions
|
|
@ -29,6 +29,8 @@ class LiteLLM_ProxyModelTable(LiteLLMPydanticObjectBase):
|
|||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def check_potential_json_str(cls, values):
|
||||
if not isinstance(values, dict):
|
||||
return values
|
||||
if isinstance(values.get("litellm_params"), str):
|
||||
try:
|
||||
values["litellm_params"] = json.loads(values["litellm_params"])
|
||||
|
|
|
|||
|
|
@ -180,6 +180,12 @@ class ModelBlockBody(BaseModel):
|
|||
model_id: str
|
||||
|
||||
|
||||
class ModelBlockResponse(BaseModel):
|
||||
model_config = ConfigDict(protected_namespaces=())
|
||||
model_id: str
|
||||
blocked: bool
|
||||
|
||||
|
||||
class ModelInfoBlockDetail(BaseModel):
|
||||
id: str | None = None
|
||||
blocked: bool | None = None
|
||||
|
|
@ -245,11 +251,6 @@ class TestModelRoutes:
|
|||
def test_block_then_unblock_persists_to_model_info(
|
||||
self, client: ManagementClient, resources: ResourceManager
|
||||
) -> None:
|
||||
"""The blocked flag's persistence is read back from /model/info, not from the
|
||||
/model/block response: that route currently returns a non-2xx serialization
|
||||
envelope even though the DB write lands, so the /model/info read-back is the
|
||||
authoritative persistence contract and keeps this test valid once the
|
||||
response shape is fixed."""
|
||||
model_name = f"e2e-mgmt-model-block-{unique_marker()}"
|
||||
model_id = _create_db_model(client, resources, model_name)
|
||||
|
||||
|
|
@ -257,27 +258,25 @@ class TestModelRoutes:
|
|||
f"{model_name!r} already reports blocked in /model/info before /model/block ran"
|
||||
)
|
||||
|
||||
_ = client.proxy.transport.send(
|
||||
"/model/block",
|
||||
headers=client.proxy.transport.master,
|
||||
json=ModelBlockBody(model_id=model_id),
|
||||
)
|
||||
_ = _poll(
|
||||
client.proxy,
|
||||
lambda: True if _model_blocked_flag(client, model_id) is True else None,
|
||||
f"/model/info never reported {model_name!r} blocked after /model/block",
|
||||
)
|
||||
|
||||
_ = client.proxy.transport.send(
|
||||
"/model/unblock",
|
||||
headers=client.proxy.transport.master,
|
||||
json=ModelBlockBody(model_id=model_id),
|
||||
)
|
||||
_ = _poll(
|
||||
client.proxy,
|
||||
lambda: True if _model_blocked_flag(client, model_id) is not True else None,
|
||||
f"/model/info never cleared blocked for {model_name!r} after /model/unblock",
|
||||
)
|
||||
for action, expected in (("block", True), ("unblock", False)):
|
||||
response = unwrap(
|
||||
client.proxy.transport.post(
|
||||
f"/model/{action}",
|
||||
headers=client.proxy.transport.master,
|
||||
json=ModelBlockBody(model_id=model_id),
|
||||
response_type=ModelBlockResponse,
|
||||
)
|
||||
)
|
||||
assert response.model_id == model_id
|
||||
assert response.blocked is expected
|
||||
_ = _poll(
|
||||
client.proxy,
|
||||
lambda: True
|
||||
if _model_blocked_flag(client, model_id) is expected
|
||||
else None,
|
||||
f"/model/info never reported blocked={expected} for {model_name!r} "
|
||||
f"after /model/{action}",
|
||||
)
|
||||
|
||||
|
||||
class TestTagRoutes:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Tests for backend domain models.
|
|||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from pydantic import BaseModel, TypeAdapter
|
||||
|
||||
from litellm.models.access_group import LiteLLM_AccessGroupTable
|
||||
from litellm.models.budget import (
|
||||
|
|
@ -130,6 +131,33 @@ class TestModel:
|
|||
assert model.litellm_params == {"model": "gpt-4"}
|
||||
assert model.model_info == {"team_id": "t1"}
|
||||
|
||||
def test_response_type_adapter_accepts_pydantic_row(self):
|
||||
class PrismaModelRow(BaseModel):
|
||||
model_id: str
|
||||
model_name: str
|
||||
litellm_params: dict[str, str]
|
||||
model_info: dict[str, str] | None = None
|
||||
blocked: bool = False
|
||||
|
||||
row = PrismaModelRow(
|
||||
model_id="m1",
|
||||
model_name="gpt-4",
|
||||
litellm_params={"model": "gpt-4"},
|
||||
model_info={"team_id": "t1"},
|
||||
blocked=True,
|
||||
)
|
||||
|
||||
model = TypeAdapter(LiteLLM_ProxyModelTable | None).validate_python(
|
||||
row,
|
||||
from_attributes=True,
|
||||
)
|
||||
|
||||
assert model is not None
|
||||
assert model.model_id == "m1"
|
||||
assert model.litellm_params == {"model": "gpt-4"}
|
||||
assert model.model_info == {"team_id": "t1"}
|
||||
assert model.blocked is True
|
||||
|
||||
def test_team_helpers_none_when_no_model_info(self):
|
||||
model = LiteLLM_ProxyModelTable(
|
||||
model_id="m1", model_name="gpt-4", litellm_params={}, model_info=None
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue