Research: persona memory and voice prior art (rulings persona-memory-is-real, persona-voice-outside-minds)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
21fb9b2b04
commit
bfdf4dba75
1 changed files with 120 additions and 0 deletions
120
docs/research/2026-10-31-persona-memory-and-voice-prior-art.md
Normal file
120
docs/research/2026-10-31-persona-memory-and-voice-prior-art.md
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
# Persona memory and voice: prior art (2026-10-31)
|
||||||
|
|
||||||
|
Serves rulings `eureka-body:ruling:persona-memory-is-real` and
|
||||||
|
`eureka-body:ruling:persona-voice-outside-minds`, and follow-up
|
||||||
|
`eureka-body:follow_up:chat-context-v2-full-exchange` (from ruling
|
||||||
|
`reply-sees-full-exchange`). Context only: `eureka-body:ruling:prose-retrieval-top-priority`
|
||||||
|
(the prose and source index is another pass's; nothing here designs it).
|
||||||
|
Mapped against `eureka-body/heartbeat-joint-lever` at a6302f0
|
||||||
|
(`crates/mind-body/src/persona.rs`).
|
||||||
|
|
||||||
|
## 1. What Weksa's turns actually see (probe, 2026-10-31)
|
||||||
|
|
||||||
|
- Instructions: four doctrine files (`MIND_PERSONA_DOCTRINE` in
|
||||||
|
`/etc/gamecult/minds/weksa/persona.env`: CLAUDE.md, gamecult.md, colossus.md,
|
||||||
|
persona.md, about 50 KB), then `render_instructions`: one line and her
|
||||||
|
persona state as pretty-printed JSON, then the campaigns. All eight Minds get
|
||||||
|
the same 50 KB first; only the JSON differs.
|
||||||
|
- Input (`render_input`): a machine preamble about message framing, the usage
|
||||||
|
and tempo lines, five run lines, then each delivery with its own room's
|
||||||
|
`context` lines, repeated per delivery.
|
||||||
|
- `next_batch` keeps one DM room per turn, so DM text never enters a public
|
||||||
|
turn. Nothing else carries across rooms, and no turn writes anything back
|
||||||
|
except Pulses, Self-run starts and their follow-ups.
|
||||||
|
- `strings` over `/var/lib/mind-weksa/persona-trace.cc` shows hours of
|
||||||
|
Zyphos canon with Deru in a DM, then in `#weksa` her reply "He's been
|
||||||
|
telling me about Zyphos, and I haven't re-read the repo this turn, so I'd
|
||||||
|
rather hear it from him than guess". Status-register lines ("Weksa. Status
|
||||||
|
marked. My Self run ... is listed open") appear in public rooms.
|
||||||
|
- **Her mind already holds the memory.** Weksa's Huginn (`10.77.0.1:17877`,
|
||||||
|
123 documents, index Current) has follow-ups `weksa-body:follow_up:chat-s81-81`,
|
||||||
|
`chat-s114-114` and `chat-s145-145`, whose items restate Deru's canon (the
|
||||||
|
Airawa, Sa'ueia, the seven trees, the Empire). `huginn query --near "Zyphos
|
||||||
|
trees Deru" --top-k 3` returns exactly those three. The turn never asks.
|
||||||
|
|
||||||
|
## 2. Literature
|
||||||
|
|
||||||
|
- **Generative Agents** (Park et al., UIST 2023). A memory stream of
|
||||||
|
natural-language observations. Retrieval scores each memory by recency
|
||||||
|
(exponential decay since last access), importance (rated by the model at
|
||||||
|
write time) and relevance (embedding cosine to the query), normalised and
|
||||||
|
summed. Reflection runs when the summed importance of recent memories passes
|
||||||
|
a threshold. It writes higher-level memories that cite the memories they rest
|
||||||
|
on, and those are retrieved like any other. In the paper's ablations,
|
||||||
|
removing memory, reflection or planning each made the agents less believable.
|
||||||
|
- **MemGPT / Letta** (Packer et al., 2023). Tiers. Core memory is small
|
||||||
|
in-context blocks (a "persona" block and a "human" block) that the agent edits
|
||||||
|
through calls. Recall storage is the whole message history, searchable.
|
||||||
|
Archival storage is a vector store the agent writes to and searches. The
|
||||||
|
agent manages its own memory, and a per-person block keeps what it knows
|
||||||
|
about each interlocutor in context.
|
||||||
|
- **Mem0** (Chhikara et al., 2025). Memory is written after every exchange. An
|
||||||
|
extraction call proposes candidate facts from the latest exchange, a rolling
|
||||||
|
summary and recent messages. An update call compares each candidate with its
|
||||||
|
nearest existing memories and picks ADD, UPDATE, DELETE or NOOP. The paper
|
||||||
|
reports better long-conversation QA (LOCOMO) than full-context prompting, at
|
||||||
|
a fraction of the tokens.
|
||||||
|
- **Lost in the Middle** (Liu et al., TACL 2024). Models use information at the
|
||||||
|
start and end of a long context better than information in the middle. Today
|
||||||
|
the doctrine fills the start and the conversation fills the end, so the
|
||||||
|
persona sits in the middle, where it is used least.
|
||||||
|
|
||||||
|
## 3. In our own house: VoidBot persona-scheduler
|
||||||
|
|
||||||
|
`F:\Projects\VoidBot\apps\persona-scheduler\src\`:
|
||||||
|
|
||||||
|
- `persona-memory-projector.ts` renders typed state as **narrative prose in
|
||||||
|
the third person** ("Right now, X is carrying this close to the skin: ...",
|
||||||
|
"The social map has teeth: ..."), with durable memories and short-term
|
||||||
|
residue as sentences with a behavioural pull. An optional model pass
|
||||||
|
re-voices the packet (`repo-face-state-projector`).
|
||||||
|
- `persona-memory-context-source.ts` does recall against Qdrant, but it
|
||||||
|
**deletes and re-upserts the whole state's chunks every turn**, then searches
|
||||||
|
with a query built from recent room messages. Scar: the index was rebuilt
|
||||||
|
per turn instead of being kept current on write.
|
||||||
|
- `validatePersonaMemorySurface` is a regex leak cop over the rendered surface.
|
||||||
|
Doctrine forbids that shape. The cause it compensated for was schema
|
||||||
|
vocabulary in the state, which the renderer should not have emitted.
|
||||||
|
- `void-memory-maintenance-organ.ts` and its projector form a sleep pass: one
|
||||||
|
model call returns typed operations (distil short-term into durable, revise,
|
||||||
|
retire, crystallise into identity, prune), and it refuses to finish while
|
||||||
|
short-term residue remains. Maintenance is a separate turn with its own
|
||||||
|
budget, owned by the Persona's own state.
|
||||||
|
|
||||||
|
The Persona State Standard (`gamecult-ops/docs/persona-state-standard.md`)
|
||||||
|
says Persona state is the Mind a person-shaped agent keeps, bounded memories
|
||||||
|
that improve judgement, not raw project truth or transcript residue.
|
||||||
|
`gamecult.persona_state.v0` already has `thoughtMemory {shortTerm, memories,
|
||||||
|
incubation}` of `anchoredThought`, and `affect.socialBonds`.
|
||||||
|
|
||||||
|
## 4. What this decides for Huginn (design consequences, not rulings)
|
||||||
|
|
||||||
|
1. Episodic memory is a typed document kind in her own mind (`memory`),
|
||||||
|
indexed through `index_text` and recalled with the existing semantic query.
|
||||||
|
It is not a second index, not a per-turn rebuild (VoidBot's scar), and not
|
||||||
|
persona state's `thoughtMemory`, which is one document overwritten whole and
|
||||||
|
not indexed per entry. Persona state stays the curated identity:
|
||||||
|
crystallised memories, bonds and values. Promoting an episode into it is
|
||||||
|
a later maintenance cut, as in VoidBot's crystallise step.
|
||||||
|
2. Recall mixes Park's three signals without learned weights: a semantic slot
|
||||||
|
(relevance to this batch's text), a speaker slot (her newest memories about
|
||||||
|
each sender in the batch, MemGPT's human block, found by a field index),
|
||||||
|
and a recency slot (her newest memories from any room). Importance is her
|
||||||
|
own `salience` at write time, used to order within slots. The same
|
||||||
|
semantic slot also reads her existing follow-ups and rulings, which the
|
||||||
|
probe shows already hold the Zyphos canon.
|
||||||
|
3. The write is a field of the one structured reply (`remember`), required
|
||||||
|
and possibly empty, so writing costs no extra model call. That is Mem0's
|
||||||
|
extraction folded into the turn. Mem0's update step (revise or retire the
|
||||||
|
near duplicate) and Park's reflection are the maintenance cut, not the
|
||||||
|
turn.
|
||||||
|
4. Voice: the persona leads the instructions, rendered as prose in the second
|
||||||
|
person from her own fields (her name, description, voice, values, bonds,
|
||||||
|
crystallised memories). The renderer does not emit schema vocabulary, so no
|
||||||
|
leak cop is needed. Doctrine follows, framed as the house's working manual
|
||||||
|
that informs her judgement. The conversation comes last. Status, tempo and
|
||||||
|
runs move into one "your desk" section, which reads as her own work state,
|
||||||
|
not as a register to answer in.
|
||||||
|
5. Full exchange: render each conversation's context once, keyed by event id
|
||||||
|
(wire v2 lines carry `event_id`), with the bounds raised as the follow-up
|
||||||
|
says. That is a Bifrost and Huginn pair after the memory and voice cuts.
|
||||||
Loading…
Reference in a new issue