merge: T37 guest_added/guest_removed event handlers

This commit is contained in:
Joseph Doherty
2026-04-26 15:49:03 -04:00
2 changed files with 114 additions and 0 deletions
+18
View File
@@ -29,6 +29,24 @@ def _apply_chat_created(conn: Connection, e: Event) -> None:
)
@on("guest_added")
def _apply_guest_added(conn: Connection, e: Event) -> None:
p = e.payload
conn.execute(
"UPDATE chats SET guest_bot_id = ? WHERE id = ?",
(p["guest_bot_id"], p["chat_id"]),
)
@on("guest_removed")
def _apply_guest_removed(conn: Connection, e: Event) -> None:
p = e.payload
conn.execute(
"UPDATE chats SET guest_bot_id = NULL WHERE id = ?",
(p["chat_id"],),
)
@on("container_created")
def _apply_container_created(conn: Connection, e: Event) -> None:
p = e.payload
+96
View File
@@ -0,0 +1,96 @@
from __future__ import annotations
from chat.db.connection import open_db
from chat.db.migrate import apply_migrations
from chat.eventlog.log import append_event
from chat.eventlog.projector import project
import chat.state.entities # registers bot_authored handler
import chat.state.world # registers chat_created / guest_added / guest_removed
from chat.state.world import get_chat
def _bot_payload(bot_id: str, name: str) -> dict:
return {
"id": bot_id,
"name": name,
"persona": "...",
"voice_samples": ["sample"],
"traits": ["shy"],
"backstory": "...",
"initial_relationship_to_you": "coworker",
"kickoff_prose": "you stay late",
}
def _chat_payload(**overrides) -> dict:
payload = {
"id": "chat_bot_a",
"host_bot_id": "bot_a",
"initial_time": "2026-04-26T20:00:00+00:00",
"narrative_anchor": "Day 1 evening",
"weather": "clear",
}
payload.update(overrides)
return payload
def test_guest_added_sets_guest_bot_id(tmp_path):
db = tmp_path / "t.db"
apply_migrations(db)
with open_db(db) as conn:
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA"))
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB"))
append_event(conn, kind="chat_created", payload=_chat_payload())
append_event(conn, kind="guest_added", payload={
"chat_id": "chat_bot_a",
"guest_bot_id": "bot_b",
})
project(conn)
chat = get_chat(conn, "chat_bot_a")
assert chat is not None
assert chat["guest_bot_id"] == "bot_b"
def test_guest_removed_clears_guest_bot_id(tmp_path):
db = tmp_path / "t.db"
apply_migrations(db)
with open_db(db) as conn:
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA"))
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB"))
append_event(conn, kind="chat_created", payload=_chat_payload())
append_event(conn, kind="guest_added", payload={
"chat_id": "chat_bot_a",
"guest_bot_id": "bot_b",
})
append_event(conn, kind="guest_removed", payload={
"chat_id": "chat_bot_a",
})
project(conn)
chat = get_chat(conn, "chat_bot_a")
assert chat is not None
assert chat["guest_bot_id"] is None
def test_guest_added_idempotent_overwrite(tmp_path):
db = tmp_path / "t.db"
apply_migrations(db)
with open_db(db) as conn:
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_a", "BotA"))
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_b", "BotB"))
append_event(conn, kind="bot_authored", payload=_bot_payload("bot_c", "BotC"))
append_event(conn, kind="chat_created", payload=_chat_payload())
append_event(conn, kind="guest_added", payload={
"chat_id": "chat_bot_a",
"guest_bot_id": "bot_b",
})
append_event(conn, kind="guest_added", payload={
"chat_id": "chat_bot_a",
"guest_bot_id": "bot_c",
})
project(conn)
chat = get_chat(conn, "chat_bot_a")
assert chat is not None
assert chat["guest_bot_id"] == "bot_c"