File size: 3,816 Bytes
0366d65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""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  # noqa: E402
from server.schema import ActionPlan, Event  # noqa: E402
from ui import blocks  # noqa: E402


# --- pure helpers -----------------------------------------------------------
def test_facts_to_recall_and_merge():
    facts = memory.merge_facts([], [("Dana is the coach", "contact"), "you decline Mondays"])
    assert len(facts) == 2
    # dedup + weight bump
    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)


# --- per-request injection (the whole point) --------------------------------
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


# --- UI client handlers -----------------------------------------------------
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)


# --- file import parsers ----------------------------------------------------
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