Spaces:
Sleeping
Sleeping
| import logging | |
| from lilith_agent.config import Config | |
| from lilith_agent.app import build_react_agent | |
| from langchain_core.messages import HumanMessage | |
| def test_build_react_agent_uses_sqlite_saver(tmp_path, monkeypatch): | |
| class FakeModel: | |
| def bind_tools(self, tools): | |
| return self | |
| cfg = Config.from_env() | |
| monkeypatch.setenv("LILITH_HOME", str(tmp_path / ".lilith")) | |
| monkeypatch.setattr("lilith_agent.app.get_strong_model", lambda cfg, **kw: FakeModel()) | |
| monkeypatch.setattr("lilith_agent.app.get_cheap_model", lambda cfg: FakeModel()) | |
| monkeypatch.setattr("lilith_agent.tools.build_tools", lambda cfg: []) | |
| agent = build_react_agent(cfg) | |
| assert agent.checkpointer is not None | |
| assert type(agent.checkpointer).__name__ == "SqliteSaver" | |
| # Check if DB file was created | |
| db_path = tmp_path / ".lilith" / "threads.sqlite" | |
| assert db_path.exists() | |
| def test_summarize_episode_stores_list_block_content_as_text(tmp_path, monkeypatch): | |
| from lilith_agent import memory | |
| class FakeModel: | |
| def invoke(self, prompt): | |
| class Response: | |
| content = [ | |
| {"type": "text", "text": "Captured lesson"}, | |
| {"type": "non_text", "value": "ignored"}, | |
| ] | |
| return Response() | |
| store = memory.MemoryStore(tmp_path / "long_term_memory.sqlite") | |
| monkeypatch.setattr(memory, "_store", store) | |
| memory.summarize_episode( | |
| [HumanMessage(content=[{"type": "text", "text": "Remember this"}])], | |
| FakeModel(), | |
| ) | |
| episodes = store.get_recent_episodes() | |
| assert episodes[0]["task"] == "Remember this" | |
| assert episodes[0]["summary"] == "Captured lesson" | |
| def test_summarize_episode_prints_saved_episode_details(tmp_path, monkeypatch, caplog, capsys): | |
| from lilith_agent import memory | |
| class FakeModel: | |
| def invoke(self, prompt): | |
| class Response: | |
| content = "Used read_file successfully and learned to inspect spreadsheet rows." | |
| return Response() | |
| store = memory.MemoryStore(tmp_path / "long_term_memory.sqlite") | |
| monkeypatch.setattr(memory, "_store", store) | |
| with caplog.at_level(logging.INFO, logger="lilith_agent.memory"): | |
| memory.summarize_episode([HumanMessage(content="Find oldest Blu-Ray title")], FakeModel()) | |
| printed = capsys.readouterr().out | |
| assert "[memory] Episode saved: task='Find oldest Blu-Ray title'" in printed | |
| assert "outcome='success'" in printed | |
| assert "summary='Used read_file successfully" in printed | |
| record = next(r for r in caplog.records if "[memory] Episode saved:" in r.message) | |
| assert "task='Find oldest Blu-Ray title'" in record.message | |
| assert "outcome='success'" in record.message | |
| assert "summary='Used read_file successfully" in record.message | |
| def test_summarize_episode_logs_traceback_on_failure(tmp_path, monkeypatch, caplog): | |
| from lilith_agent import memory | |
| class BrokenModel: | |
| def invoke(self, prompt): | |
| raise RuntimeError("boom") | |
| store = memory.MemoryStore(tmp_path / "long_term_memory.sqlite") | |
| monkeypatch.setattr(memory, "_store", store) | |
| with caplog.at_level(logging.ERROR, logger="lilith_agent.memory"): | |
| memory.summarize_episode([HumanMessage(content="Remember this")], BrokenModel()) | |
| record = next(r for r in caplog.records if "Summarization failed" in r.message) | |
| assert record.exc_info is not None | |
| def test_extract_and_compress_facts_passes_existing_memories_with_ids(tmp_path, monkeypatch): | |
| from lilith_agent import memory | |
| import langmem | |
| captured = {} | |
| class FakeManager: | |
| def invoke(self, payload): | |
| captured["existing"] = payload["existing"] | |
| return [] | |
| store = memory.MemoryStore(tmp_path / "long_term_memory.sqlite") | |
| store.save_memories([{"id": "memory-1", "content": "Existing fact"}]) | |
| monkeypatch.setattr(memory, "_store", store) | |
| monkeypatch.setattr(langmem, "create_memory_manager", lambda model, enable_deletes: FakeManager()) | |
| class FakeModel: | |
| def invoke(self, prompt): | |
| class Response: | |
| content = "Lesson" | |
| return Response() | |
| memory.extract_and_compress_facts([HumanMessage(content="New fact")], FakeModel()) | |
| existing_id, existing_memory = captured["existing"][0] | |
| assert existing_id == "memory-1" | |
| assert existing_memory.content == "Existing fact" | |