From 1a7b80096b0cb52bc864eab00aeece2f7be9f5aa Mon Sep 17 00:00:00 2001 From: timepointai Date: Wed, 25 Mar 2026 06:59:39 -0600 Subject: [PATCH] fix: correct batch resolve request format and response parsing in entity_client --- app/core/entity_client.py | 18 +++++++++++++++--- tests/unit/test_entity_client.py | 20 +++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/core/entity_client.py b/app/core/entity_client.py index 181df97..ca8ef05 100644 --- a/app/core/entity_client.py +++ b/app/core/entity_client.py @@ -75,14 +75,26 @@ async def resolve_figures( async with httpx.AsyncClient(timeout=_TIMEOUT) as client: response = await client.post( url, - json={"names": names, "entity_type": entity_type}, + json={ + "names": [ + {"display_name": n, "entity_type": entity_type} + for n in names + ] + }, headers=_get_headers(), ) response.raise_for_status() data = response.json() - # Expected response: {"resolved": {"Name": "entity_id", ...}} - resolved: dict[str, str] = data.get("resolved", {}) + # Response: {"results": [{"figure": {"id": "...", "display_name": "..."}, "created": bool}, ...]} + results: list[dict] = data.get("results", []) + resolved: dict[str, str] = {} + for item in results: + figure = item.get("figure", {}) + display_name = figure.get("display_name", "") + figure_id = figure.get("id", "") + if display_name and figure_id: + resolved[display_name] = figure_id logger.debug(f"Entity resolution: {len(resolved)}/{len(names)} names resolved") return resolved diff --git a/tests/unit/test_entity_client.py b/tests/unit/test_entity_client.py index 2142054..a01f408 100644 --- a/tests/unit/test_entity_client.py +++ b/tests/unit/test_entity_client.py @@ -22,7 +22,12 @@ async def test_resolve_figures_success(): """Mock successful batch resolve — returns name→entity_id mapping.""" mock_response = httpx.Response( 200, - json={"resolved": {"Julius Caesar": "fig_abc123", "Brutus": "fig_def456"}}, + json={ + "results": [ + {"figure": {"id": "fig_abc123", "display_name": "Julius Caesar"}, "created": True}, + {"figure": {"id": "fig_def456", "display_name": "Brutus"}, "created": False}, + ] + }, request=httpx.Request("POST", "http://test/api/v1/figures/resolve/batch"), ) @@ -45,7 +50,12 @@ async def test_resolve_figures_success(): assert result == {"Julius Caesar": "fig_abc123", "Brutus": "fig_def456"} client_instance.post.assert_called_once() call_kwargs = client_instance.post.call_args - assert call_kwargs[1]["json"] == {"names": ["Julius Caesar", "Brutus"], "entity_type": "person"} + assert call_kwargs[1]["json"] == { + "names": [ + {"display_name": "Julius Caesar", "entity_type": "person"}, + {"display_name": "Brutus", "entity_type": "person"}, + ] + } assert call_kwargs[1]["headers"]["X-Service-Key"] == "test-key" @@ -123,7 +133,11 @@ async def test_resolve_figures_falls_back_to_clockchain_url(): """When CLOCKCHAIN_ENTITY_URL is empty, should use CLOCKCHAIN_URL.""" mock_response = httpx.Response( 200, - json={"resolved": {"Napoleon": "fig_xyz"}}, + json={ + "results": [ + {"figure": {"id": "fig_xyz", "display_name": "Napoleon"}, "created": True} + ] + }, request=httpx.Request("POST", "http://clockchain/api/v1/figures/resolve/batch"), )