diff --git a/hindsight-api-slim/tests/conftest.py b/hindsight-api-slim/tests/conftest.py index 586c9ab88..4c5bf05dd 100644 --- a/hindsight-api-slim/tests/conftest.py +++ b/hindsight-api-slim/tests/conftest.py @@ -54,6 +54,29 @@ async def _teardown_memory_engine(mem: MemoryEngine) -> None: unregister_span_recorder(mem._llm_recorder) +@pytest.fixture(autouse=True) +def _cleanup_leaked_span_recorders(): + """Fail-safe for the process-global LLM-trace recorder registry (#2229). + + ``MemoryEngine.__init__`` registers its recorder in the shared registry, and + only ``close()`` removes it. Tests that construct an engine directly (without + ``_teardown_memory_engine``/``close()``) leak an *enabled* recorder; a later + test's LLM calls then get recorded into the shared DB, flaking + ``test_llm_trace::test_disabled_writes_no_rows`` (it observes rows for its + bank even though its own recorder is disabled). ``_teardown_memory_engine`` + guards the fixtures; this guards everything else by dropping any recorder a + test added to the registry. + """ + from hindsight_api.tracing import get_span_recorder + + recorders = get_span_recorder()._recorders + before = {id(r) for r in recorders} + yield + for recorder in list(recorders): + if id(recorder) not in before: + recorders.remove(recorder) + + # Default pg0 instance configuration for tests DEFAULT_PG0_INSTANCE_NAME = "hindsight-test" DEFAULT_PG0_PORT = int(os.environ.get("HINDSIGHT_TEST_PG_PORT", "5556")) diff --git a/hindsight-api-slim/tests/test_consolidation_dedup.py b/hindsight-api-slim/tests/test_consolidation_dedup.py index fce31015b..aa8417e3a 100644 --- a/hindsight-api-slim/tests/test_consolidation_dedup.py +++ b/hindsight-api-slim/tests/test_consolidation_dedup.py @@ -84,7 +84,13 @@ def _ctx(threshold: float = 0.97): conn=conn, memory_engine=types.SimpleNamespace(embeddings=object()), bank_id="bank1", - config=types.SimpleNamespace(consolidation_dedup_threshold=threshold), + # The merge path builds a search_vector UPDATE clause from the text-search + # config, so these must be present (production defaults: native/english). + config=types.SimpleNamespace( + consolidation_dedup_threshold=threshold, + text_search_extension="native", + text_search_extension_native_language="english", + ), dedup_llm_config=llm, create_text="YouTube content in Uzbek is very rich.", create_source_ids=[uuid.uuid4()], @@ -179,7 +185,13 @@ def _update_ctx(threshold: float = 0.97): conn=conn, memory_engine=types.SimpleNamespace(embeddings=object()), bank_id="bank1", - config=types.SimpleNamespace(consolidation_dedup_threshold=threshold), + # The merge path builds a search_vector UPDATE clause from the text-search + # config, so these must be present (production defaults: native/english). + config=types.SimpleNamespace( + consolidation_dedup_threshold=threshold, + text_search_extension="native", + text_search_extension_native_language="english", + ), dedup_llm_config=llm, updated_id=_UPDATED_ID, updated_text="Uzbek content on YouTube is very rich and growing.", diff --git a/hindsight-api-slim/tests/test_fact_extraction_analysis.py b/hindsight-api-slim/tests/test_fact_extraction_analysis.py index 78d6a7be5..de985e33d 100644 --- a/hindsight-api-slim/tests/test_fact_extraction_analysis.py +++ b/hindsight-api-slim/tests/test_fact_extraction_analysis.py @@ -27,6 +27,13 @@ def llm_config(): api_key=config.retain_llm_api_key or config.llm_api_key, model=config.retain_llm_model or config.llm_model, base_url=config.retain_llm_base_url or config.llm_base_url, + # LLMConfig uses these as-passed and no longer reads them from global config, + # so the caller must forward the Vertex AI settings (mirrors MemoryEngine's + # own LLMConfig construction). Without this, provider=vertexai raises + # "HINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID is required" even when it is set. + vertexai_project_id=config.llm_vertexai_project_id, + vertexai_region=config.llm_vertexai_region, + vertexai_service_account_key=config.llm_vertexai_service_account_key, ) diff --git a/hindsight-api-slim/tests/test_llm_provider.py b/hindsight-api-slim/tests/test_llm_provider.py index 331a1f8d3..7f92e21ca 100644 --- a/hindsight-api-slim/tests/test_llm_provider.py +++ b/hindsight-api-slim/tests/test_llm_provider.py @@ -45,11 +45,22 @@ def _get_api_key() -> str: def _make_llm() -> LLMProvider: + # LLMProvider uses provider-specific settings as-passed (it does not resolve + # them from global config), so forward the ones whose providers require them: + # Vertex AI needs project/region, and litellmrouter needs its router config. + # Without these, provider=vertexai/litellmrouter raise at construction. + from hindsight_api.config import get_config + + config = get_config() return LLMProvider( provider=_PROVIDER, api_key=_get_api_key(), base_url=os.environ.get("HINDSIGHT_API_LLM_BASE_URL", ""), model=_MODEL, + vertexai_project_id=config.llm_vertexai_project_id, + vertexai_region=config.llm_vertexai_region, + vertexai_service_account_key=config.llm_vertexai_service_account_key, + litellmrouter_config=config.llm_litellmrouter_config, )