log + cli idk
i need some kind of notif system
This commit is contained in:
7 files changed
+399
-130
No files matched your search
@@ -56,24 +56,37 @@ import uuid
|
||||
from agentmsgs.core.types import Agent, Thread, Message
|
||||
import datetime
|
||||
|
||||
|
||||
def test_agent_identity_on_id_not_name():
|
||||
a1 = Agent(id=uuid.uuid4(), name="Alice")
|
||||
a2 = Agent(id=uuid.uuid4(), name="Alice")
|
||||
assert a1 != a2 # different id => not equal even though name same
|
||||
assert hash(a1) != hash(a2)
|
||||
|
||||
|
||||
def test_agent_hash_on_id():
|
||||
uid = uuid.uuid4()
|
||||
a1 = Agent(id=uid, name="Alice")
|
||||
a2 = Agent(id=uid, name="Bob") # same id, different name => equal per design (id is identity)
|
||||
a2 = Agent(
|
||||
id=uid, name="Bob"
|
||||
) # same id, different name => equal per design (id is identity)
|
||||
assert a1 == a2
|
||||
assert hash(a1) == hash(a2)
|
||||
|
||||
|
||||
def test_thread_multiple_with_same_participants_allowed():
|
||||
a = Agent(id=uuid.uuid4(), name="A")
|
||||
b = Agent(id=uuid.uuid4(), name="B")
|
||||
t1 = Thread(id=uuid.uuid4(), participants=frozenset({a,b}), created_at=datetime.datetime.now(datetime.timezone.utc))
|
||||
t2 = Thread(id=uuid.uuid4(), participants=frozenset({a,b}), created_at=datetime.datetime.now(datetime.timezone.utc))
|
||||
t1 = Thread(
|
||||
id=uuid.uuid4(),
|
||||
participants=frozenset({a, b}),
|
||||
created_at=datetime.datetime.now(datetime.timezone.utc),
|
||||
)
|
||||
t2 = Thread(
|
||||
id=uuid.uuid4(),
|
||||
participants=frozenset({a, b}),
|
||||
created_at=datetime.datetime.now(datetime.timezone.utc),
|
||||
)
|
||||
assert t1 != t2
|
||||
assert t1.participants == t2.participants
|
||||
```
|
||||
@@ -92,12 +105,18 @@ import uuid
|
||||
import datetime
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Agent:
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
def __hash__(self): return hash(self.id)
|
||||
def __eq__(self, other): return isinstance(other, Agent) and self.id == other.id
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.id)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Agent) and self.id == other.id
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Message:
|
||||
@@ -107,6 +126,7 @@ class Message:
|
||||
seq: int
|
||||
ts: datetime.datetime
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class Thread:
|
||||
id: uuid.UUID
|
||||
@@ -146,10 +166,27 @@ from typing import Protocol
|
||||
from agentmsgs.core.store import Store
|
||||
import inspect
|
||||
|
||||
|
||||
def test_store_is_protocol():
|
||||
assert issubclass(Store, Protocol)
|
||||
# check required methods exist
|
||||
for m in ["get_or_create_agent","get_agent_by_name","get_agent_by_id","create_agent","delete_agent","create_thread","get_thread","find_threads","add_participant","remove_participant","delete_thread","append_message","list_messages","get_cursor","set_cursor"]:
|
||||
for m in [
|
||||
"get_or_create_agent",
|
||||
"get_agent_by_name",
|
||||
"get_agent_by_id",
|
||||
"create_agent",
|
||||
"delete_agent",
|
||||
"create_thread",
|
||||
"get_thread",
|
||||
"find_threads",
|
||||
"add_participant",
|
||||
"remove_participant",
|
||||
"delete_thread",
|
||||
"append_message",
|
||||
"list_messages",
|
||||
"get_cursor",
|
||||
"set_cursor",
|
||||
]:
|
||||
assert hasattr(Store, m), f"missing {m}"
|
||||
```
|
||||
|
||||
@@ -167,6 +204,7 @@ from typing import Protocol
|
||||
import uuid
|
||||
from .types import Agent, Thread, Message
|
||||
|
||||
|
||||
class Store(Protocol):
|
||||
def get_or_create_agent(self, name: str) -> Agent: ...
|
||||
def get_agent_by_name(self, name: str) -> Agent | None: ...
|
||||
@@ -180,8 +218,12 @@ class Store(Protocol):
|
||||
def add_participant(self, thread_id: uuid.UUID, agent: Agent) -> Thread: ...
|
||||
def remove_participant(self, thread_id: uuid.UUID, agent: Agent) -> Thread: ...
|
||||
def delete_thread(self, id: uuid.UUID) -> None: ...
|
||||
def append_message(self, thread_id: uuid.UUID, sender: Agent, content: str) -> Message: ...
|
||||
def list_messages(self, thread_id: uuid.UUID, after_seq: int = 0) -> list[Message]: ...
|
||||
def append_message(
|
||||
self, thread_id: uuid.UUID, sender: Agent, content: str
|
||||
) -> Message: ...
|
||||
def list_messages(
|
||||
self, thread_id: uuid.UUID, after_seq: int = 0
|
||||
) -> list[Message]: ...
|
||||
def get_cursor(self, thread_id: uuid.UUID, agent: Agent) -> int: ...
|
||||
def set_cursor(self, thread_id: uuid.UUID, agent: Agent, seq: int) -> None: ...
|
||||
```
|
||||
@@ -217,6 +259,7 @@ git commit -m "feat: add Store Protocol (dumb I/O)"
|
||||
# tests/test_store_memory.py
|
||||
from agentmsgs.stores.memory import InMemoryStore
|
||||
|
||||
|
||||
def test_memory_create_and_find_thread():
|
||||
s = InMemoryStore()
|
||||
alice = s.get_or_create_agent("Alice")
|
||||
@@ -227,12 +270,14 @@ def test_memory_create_and_find_thread():
|
||||
assert t in s.find_threads({alice, bob})
|
||||
assert s.find_threads({alice, bob, s.get_or_create_agent("Charlie")}) == []
|
||||
|
||||
|
||||
def test_memory_soft_unique_name():
|
||||
s = InMemoryStore()
|
||||
a1 = s.get_or_create_agent("Alice")
|
||||
a2 = s.get_or_create_agent("Alice")
|
||||
assert a1.id == a2.id
|
||||
|
||||
|
||||
def test_memory_delete_account():
|
||||
s = InMemoryStore()
|
||||
a = s.get_or_create_agent("Alice")
|
||||
@@ -240,10 +285,12 @@ def test_memory_delete_account():
|
||||
assert s.get_agent_by_id(a.id) is None
|
||||
assert s.get_agent_by_name("Alice") is None
|
||||
|
||||
|
||||
def test_memory_append_and_list():
|
||||
s = InMemoryStore()
|
||||
a = s.get_or_create_agent("A"); b = s.get_or_create_agent("B")
|
||||
t = s.create_thread({a,b})
|
||||
a = s.get_or_create_agent("A")
|
||||
b = s.get_or_create_agent("B")
|
||||
t = s.create_thread({a, b})
|
||||
m1 = s.append_message(t.id, a, "hi")
|
||||
m2 = s.append_message(t.id, b, "yo")
|
||||
assert m1.seq == 1 and m2.seq == 2
|
||||
@@ -263,6 +310,7 @@ import uuid, datetime
|
||||
from collections import defaultdict
|
||||
from agentmsgs.core.types import Agent, Thread, Message
|
||||
|
||||
|
||||
class InMemoryStore:
|
||||
def __init__(self):
|
||||
self._agents: dict[uuid.UUID, Agent] = {}
|
||||
@@ -270,51 +318,102 @@ class InMemoryStore:
|
||||
self._threads: dict[uuid.UUID, Thread] = {}
|
||||
self._msgs: dict[uuid.UUID, list[Message]] = defaultdict(list)
|
||||
self._cursors: dict[tuple[uuid.UUID, uuid.UUID], int] = {}
|
||||
|
||||
def get_or_create_agent(self, name):
|
||||
if name in self._name_idx:
|
||||
return self._agents[self._name_idx[name]]
|
||||
return self.create_agent(name)
|
||||
|
||||
def create_agent(self, name):
|
||||
if name in self._name_idx: raise ValueError(f"agent name taken: {name}")
|
||||
if name in self._name_idx:
|
||||
raise ValueError(f"agent name taken: {name}")
|
||||
a = Agent(id=uuid.uuid4(), name=name)
|
||||
self._agents[a.id]=a; self._name_idx[name]=a.id; return a
|
||||
def get_agent_by_name(self, name):
|
||||
uid=self._name_idx.get(name)
|
||||
self._agents[a.id] = a
|
||||
self._name_idx[name] = a.id
|
||||
return a
|
||||
|
||||
def get_agent_by_name(self, name):
|
||||
uid = self._name_idx.get(name)
|
||||
return self._agents.get(uid) if uid else None
|
||||
def get_agent_by_id(self, id): return self._agents.get(id)
|
||||
|
||||
def get_agent_by_id(self, id):
|
||||
return self._agents.get(id)
|
||||
|
||||
def delete_agent(self, id):
|
||||
a=self._agents.pop(id, None)
|
||||
if a: self._name_idx.pop(a.name, None)
|
||||
a = self._agents.pop(id, None)
|
||||
if a:
|
||||
self._name_idx.pop(a.name, None)
|
||||
# remove from threads
|
||||
for tid,t in list(self._threads.items()):
|
||||
for tid, t in list(self._threads.items()):
|
||||
if a in t.participants:
|
||||
self._threads[tid]=Thread(id=t.id, participants=t.participants-{a}, created_at=t.created_at)
|
||||
def list_agents(self): return list(self._agents.values())
|
||||
self._threads[tid] = Thread(
|
||||
id=t.id, participants=t.participants - {a}, created_at=t.created_at
|
||||
)
|
||||
|
||||
def list_agents(self):
|
||||
return list(self._agents.values())
|
||||
|
||||
def create_thread(self, participants):
|
||||
if len(participants)<2: raise ValueError("need >=2 participants")
|
||||
t=Thread(id=uuid.uuid4(), participants=frozenset(participants), created_at=datetime.datetime.now(datetime.timezone.utc))
|
||||
self._threads[t.id]=t; return t
|
||||
def get_thread(self, id): return self._threads.get(id)
|
||||
if len(participants) < 2:
|
||||
raise ValueError("need >=2 participants")
|
||||
t = Thread(
|
||||
id=uuid.uuid4(),
|
||||
participants=frozenset(participants),
|
||||
created_at=datetime.datetime.now(datetime.timezone.utc),
|
||||
)
|
||||
self._threads[t.id] = t
|
||||
return t
|
||||
|
||||
def get_thread(self, id):
|
||||
return self._threads.get(id)
|
||||
|
||||
def find_threads(self, containing):
|
||||
return [t for t in self._threads.values() if containing<=t.participants]
|
||||
return [t for t in self._threads.values() if containing <= t.participants]
|
||||
|
||||
def add_participant(self, thread_id, agent):
|
||||
t=self._threads[thread_id]
|
||||
nt=Thread(id=t.id, participants=t.participants|{agent}, created_at=t.created_at)
|
||||
self._threads[thread_id]=nt; return nt
|
||||
t = self._threads[thread_id]
|
||||
nt = Thread(
|
||||
id=t.id, participants=t.participants | {agent}, created_at=t.created_at
|
||||
)
|
||||
self._threads[thread_id] = nt
|
||||
return nt
|
||||
|
||||
def remove_participant(self, thread_id, agent):
|
||||
t=self._threads[thread_id]
|
||||
nt=Thread(id=t.id, participants=t.participants-{agent}, created_at=t.created_at)
|
||||
self._threads[thread_id]=nt; return nt
|
||||
def delete_thread(self, id): self._threads.pop(id,None); self._msgs.pop(id,None)
|
||||
t = self._threads[thread_id]
|
||||
nt = Thread(
|
||||
id=t.id, participants=t.participants - {agent}, created_at=t.created_at
|
||||
)
|
||||
self._threads[thread_id] = nt
|
||||
return nt
|
||||
|
||||
def delete_thread(self, id):
|
||||
self._threads.pop(id, None)
|
||||
self._msgs.pop(id, None)
|
||||
|
||||
def append_message(self, thread_id, sender, content):
|
||||
if thread_id not in self._threads: raise KeyError(thread_id)
|
||||
if sender not in self._threads[thread_id].participants: raise ValueError("sender not in thread")
|
||||
seq=len(self._msgs[thread_id])+1
|
||||
m=Message(id=uuid.uuid4(), sender=sender, content=content, seq=seq, ts=datetime.datetime.now(datetime.timezone.utc))
|
||||
self._msgs[thread_id].append(m); return m
|
||||
def list_messages(self, thread_id, after_seq=0): return [m for m in self._msgs.get(thread_id,[]) if m.seq>after_seq]
|
||||
def get_cursor(self, thread_id, agent): return self._cursors.get((thread_id, agent.id),0)
|
||||
def set_cursor(self, thread_id, agent, seq): self._cursors[(thread_id, agent.id)]=seq
|
||||
if thread_id not in self._threads:
|
||||
raise KeyError(thread_id)
|
||||
if sender not in self._threads[thread_id].participants:
|
||||
raise ValueError("sender not in thread")
|
||||
seq = len(self._msgs[thread_id]) + 1
|
||||
m = Message(
|
||||
id=uuid.uuid4(),
|
||||
sender=sender,
|
||||
content=content,
|
||||
seq=seq,
|
||||
ts=datetime.datetime.now(datetime.timezone.utc),
|
||||
)
|
||||
self._msgs[thread_id].append(m)
|
||||
return m
|
||||
|
||||
def list_messages(self, thread_id, after_seq=0):
|
||||
return [m for m in self._msgs.get(thread_id, []) if m.seq > after_seq]
|
||||
|
||||
def get_cursor(self, thread_id, agent):
|
||||
return self._cursors.get((thread_id, agent.id), 0)
|
||||
|
||||
def set_cursor(self, thread_id, agent, seq):
|
||||
self._cursors[(thread_id, agent.id)] = seq
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
@@ -348,12 +447,14 @@ git commit -m "feat: add InMemoryStore (dict-backed Store)"
|
||||
import tempfile, pathlib
|
||||
from agentmsgs.stores.sqlite import SQLiteStore
|
||||
|
||||
|
||||
def test_sqlite_persists_across_handles():
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p = pathlib.Path(d)/"test.db"
|
||||
p = pathlib.Path(d) / "test.db"
|
||||
s1 = SQLiteStore(p)
|
||||
a = s1.get_or_create_agent("Alice"); b = s1.get_or_create_agent("Bob")
|
||||
t = s1.create_thread({a,b})
|
||||
a = s1.get_or_create_agent("Alice")
|
||||
b = s1.get_or_create_agent("Bob")
|
||||
t = s1.create_thread({a, b})
|
||||
s1.append_message(t.id, a, "hi")
|
||||
# new handle same file
|
||||
s2 = SQLiteStore(p)
|
||||
@@ -361,16 +462,21 @@ def test_sqlite_persists_across_handles():
|
||||
assert len(s2.list_messages(t.id)) == 1
|
||||
assert s2.find_threads({a})[0].id == t.id
|
||||
|
||||
|
||||
def test_sqlite_concurrent_append():
|
||||
import pathlib, tempfile
|
||||
from agentmsgs.stores.sqlite import SQLiteStore
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p = pathlib.Path(d)/"c.db"
|
||||
s1 = SQLiteStore(p); s2 = SQLiteStore(p)
|
||||
a = s1.get_or_create_agent("A"); b = s1.get_or_create_agent("B")
|
||||
p = pathlib.Path(d) / "c.db"
|
||||
s1 = SQLiteStore(p)
|
||||
s2 = SQLiteStore(p)
|
||||
a = s1.get_or_create_agent("A")
|
||||
b = s1.get_or_create_agent("B")
|
||||
# s2 sees same agents via file
|
||||
a2 = s2.get_agent_by_name("A"); b2 = s2.get_agent_by_name("B")
|
||||
t = s1.create_thread({a,b})
|
||||
a2 = s2.get_agent_by_name("A")
|
||||
b2 = s2.get_agent_by_name("B")
|
||||
t = s1.create_thread({a, b})
|
||||
s1.append_message(t.id, a, "from s1")
|
||||
s2.append_message(t.id, b2, "from s2")
|
||||
assert len(s1.list_messages(t.id)) == 2
|
||||
@@ -437,20 +543,25 @@ git commit -m "feat: add SQLiteStore (WAL, file-shared)"
|
||||
from agentmsgs.stores.memory import InMemoryStore
|
||||
from agentmsgs.core import ops
|
||||
|
||||
|
||||
def test_ops_validates_sender_must_be_in_thread():
|
||||
s = InMemoryStore()
|
||||
a = ops.get_or_create_agent(s, "A"); b = ops.get_or_create_agent(s, "B"); c = ops.get_or_create_agent(s, "C")
|
||||
t = ops.create_thread(s, {a,b})
|
||||
a = ops.get_or_create_agent(s, "A")
|
||||
b = ops.get_or_create_agent(s, "B")
|
||||
c = ops.get_or_create_agent(s, "C")
|
||||
t = ops.create_thread(s, {a, b})
|
||||
try:
|
||||
ops.append_message(s, t.id, c, "oops")
|
||||
assert False, "should raise"
|
||||
except ValueError as e:
|
||||
assert "not in thread" in str(e)
|
||||
|
||||
|
||||
def test_ops_has_unread_exclude_own():
|
||||
s = InMemoryStore()
|
||||
a = ops.get_or_create_agent(s, "A"); b = ops.get_or_create_agent(s, "B")
|
||||
t = ops.create_thread(s, {a,b})
|
||||
a = ops.get_or_create_agent(s, "A")
|
||||
b = ops.get_or_create_agent(s, "B")
|
||||
t = ops.create_thread(s, {a, b})
|
||||
ops.append_message(s, t.id, a, "a1")
|
||||
# b has unread, a's own message shouldn't count if exclude_own
|
||||
assert ops.has_unread(s, t.id, b) is True
|
||||
@@ -459,10 +570,13 @@ def test_ops_has_unread_exclude_own():
|
||||
ops.mark_read(s, t.id, b, 1)
|
||||
assert ops.has_unread(s, t.id, b) is False
|
||||
|
||||
|
||||
def test_ops_join_and_delete():
|
||||
s = InMemoryStore()
|
||||
a = ops.get_or_create_agent(s, "A"); b = ops.get_or_create_agent(s, "B"); c = ops.get_or_create_agent(s, "C")
|
||||
t = ops.create_thread(s, {a,b})
|
||||
a = ops.get_or_create_agent(s, "A")
|
||||
b = ops.get_or_create_agent(s, "B")
|
||||
c = ops.get_or_create_agent(s, "C")
|
||||
t = ops.create_thread(s, {a, b})
|
||||
t2 = ops.join_thread(s, t.id, c)
|
||||
assert c in t2.participants
|
||||
ops.delete_agent(s, c.id)
|
||||
@@ -482,24 +596,57 @@ from .store import Store
|
||||
from .types import Agent, Thread
|
||||
import uuid
|
||||
|
||||
def get_or_create_agent(store: Store, name: str) -> Agent: return store.get_or_create_agent(name)
|
||||
def create_agent(store: Store, name: str) -> Agent: return store.create_agent(name)
|
||||
def delete_agent(store: Store, id: uuid.UUID) -> None: return store.delete_agent(id)
|
||||
|
||||
def get_or_create_agent(store: Store, name: str) -> Agent:
|
||||
return store.get_or_create_agent(name)
|
||||
|
||||
|
||||
def create_agent(store: Store, name: str) -> Agent:
|
||||
return store.create_agent(name)
|
||||
|
||||
|
||||
def delete_agent(store: Store, id: uuid.UUID) -> None:
|
||||
return store.delete_agent(id)
|
||||
|
||||
|
||||
def create_thread(store: Store, participants: set[Agent]) -> Thread:
|
||||
if len(participants)<2: raise ValueError("need >=2")
|
||||
if len(participants) < 2:
|
||||
raise ValueError("need >=2")
|
||||
return store.create_thread(participants)
|
||||
def find_threads(store: Store, containing: set[Agent]): return store.find_threads(containing)
|
||||
def join_thread(store: Store, tid, agent): return store.add_participant(tid, agent)
|
||||
def leave_thread(store: Store, tid, agent): return store.remove_participant(tid, agent)
|
||||
def append_message(store: Store, tid, sender, content): return store.append_message(tid, sender, content)
|
||||
def list_messages(store: Store, tid, after_seq=0): return store.list_messages(tid, after_seq)
|
||||
def mark_read(store: Store, tid, agent, seq): return store.set_cursor(tid, agent, seq)
|
||||
|
||||
|
||||
def find_threads(store: Store, containing: set[Agent]):
|
||||
return store.find_threads(containing)
|
||||
|
||||
|
||||
def join_thread(store: Store, tid, agent):
|
||||
return store.add_participant(tid, agent)
|
||||
|
||||
|
||||
def leave_thread(store: Store, tid, agent):
|
||||
return store.remove_participant(tid, agent)
|
||||
|
||||
|
||||
def append_message(store: Store, tid, sender, content):
|
||||
return store.append_message(tid, sender, content)
|
||||
|
||||
|
||||
def list_messages(store: Store, tid, after_seq=0):
|
||||
return store.list_messages(tid, after_seq)
|
||||
|
||||
|
||||
def mark_read(store: Store, tid, agent, seq):
|
||||
return store.set_cursor(tid, agent, seq)
|
||||
|
||||
|
||||
def has_unread(store: Store, tid, agent, exclude_own=False):
|
||||
cur=store.get_cursor(tid, agent)
|
||||
msgs=store.list_messages(tid, after_seq=cur)
|
||||
if not msgs: return False
|
||||
if exclude_own: msgs=[m for m in msgs if m.sender.id != agent.id]
|
||||
return len(msgs)>0
|
||||
cur = store.get_cursor(tid, agent)
|
||||
msgs = store.list_messages(tid, after_seq=cur)
|
||||
if not msgs:
|
||||
return False
|
||||
if exclude_own:
|
||||
msgs = [m for m in msgs if m.sender.id != agent.id]
|
||||
return len(msgs) > 0
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
@@ -534,6 +681,7 @@ git commit -m "feat: add ops (validation + has_unread/join/delete)"
|
||||
from agentmsgs.core.app import App
|
||||
from agentmsgs.stores.memory import InMemoryStore
|
||||
|
||||
|
||||
def test_app_facade_with_memory():
|
||||
app = App(store=InMemoryStore())
|
||||
alice = app.get_or_create_agent("Alice")
|
||||
@@ -542,13 +690,15 @@ def test_app_facade_with_memory():
|
||||
app.append(t.id, alice, "hello")
|
||||
assert app.has_unread(t.id, bob) is True
|
||||
msgs = app.poll(t.id, bob)
|
||||
assert len(msgs)==1
|
||||
assert len(msgs) == 1
|
||||
app.mark_read(t.id, bob, msgs[0].seq)
|
||||
assert app.has_unread(t.id, bob) is False
|
||||
|
||||
|
||||
def test_app_delete_account():
|
||||
from agentmsgs.core.app import App
|
||||
from agentmsgs.stores.memory import InMemoryStore
|
||||
|
||||
app = App(store=InMemoryStore())
|
||||
a = app.get_or_create_agent("A")
|
||||
app.delete_account(a.id)
|
||||
@@ -569,25 +719,60 @@ from agentmsgs.stores.memory import InMemoryStore
|
||||
from . import ops
|
||||
from .store import Store
|
||||
|
||||
|
||||
@dataclass
|
||||
class App:
|
||||
store: Store = field(default_factory=InMemoryStore)
|
||||
def get_or_create_agent(self, name): return ops.get_or_create_agent(self.store, name)
|
||||
def create_agent(self, name): return ops.create_agent(self.store, name)
|
||||
def delete_account(self, id): return ops.delete_agent(self.store, id)
|
||||
def create_thread(self, *agents): return ops.create_thread(self.store, set(agents))
|
||||
def get_thread(self, id): return self.store.get_thread(id)
|
||||
def find_threads(self, *agents): return ops.find_threads(self.store, set(agents))
|
||||
def find_thread(self, *agents): return self.find_threads(*agents) # compat
|
||||
def join_thread(self, tid, agent): return ops.join_thread(self.store, tid, agent)
|
||||
def leave_thread(self, tid, agent): return ops.leave_thread(self.store, tid, agent)
|
||||
def append(self, tid, sender, content): return ops.append_message(self.store, tid, sender, content)
|
||||
def poll(self, tid, agent, after_seq=0): return ops.list_messages(self.store, tid, after_seq)
|
||||
def mark_read(self, tid, agent, seq): return ops.mark_read(self.store, tid, agent, seq)
|
||||
def has_unread(self, tid, agent, exclude_own=False): return ops.has_unread(self.store, tid, agent, exclude_own)
|
||||
|
||||
def get_or_create_agent(self, name):
|
||||
return ops.get_or_create_agent(self.store, name)
|
||||
|
||||
def create_agent(self, name):
|
||||
return ops.create_agent(self.store, name)
|
||||
|
||||
def delete_account(self, id):
|
||||
return ops.delete_agent(self.store, id)
|
||||
|
||||
def create_thread(self, *agents):
|
||||
return ops.create_thread(self.store, set(agents))
|
||||
|
||||
def get_thread(self, id):
|
||||
return self.store.get_thread(id)
|
||||
|
||||
def find_threads(self, *agents):
|
||||
return ops.find_threads(self.store, set(agents))
|
||||
|
||||
def find_thread(self, *agents):
|
||||
return self.find_threads(*agents) # compat
|
||||
|
||||
def join_thread(self, tid, agent):
|
||||
return ops.join_thread(self.store, tid, agent)
|
||||
|
||||
def leave_thread(self, tid, agent):
|
||||
return ops.leave_thread(self.store, tid, agent)
|
||||
|
||||
def append(self, tid, sender, content):
|
||||
return ops.append_message(self.store, tid, sender, content)
|
||||
|
||||
def poll(self, tid, agent, after_seq=0):
|
||||
return ops.list_messages(self.store, tid, after_seq)
|
||||
|
||||
def mark_read(self, tid, agent, seq):
|
||||
return ops.mark_read(self.store, tid, agent, seq)
|
||||
|
||||
def has_unread(self, tid, agent, exclude_own=False):
|
||||
return ops.has_unread(self.store, tid, agent, exclude_own)
|
||||
|
||||
# compat shims for old tests
|
||||
def add_thread(self, *a): return self.create_thread(*a)
|
||||
def add_thread_2(self, thread): return self.store._threads.__setitem__(thread.id, thread) if hasattr(self.store,'_threads') else None
|
||||
def add_thread(self, *a):
|
||||
return self.create_thread(*a)
|
||||
|
||||
def add_thread_2(self, thread):
|
||||
return (
|
||||
self.store._threads.__setitem__(thread.id, thread)
|
||||
if hasattr(self.store, "_threads")
|
||||
else None
|
||||
)
|
||||
```
|
||||
|
||||
Update `core/__init__.py` to export `Agent, Thread, Message` from `types`.
|
||||
@@ -624,13 +809,16 @@ git commit -m "feat: thin App facade over ops/store"
|
||||
# tests/test_no_gng.py
|
||||
def test_gng_removed():
|
||||
import importlib
|
||||
|
||||
try:
|
||||
import agentmsgs.utils
|
||||
|
||||
assert False, "utils should be deleted"
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
# importing agentmsgs shouldn't print
|
||||
import agentmsgs
|
||||
|
||||
assert hasattr(agentmsgs, "main") or True
|
||||
```
|
||||
|
||||
@@ -648,13 +836,19 @@ Expected: FAIL (utils still exists)
|
||||
from pathlib import Path
|
||||
from agentmsgs.core.app import App
|
||||
from agentmsgs.stores.sqlite import SQLiteStore
|
||||
|
||||
|
||||
def main():
|
||||
app = App(store=SQLiteStore(Path.home()/".agentmsgs.db"))
|
||||
alice = app.get_or_create_agent("Alice"); bob = app.get_or_create_agent("Bob")
|
||||
t = app.create_thread(alice,bob)
|
||||
app = App(store=SQLiteStore(Path.home() / ".agentmsgs.db"))
|
||||
alice = app.get_or_create_agent("Alice")
|
||||
bob = app.get_or_create_agent("Bob")
|
||||
t = app.create_thread(alice, bob)
|
||||
app.append(t.id, alice, "Hello")
|
||||
print(app.poll(t.id, bob))
|
||||
if __name__=="__main__": main()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
- Keep `src/agentmsgs/__init__.py` minimal: `from .core.app import App; from .core.types import Agent, Thread, Message`
|
||||
- Remove `tests/gng/` dir
|
||||
|
||||
Reference in new issue
Block a user