feat: Autonomy Core v1 — Lyra's evolving self-state

Give Lyra a model of *herself* (vs the profile/narrative which model Brian):

- persona: a real origin/identity — she's an AI and knows it (Bender/C-3PO
  style), with the Cortex/NeoMem lineage as her actual past, so "how were you
  made" stops falling through to generic-assistant deflection.
- memory: self_state table (JSON blob) + get/set_self_state.
- lyra/self_state.py: evolving first-person inner state (mood, valence, energy,
  confidence, curiosity, self_narrative, relationship, reflections). render_for_
  context injects it; reflect() updates it from recent activity. `lyra-reflect`.
- chat.build_messages injects her interiority right after the persona — she
  speaks from a continuous self, not a reset.

The state -> behavior -> reflection -> updated state loop is the substrate for
the emergence experiment. Verified: reflection shifted mood curious->reflective
and produced genuine first-person self-observations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-16 20:36:33 +00:00
parent bfb81428ab
commit ac505243a0
5 changed files with 187 additions and 1 deletions
+26
View File
@@ -7,6 +7,7 @@ thousands of rows; swap in a vector index when that stops being true.
"""
from __future__ import annotations
import json
import sqlite3
from dataclasses import dataclass
from datetime import datetime, timezone
@@ -70,6 +71,14 @@ CREATE TABLE IF NOT EXISTS narrative (
content TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- Autonomy Core: Lyra's evolving self-state (mood, energy, her own first-person
-- self-narrative, reflections). Stored as a JSON blob. Single row (id='lyra').
CREATE TABLE IF NOT EXISTS self_state (
id TEXT PRIMARY KEY,
data TEXT NOT NULL,
updated_at TEXT NOT NULL
);
"""
_conn: sqlite3.Connection | None = None
@@ -434,6 +443,23 @@ def get_narrative(narrative_id: str = "current") -> str | None:
return r["content"] if r else None
def get_self_state(state_id: str = "lyra") -> dict | None:
conn = _connection()
r = conn.execute("SELECT data FROM self_state WHERE id = ?", (state_id,)).fetchone()
return json.loads(r["data"]) if r else None
def set_self_state(state: dict, state_id: str = "lyra") -> None:
now = datetime.now(timezone.utc).isoformat()
conn = _connection()
with conn:
conn.execute(
"INSERT INTO self_state (id, data, updated_at) VALUES (?, ?, ?) "
"ON CONFLICT(id) DO UPDATE SET data=excluded.data, updated_at=excluded.updated_at",
(state_id, json.dumps(state), now),
)
def recall_eras(query: str, k: int = 2) -> list[Era]:
"""Top-k month digests most similar to `query` (time-based context)."""
[q_vec] = llm.embed([query])