Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions hindsight-api-slim/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
16 changes: 14 additions & 2 deletions hindsight-api-slim/tests/test_consolidation_dedup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down Expand Up @@ -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.",
Expand Down
7 changes: 7 additions & 0 deletions hindsight-api-slim/tests/test_fact_extraction_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)


Expand Down
11 changes: 11 additions & 0 deletions hindsight-api-slim/tests/test_llm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)


Expand Down
Loading