| """Per-user (client/localStorage) memory: pure helpers, parsers, UI handlers,
|
| and per-request injection into the agent prompt. Stub mode; no network."""
|
| import os
|
| from datetime import datetime
|
|
|
| os.environ.setdefault("USE_STUB_EXTRACTOR", "1")
|
|
|
| from server import agent, memory
|
| from server.schema import ActionPlan, Event
|
| from ui import blocks
|
|
|
|
|
|
|
| def test_facts_to_recall_and_merge():
|
| facts = memory.merge_facts([], [("Dana is the coach", "contact"), "you decline Mondays"])
|
| assert len(facts) == 2
|
|
|
| facts = memory.merge_facts(facts, ["Dana is the coach"])
|
| dana = [f for f in facts if "Dana" in f["text"]][0]
|
| assert dana["weight"] == 2
|
| block = memory.facts_to_recall(facts)
|
| assert "What I know about you" in block and "Dana is the coach" in block
|
| assert memory.facts_to_recall([]) == ""
|
|
|
|
|
| def test_learn_from_plan_returns_contacts():
|
| plan = ActionPlan(reasoning="x", events=[Event(title="Game", start="2026-06-12T10:00", attendees=["Coach Dana"])])
|
| learned = memory.learn_from_plan(plan)
|
| assert any("Coach Dana" in t for t in learned)
|
|
|
|
|
|
|
| def test_build_messages_uses_passed_memory():
|
| msgs = agent.build_messages("hi", datetime(2026, 6, 12, 9, 0), [], None,
|
| memory_block="What I know about you (memory):\n- Dana is the coach")
|
| blob = str(msgs)
|
| assert "Dana is the coach" in blob
|
|
|
|
|
|
|
| def test_mem_remember_and_forget_roundtrip():
|
| mem, status = blocks._mem_remember("you decline Mondays", "preference", "[]")
|
| facts = blocks._facts_load(mem)
|
| assert facts and facts[0]["text"] == "you decline Mondays"
|
| fid = facts[0]["id"]
|
| mem2, status2 = blocks._mem_forget(fid, mem)
|
| assert blocks._facts_load(mem2) == []
|
| assert "Forgotten" in status2
|
|
|
|
|
| def test_onboard_writes_facts():
|
| mem, vis, msg = blocks._on_onboard("Dana = soccer coach\nMr. Lee = teacher", 30, "Mondays", "[]")
|
| texts = [f["text"] for f in blocks._facts_load(mem)]
|
| assert any("Dana is the soccer coach" in t for t in texts)
|
| assert any("teacher" in t for t in texts)
|
| assert any("30 minutes" in t for t in texts)
|
| assert any("Mondays" in t for t in texts)
|
|
|
|
|
|
|
| def test_parse_vcf_csv_ics(tmp_path):
|
| vcf = tmp_path / "c.vcf"
|
| vcf.write_text("BEGIN:VCARD\nFN:Coach Dana\nEND:VCARD\nBEGIN:VCARD\nFN:Mr. Lee\nEND:VCARD\n")
|
| names, _ = blocks._parse_memory_file(str(vcf))
|
| assert "Coach Dana" in names and "Mr. Lee" in names
|
|
|
| csv = tmp_path / "c.csv"
|
| csv.write_text("name,phone\nAlex Kim,123\nJamie Fox,456\n")
|
| names, _ = blocks._parse_memory_file(str(csv))
|
| assert "Alex Kim" in names and "Jamie Fox" in names
|
|
|
| ics = tmp_path / "cal.ics"
|
| ics.write_text("BEGIN:VEVENT\nSUMMARY:Soccer practice\nATTENDEE;CN=Coach Dana:mailto:d@x.com\nEND:VEVENT\n")
|
| names, prefs = blocks._parse_memory_file(str(ics))
|
| assert "Coach Dana" in names
|
| assert any("Soccer practice" in p[0] for p in prefs)
|
|
|
|
|
| def test_import_file_merges_into_memory(tmp_path):
|
| vcf = tmp_path / "c.vcf"
|
| vcf.write_text("BEGIN:VCARD\nFN:Coach Dana\nEND:VCARD\n")
|
| mem, status = blocks._import_file(str(vcf), "[]")
|
| assert any("Coach Dana" in f["text"] for f in blocks._facts_load(mem))
|
| assert "Imported" in status
|
|
|
|
|
| def test_import_gcal_unchecked_is_graceful():
|
| mem, status = blocks._import_gcal(False, "[]")
|
| assert "Tick the box" in status
|
|
|