feat: session modes (Talk/Cash) + live session HUD
Lyra now switches register based on what she's doing at the table instead of
being a wishy-washy companion mid-session.
Modes (lyra/modes.py):
- Talk (default companion) + Cash (live cash copilot); a mode = prompt card +
tool allow-list. Tool gating via tools.specs(allow=).
- Two-register Cash voice: act-first one-line logging when fed facts; full warm
companion voice for strategy / tilt / mental game.
- mode persisted per chat session (new sessions.mode column); auto-switch into
Cash when start_session fires; UI forces cloud backend in Cash (tools only
fire there).
Stack tracking + HUD:
- log_stack tool + poker_stack_log table; live net while sitting (stack - buy-in).
- poker.hud() bundle; /session HUD page (stack sparkline, hands, villains, notes,
stats) polling /session/data every 5s; Talk/Cash switcher + Session nav.
Endpoints: /session, /session/data, GET/POST /sessions/{id}/mode, /modes.
tests/test_modes.py (gating, mode roundtrip, stack/HUD); 36 tests green. v0.3.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ CREATE INDEX IF NOT EXISTS idx_session_created ON exchanges(session_id, created_
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT,
|
||||
mode TEXT, -- conversation mode (see lyra/modes.py); NULL = default
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
@@ -131,6 +132,12 @@ def _connection() -> sqlite3.Connection:
|
||||
_conn.execute("PRAGMA busy_timeout=5000")
|
||||
_conn.execute("PRAGMA journal_mode=WAL")
|
||||
_conn.executescript(SCHEMA)
|
||||
# Migrations for DBs created before a column existed (no-op if present).
|
||||
for ddl in ("ALTER TABLE sessions ADD COLUMN mode TEXT",):
|
||||
try:
|
||||
_conn.execute(ddl)
|
||||
except sqlite3.OperationalError:
|
||||
pass
|
||||
_conn_path = cfg.db_path
|
||||
return _conn
|
||||
|
||||
@@ -236,6 +243,21 @@ def ensure_session(session_id: str, name: str | None = None) -> None:
|
||||
conn.execute("UPDATE sessions SET name = ? WHERE id = ?", (name, session_id))
|
||||
|
||||
|
||||
def get_session_mode(session_id: str) -> str | None:
|
||||
"""The session's conversation mode key, or None if unset (caller applies default)."""
|
||||
conn = _connection()
|
||||
r = conn.execute("SELECT mode FROM sessions WHERE id = ?", (session_id,)).fetchone()
|
||||
return r["mode"] if r and r["mode"] else None
|
||||
|
||||
|
||||
def set_session_mode(session_id: str, mode: str) -> None:
|
||||
"""Persist the session's conversation mode (creating the session row if needed)."""
|
||||
ensure_session(session_id)
|
||||
conn = _connection()
|
||||
with conn:
|
||||
conn.execute("UPDATE sessions SET mode = ? WHERE id = ?", (mode, session_id))
|
||||
|
||||
|
||||
def list_sessions() -> list[dict]:
|
||||
"""All known sessions (named rows + any session that has exchanges), newest first."""
|
||||
conn = _connection()
|
||||
|
||||
Reference in New Issue
Block a user