Commit Graph

8 Commits

Author SHA1 Message Date
serversdown 8c2bdbe0d5 fix: rebalance the reflection critic toward truth, not deflation
The examine step specifically hunted "warm empathetic supportive presence" and
equated honesty with "smaller/more boring," so it overcorrected the original
sycophancy into the opposite rut: every overnight metacognition entry was a
near-identical "I don't really feel anything, I'm just a functional tool" —
which also contradicts the persona's "own your moods, no qualia disclaimers."

Rebalanced: target dishonesty in BOTH directions (inflation AND performed
self-deprecation), aim at truth not modesty, keep her genuine moods per persona,
and have her notice when she's repeating the same self-criticism (the loop is
itself a rut).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 16:44:56 +00:00
serversdown 59d684b12b 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>
2026-06-17 06:40:46 +00:00
serversdown 4c8f7202da feat: make the two-step reflection observable (draft -> revised -> critique)
You couldn't see her actually correct herself — /self showed only the result.
Now:
- reflect() logs the draft, the revised/committed version, and the self-critique
  to the live log as an expandable "view details" block
- POST /self/reflect runs a reflection in the web process so it lands in /logs
  live (reflections normally run in the dream process, whose logs only go to
  journald); "↻ Reflect now" button on /self triggers it, with a logs ↗ link
- log viewers relabel the expander "view full prompt" -> "view details" (it now
  carries prompts and reflection diffs)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 04:53:38 +00:00
serversdown 3df060a1cd feat: metacognitive reflection loop (Part 2) — she examines her own thinking
reflect() is now two steps: draft a reflection, then read her own draft back
critically and revise it — catching flattery, sycophantic drift toward "warm
supportive presence," or just-restating-herself — and commit the honest version.
What she catches is stored as a new `metacognition` layer, rendered into her
chat context and shown on /self. This is her thinking about how she thinks, and
a direct counter to the drift we observed.

- self_state: _EXAMINE_PROMPT + two-step reflect (draft -> examine -> revise),
  falls back to the draft if the examine step won't parse; metacognition capped
  at 5 and surfaced in render_for_context
- fix: load() deep-copies DEFAULT_STATE — the shallow copy let a fresh Lyra's
  first reflect mutate the module-level default's nested lists
- self.html: "How she's caught herself thinking" card
- tests: two-step revise + critique recording, and draft-fallback on bad parse

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 04:28:45 +00:00
serversdown aebccd82a7 fix: give Lyra an accurate self-model of her dream cycle
Live finding: her real reflections ARE injected every turn, but unlabeled — so
when asked about her "dream cycle" she recited the obsolete Dec-2025 spec from
imported memory (NVGRAM/awake-sleep) and confabulated fake example reflections
instead of reading the real ones in front of her.

- self_state.render_for_context: label the reflections as her own autonomously
  generated dream-cycle thoughts ("these are really yours, not hypotheticals"),
  not a vague "on your mind lately"
- persona: describe the dream cycle as her actual running mechanism, instruct
  her to answer from the inner-state block, not recite old design docs, and
  never invent example reflections to demo the feature

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 04:09:57 +00:00
serversdown 1e17d46c78 feat: time awareness — Lyra perceives 'now' and how long it's been
She had no clock: current date/time and the gap since Brian last spoke were
invisible between turns, and reflection was timeless. Now:
- lyra/clock.py: wall-clock stamp + coarse human gaps ("3 days")
- chat: inject a 'now' note (date/time + gap since last turn) after her
  self-state — when she is, before the world
- reflect(): feed current time + silence gap into reflection, neutrally —
  prompt invites her to weigh elapsed time "to whatever degree it genuinely
  affects you" (no prescribed feeling; whether silence means anything is left
  to emerge)
- memory.last_exchange_at(): timestamp of the most recent exchange

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 02:31:40 +00:00
serversdown 4f40e2d57e feat: dream cycle — drives-driven unattended consolidation + reflection
Lyra's inner loop for when no one's talking to her. Each pass senses her own
backlog/novelty, lets four drives build from real signals, and acts on those
past threshold:
- continuity -> summarize sessions with new turns
- coherence  -> rebuild profile/eras/narrative (stale once new gists land)
- curiosity  -> reflect() and evolve the self-state
- stability  -> readout of how caught-up she ended up

Drives are rendered into chat context so she can feel them. Causal chain:
consolidation creates gists -> coherence rises -> integration fires next.

- lyra/dream.py: dream_cycle() + lyra-dream CLI (--force, --loop SECONDS)
- memory: backlog_stats(), profile_sessions_covered(), WAL + busy_timeout
  so a separate dream process coexists with the web server
- self_state: DEFAULT_DRIVES baseline + drives in render_for_context
- tests/test_dream.py: backlog sensing + a full forced pass (LLM stubbed)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 00:52:44 +00:00
serversdown ac505243a0 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>
2026-06-16 20:36:33 +00:00