From e36e3aaea85a1c1ea0ae08dc4efbf48744c12c4b Mon Sep 17 00:00:00 2001 From: Hyu Date: Sat, 1 Aug 2026 18:50:47 +0800 Subject: [PATCH] fix(cloud): accept null model abilities (#2377) Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com> --- src/langbot/pkg/cloud/model_catalog.py | 5 +++++ tests/unit_tests/cloud/test_model_catalog.py | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/langbot/pkg/cloud/model_catalog.py b/src/langbot/pkg/cloud/model_catalog.py index 48b80b24b..a76376505 100644 --- a/src/langbot/pkg/cloud/model_catalog.py +++ b/src/langbot/pkg/cloud/model_catalog.py @@ -32,6 +32,11 @@ class CloudModelCatalogItem(BaseModel): is_featured: bool = False featured_order: int = 0 + @field_validator('llm_abilities', mode='before') + @classmethod + def normalize_missing_abilities(cls, value: Any) -> Any: + return () if value is None else value + @field_validator('llm_abilities') @classmethod def validate_abilities(cls, value: tuple[str, ...]) -> tuple[str, ...]: diff --git a/tests/unit_tests/cloud/test_model_catalog.py b/tests/unit_tests/cloud/test_model_catalog.py index 1a251f1e7..6f4b0a275 100644 --- a/tests/unit_tests/cloud/test_model_catalog.py +++ b/tests/unit_tests/cloud/test_model_catalog.py @@ -84,6 +84,15 @@ def _snapshot( ) +async def test_catalog_snapshot_treats_null_model_abilities_as_empty() -> None: + payload = _snapshot().model_dump(mode='json') + payload['models'][0]['llm_abilities'] = None + + snapshot = CloudModelCatalogSnapshot.model_validate(payload) + + assert snapshot.models[0].llm_abilities == () + + async def test_catalog_reconciles_every_workspace_idempotently_and_tracks_owner_and_downlisting(tmp_path) -> None: engine = create_async_engine(f'sqlite+aiosqlite:///{tmp_path / "model-catalog.db"}') manager = PersistenceManager(object(), mode=PersistenceMode.CLOUD_RUNTIME)