diff --git a/hindsight-api-slim/hindsight_api/api/http.py b/hindsight-api-slim/hindsight_api/api/http.py index 08896f35..24080396 100644 --- a/hindsight-api-slim/hindsight_api/api/http.py +++ b/hindsight-api-slim/hindsight_api/api/http.py @@ -2545,6 +2545,7 @@ def _register_routes(app: FastAPI): occurred_end=fact.occurred_end, mentioned_at=fact.mentioned_at, document_id=fact.document_id, + metadata=fact.metadata, chunk_id=fact.chunk_id, tags=fact.tags, source_fact_ids=fact.source_fact_ids, diff --git a/hindsight-api-slim/tests/test_http_api_integration.py b/hindsight-api-slim/tests/test_http_api_integration.py index a2b2b543..0a34ea13 100644 --- a/hindsight-api-slim/tests/test_http_api_integration.py +++ b/hindsight-api-slim/tests/test_http_api_integration.py @@ -1229,3 +1229,45 @@ async def test_retain_with_timestamp_async_complete_processing(api_client, test_ assert response.status_code == 200 items = response.json()["items"] assert len(items) > 0, "Should have stored memories after async processing" + + +@pytest.mark.asyncio +async def test_http_recall_preserves_metadata(api_client, test_bank_id): + """ + Regression test for #797: HTTP recall must return metadata stored during retain. + + The engine correctly preserves metadata, but _fact_to_result in http.py was + missing the metadata= kwarg, causing the HTTP endpoint to always return null. + """ + metadata = {"source": "slack", "channel": "engineering", "importance": "high"} + + # Retain with metadata + response = await api_client.post( + f"/v1/default/banks/{test_bank_id}/memories", + json={ + "items": [ + { + "content": "The product launch is scheduled for March 1st.", + "metadata": metadata, + } + ] + }, + ) + assert response.status_code == 200 + + # Recall via HTTP + response = await api_client.post( + f"/v1/default/banks/{test_bank_id}/memories/recall", + json={"query": "When is the product launch?", "budget": "low"}, + ) + assert response.status_code == 200 + results = response.json()["results"] + assert len(results) > 0, "Should recall at least one fact" + + # Find a result that has our metadata (LLM may extract multiple facts) + facts_with_metadata = [r for r in results if r.get("metadata")] + assert len(facts_with_metadata) > 0, "At least one fact must have metadata (regression #797)" + fact = facts_with_metadata[0] + assert fact["metadata"]["source"] == "slack" + assert fact["metadata"]["channel"] == "engineering" + assert fact["metadata"]["importance"] == "high"