fix(products): work around Gemini int-enum schema rejection in parse-text

Gemini API rejects int-valued enums (StrengthLevel) in response_schema,
raising a validation error before any request is sent. Fix by introducing
AIActiveIngredient (inherits ActiveIngredient, overrides strength_level and
irritation_potential as Optional[int]) and ProductParseLLMResponse used only
as the Gemini schema. The two-step validation converts ints back to StrengthLevel
via Pydantic coercion. Adds a test covering the numeric strength level path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Piotr Oleszczyk 2026-03-01 22:00:48 +01:00
parent 921fe3ef61
commit 914c6087bd
2 changed files with 35 additions and 2 deletions

View file

@ -199,3 +199,22 @@ def test_create_inventory(client, created_product):
def test_create_inventory_product_not_found(client):
r = client.post(f"/products/{uuid.uuid4()}/inventory", json={})
assert r.status_code == 404
def test_parse_text_accepts_numeric_strength_levels(client, monkeypatch):
from innercontext.api import products as products_api
class _FakeResponse:
text = (
'{"name":"Test Serum","actives":[{"name":"Niacinamide","percent":10,'
'"functions":["niacinamide"],"strength_level":2,"irritation_potential":1}]}'
)
monkeypatch.setattr(products_api, "call_gemini", lambda **kwargs: _FakeResponse())
r = client.post("/products/parse-text", json={"text": "dummy input"})
assert r.status_code == 200
data = r.json()
assert data["name"] == "Test Serum"
assert data["actives"][0]["strength_level"] == 2
assert data["actives"][0]["irritation_potential"] == 1