test: add regression tests for #874 and #894 (#901)

Add tests for None event_date in fact extraction (AttributeError fix)
and for _register_profile skipping .env overwrite with short config keys.
This commit is contained in:
Nicolò Boschi 2026-04-07 09:43:25 +02:00 committed by GitHub
parent cf4bd598b4
commit 66cbdda3cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 116 additions and 0 deletions

View file

@ -139,3 +139,76 @@ async def test_retain_llm_max_retries_overrides_global():
assert facts == [] assert facts == []
# Verify it retried exactly retain_llm_max_retries times # Verify it retried exactly retain_llm_max_retries times
assert llm_config.call.call_count == 5 assert llm_config.call.call_count == 5
@pytest.mark.asyncio
async def test_none_event_date_with_empty_facts_no_crash():
"""
When event_date is None and the LLM returns an empty facts list,
the debug log should not crash with AttributeError on .isoformat().
Regression test for https://github.com/vectorize-io/hindsight/issues/874
"""
from hindsight_api.engine.retain.fact_extraction import _extract_facts_from_chunk
config = _make_config(llm_max_retries=1)
# LLM returns a valid dict but with no facts — triggers the debug log path
llm_config = _make_llm_config(mock_response={"facts": []})
with patch(
"hindsight_api.engine.retain.fact_extraction._build_extraction_prompt_and_schema",
return_value=("system prompt", MagicMock()),
):
facts, usage = await _extract_facts_from_chunk(
chunk="A plain text document with no timestamp.",
chunk_index=0,
total_chunks=1,
event_date=None,
context="",
llm_config=llm_config,
config=config,
agent_name="test-agent",
)
assert facts == []
@pytest.mark.asyncio
async def test_none_event_date_with_valid_facts_no_crash():
"""
When event_date is None but the LLM returns valid facts,
extraction should succeed without errors.
"""
from hindsight_api.engine.retain.fact_extraction import _extract_facts_from_chunk
config = _make_config(llm_max_retries=1)
llm_config = _make_llm_config(mock_response={
"facts": [
{
"what": "Alice visited Paris",
"when": "2023",
"who": "Alice",
"why": "vacation",
}
]
})
with patch(
"hindsight_api.engine.retain.fact_extraction._build_extraction_prompt_and_schema",
return_value=("system prompt", MagicMock()),
):
facts, usage = await _extract_facts_from_chunk(
chunk="Alice visited Paris in 2023.",
chunk_index=0,
total_chunks=1,
event_date=None,
context="",
llm_config=llm_config,
config=config,
agent_name="test-agent",
)
assert len(facts) == 1
assert "Alice visited Paris" in facts[0].fact

View file

@ -1,6 +1,9 @@
"""Tests for EmbedManager interface.""" """Tests for EmbedManager interface."""
from unittest.mock import MagicMock
from hindsight_embed import get_embed_manager from hindsight_embed import get_embed_manager
from hindsight_embed.daemon_embed_manager import DaemonEmbedManager
def test_sanitize_profile_name_via_db_url(): def test_sanitize_profile_name_via_db_url():
@ -51,3 +54,43 @@ def test_manager_singleton():
# They should produce the same results # They should produce the same results
assert manager1.get_database_url("test") == manager2.get_database_url("test") assert manager1.get_database_url("test") == manager2.get_database_url("test")
def test_register_profile_skips_when_no_api_keys():
"""
When config contains only short keys (no HINDSIGHT_API_* prefix),
_register_profile should not call create_profile, preserving any
existing profile .env file.
Regression test for https://github.com/vectorize-io/hindsight/issues/894
"""
manager = DaemonEmbedManager()
manager._profile_manager = MagicMock()
# Config with short keys (as passed from cli.py's get_config())
config = {"llm_api_key": "sk-123", "llm_provider": "openai", "llm_model": "gpt-4o"}
manager._register_profile("myprofile", 8100, config)
manager._profile_manager.create_profile.assert_not_called()
def test_register_profile_calls_create_when_api_keys_present():
"""
When config contains HINDSIGHT_API_* keys, _register_profile should
forward them to create_profile.
"""
manager = DaemonEmbedManager()
manager._profile_manager = MagicMock()
config = {
"HINDSIGHT_API_LLM_PROVIDER": "openai",
"HINDSIGHT_API_LLM_API_KEY": "sk-123",
"some_internal_key": "ignored",
}
manager._register_profile("myprofile", 8100, config)
manager._profile_manager.create_profile.assert_called_once_with(
"myprofile",
8100,
{"HINDSIGHT_API_LLM_PROVIDER": "openai", "HINDSIGHT_API_LLM_API_KEY": "sk-123"},
)