feat: Lyra's journal — permanent thought record + a knowing journal note
Her reflections/metacognition were capped rolling windows (6/5), so older thoughts were lost for good. Now everything she produces is also appended to a permanent, append-only journal; the capped lists stay as her working-memory window for context. - memory: journal table + add_journal_entry/list_journal - reflect(): persists every committed reflection + critique to the journal, and the examine step gains a "journal" field — a deliberate, first-person note she writes for herself (her knowing journaling), tagged by source (dream/manual) - web: /journal diary view (kind filters, grouped by day) + /journal/data; linked from /self - tests assert reflections + metacognition land in the journal Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,6 +79,19 @@ CREATE TABLE IF NOT EXISTS self_state (
|
||||
data TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Lyra's journal: append-only, permanent record of her thoughts. The self_state
|
||||
-- reflections/metacognition lists are a short rolling window for context; this
|
||||
-- keeps everything so nothing is lost when those roll over. kind is
|
||||
-- 'reflection' | 'metacognition' | 'journal' (a deliberate note to herself).
|
||||
CREATE TABLE IF NOT EXISTS journal (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_at TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
source TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_journal_created ON journal(created_at);
|
||||
"""
|
||||
|
||||
_conn: sqlite3.Connection | None = None
|
||||
@@ -517,6 +530,33 @@ def get_self_state(state_id: str = "lyra") -> dict | None:
|
||||
return json.loads(r["data"]) if r else None
|
||||
|
||||
|
||||
def add_journal_entry(kind: str, content: str, source: str | None = None) -> int:
|
||||
"""Append a permanent journal entry (never truncated). Returns row id."""
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
conn = _connection()
|
||||
with conn:
|
||||
cur = conn.execute(
|
||||
"INSERT INTO journal (created_at, kind, content, source) VALUES (?, ?, ?, ?)",
|
||||
(now, kind, content, source),
|
||||
)
|
||||
return int(cur.lastrowid)
|
||||
|
||||
|
||||
def list_journal(limit: int | None = None, kinds: tuple[str, ...] | None = None) -> list[dict]:
|
||||
"""Journal entries, newest first. Optionally filter by kind."""
|
||||
conn = _connection()
|
||||
sql = "SELECT id, created_at, kind, content, source FROM journal"
|
||||
params: list = []
|
||||
if kinds:
|
||||
sql += " WHERE kind IN (%s)" % ",".join("?" * len(kinds))
|
||||
params += list(kinds)
|
||||
sql += " ORDER BY id DESC"
|
||||
if limit is not None:
|
||||
sql += " LIMIT ?"
|
||||
params.append(limit)
|
||||
return [dict(r) for r in conn.execute(sql, params).fetchall()]
|
||||
|
||||
|
||||
def self_state_updated_at(state_id: str = "lyra") -> str | None:
|
||||
"""ISO timestamp her self-state was last written (None if never)."""
|
||||
conn = _connection()
|
||||
|
||||
Reference in New Issue
Block a user