Nomearod's picture
feat: add SQLite conversation sessions with session_id
9874438
"""SQLite-backed conversation persistence."""
from __future__ import annotations
import json
import sqlite3
from datetime import datetime, timezone
from pathlib import Path
class ConversationStore:
"""Store and retrieve conversation history keyed by session_id."""
def __init__(self, db_path: str = "data/conversations.db") -> None:
self.db_path = Path(db_path)
self.db_path.parent.mkdir(parents=True, exist_ok=True)
self._init_db()
def _init_db(self) -> None:
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS conversations (
session_id TEXT NOT NULL,
role TEXT NOT NULL,
content TEXT NOT NULL,
timestamp TEXT NOT NULL,
metadata TEXT DEFAULT '{}'
)
""")
conn.execute("""
CREATE INDEX IF NOT EXISTS idx_session
ON conversations(session_id)
""")
def append(
self,
session_id: str,
role: str,
content: str,
metadata: dict | None = None,
) -> None:
"""Add a message to a session."""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"INSERT INTO conversations VALUES (?, ?, ?, ?, ?)",
(
session_id,
role,
content,
datetime.now(timezone.utc).isoformat(),
json.dumps(metadata or {}),
),
)
def get_history(
self, session_id: str, max_turns: int = 10
) -> list[dict]:
"""Get recent conversation history for a session.
Returns up to max_turns * 2 messages (user + assistant pairs),
ordered chronologically.
"""
with sqlite3.connect(self.db_path) as conn:
rows = conn.execute(
"""SELECT role, content FROM conversations
WHERE session_id = ?
ORDER BY timestamp DESC LIMIT ?""",
(session_id, max_turns * 2),
).fetchall()
return [{"role": r, "content": c} for r, c in reversed(rows)]
def list_sessions(self) -> list[str]:
"""List all session IDs."""
with sqlite3.connect(self.db_path) as conn:
rows = conn.execute(
"SELECT DISTINCT session_id FROM conversations"
).fetchall()
return [r[0] for r in rows]
def delete_session(self, session_id: str) -> None:
"""Delete all messages for a session."""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
"DELETE FROM conversations WHERE session_id = ?",
(session_id,),
)