"""Time-awareness: gap humanizing + the 'now' note injected into chat context.""" from __future__ import annotations import importlib from datetime import timedelta import pytest from lyra import clock def test_humanize_gap_scales(): ref = clock.now() assert clock.humanize_gap(None) is None assert clock.humanize_gap((ref - timedelta(seconds=10)).isoformat(), ref) == "moments" assert clock.humanize_gap((ref - timedelta(minutes=5)).isoformat(), ref) == "5 minutes" assert clock.humanize_gap((ref - timedelta(hours=3)).isoformat(), ref) == "3 hours" assert clock.humanize_gap((ref - timedelta(days=3)).isoformat(), ref) == "3 days" assert clock.humanize_gap((ref - timedelta(days=21)).isoformat(), ref) == "3 weeks" assert clock.humanize_gap((ref - timedelta(days=90)).isoformat(), ref) == "3 months" def test_humanize_gap_handles_future_and_naive(): ref = clock.now() # future timestamp clamps to "moments", never negative assert clock.humanize_gap((ref + timedelta(hours=1)).isoformat(), ref) == "moments" # naive ISO (no tz) is treated as UTC, doesn't crash assert clock.humanize_gap("2026-06-01T00:00:00") is not None @pytest.fixture def lyra(tmp_path, monkeypatch): monkeypatch.setenv("LYRA_DB_PATH", str(tmp_path / "test.db")) from lyra import llm monkeypatch.setattr(llm, "embed", lambda texts: [[0.1, 0.2, 0.3] for _ in texts]) import lyra.memory as memory importlib.reload(memory) return memory def test_now_note_first_contact(lyra): from lyra import chat note = chat._now_note()["content"] assert "current date and time is" in note assert "first thing Brian has ever said" in note def test_now_note_reports_gap(lyra): memory = lyra memory.remember("s1", "user", "hey") from lyra import chat note = chat._now_note()["content"] assert "since Brian last spoke with you" in note