feat: bot and you entity schemas with projector handlers
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE bots (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
persona TEXT NOT NULL,
|
||||
voice_samples_json TEXT NOT NULL DEFAULT '[]',
|
||||
traits_json TEXT NOT NULL DEFAULT '[]',
|
||||
backstory TEXT NOT NULL DEFAULT '',
|
||||
initial_relationship_to_you TEXT NOT NULL DEFAULT '',
|
||||
kickoff_prose TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE you_entity (
|
||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||
name TEXT NOT NULL,
|
||||
pronouns TEXT NOT NULL DEFAULT '',
|
||||
persona TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
import json
|
||||
from sqlite3 import Connection
|
||||
from chat.eventlog.projector import on
|
||||
from chat.eventlog.log import Event
|
||||
|
||||
|
||||
@on("bot_authored")
|
||||
def _apply_bot_authored(conn: Connection, e: Event) -> None:
|
||||
p = e.payload
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO bots "
|
||||
"(id, name, persona, voice_samples_json, traits_json, backstory, "
|
||||
" initial_relationship_to_you, kickoff_prose) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(p["id"], p["name"], p["persona"],
|
||||
json.dumps(p.get("voice_samples", [])),
|
||||
json.dumps(p.get("traits", [])),
|
||||
p.get("backstory", ""),
|
||||
p.get("initial_relationship_to_you", ""),
|
||||
p.get("kickoff_prose", "")),
|
||||
)
|
||||
|
||||
|
||||
@on("you_authored")
|
||||
def _apply_you_authored(conn: Connection, e: Event) -> None:
|
||||
p = e.payload
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO you_entity (id, name, pronouns, persona) VALUES (1, ?, ?, ?)",
|
||||
(p["name"], p.get("pronouns", ""), p.get("persona", "")),
|
||||
)
|
||||
|
||||
|
||||
def get_bot(conn: Connection, bot_id: str) -> dict | None:
|
||||
row = conn.execute("SELECT * FROM bots WHERE id = ?", (bot_id,)).fetchone()
|
||||
if not row:
|
||||
return None
|
||||
cols = [c[1] for c in conn.execute("PRAGMA table_info(bots)").fetchall()]
|
||||
d = dict(zip(cols, row))
|
||||
d["voice_samples"] = json.loads(d.pop("voice_samples_json"))
|
||||
d["traits"] = json.loads(d.pop("traits_json"))
|
||||
return d
|
||||
|
||||
|
||||
def list_bots(conn: Connection) -> list[dict]:
|
||||
cur = conn.execute("SELECT id, name FROM bots ORDER BY name")
|
||||
return [{"id": r[0], "name": r[1]} for r in cur]
|
||||
|
||||
|
||||
def get_you(conn: Connection) -> dict | None:
|
||||
row = conn.execute("SELECT name, pronouns, persona FROM you_entity WHERE id = 1").fetchone()
|
||||
if not row:
|
||||
return None
|
||||
return {"name": row[0], "pronouns": row[1], "persona": row[2]}
|
||||
@@ -0,0 +1,38 @@
|
||||
from chat.db.migrate import apply_migrations
|
||||
from chat.db.connection import open_db
|
||||
from chat.eventlog.log import append_event
|
||||
from chat.eventlog.projector import project
|
||||
from chat.state.entities import get_bot, list_bots, get_you
|
||||
import chat.state.entities # registers handlers
|
||||
|
||||
|
||||
def test_bot_authored_creates_bot_row(tmp_path):
|
||||
db = tmp_path / "t.db"
|
||||
apply_migrations(db)
|
||||
with open_db(db) as conn:
|
||||
append_event(conn, kind="bot_authored", payload={
|
||||
"id": "bot_a", "name": "BotA",
|
||||
"persona": "...", "voice_samples": ["sample"], "traits": ["shy"],
|
||||
"backstory": "...",
|
||||
"initial_relationship_to_you": "coworker",
|
||||
"kickoff_prose": "you stay late",
|
||||
})
|
||||
project(conn)
|
||||
bot = get_bot(conn, "bot_a")
|
||||
assert bot is not None
|
||||
assert bot["name"] == "BotA"
|
||||
assert bot["traits"] == ["shy"]
|
||||
assert "bot_a" in [b["id"] for b in list_bots(conn)]
|
||||
|
||||
|
||||
def test_you_authored_creates_you_singleton(tmp_path):
|
||||
db = tmp_path / "t.db"
|
||||
apply_migrations(db)
|
||||
with open_db(db) as conn:
|
||||
append_event(conn, kind="you_authored", payload={
|
||||
"name": "Me", "pronouns": "they/them", "persona": "engineer",
|
||||
})
|
||||
project(conn)
|
||||
you = get_you(conn)
|
||||
assert you is not None
|
||||
assert you["name"] == "Me"
|
||||
Reference in New Issue
Block a user