3.5 KiB
SPEC-002 — Structured memory
Replaces the single-string per-answer LLM rewrite (lossy, O(convo)
cost — the old memoize path). Layers, simplified per plan v4:
user facts (durable, provenance-tracked), pinned facts
(operator-set, global or per channel), episodes (rolling channel
summaries with decay). Channel-facts deferred until recall proves
insufficient. Raw feed = observations (messages, reactions,
edits, deletes); an async consolidation pass turns observations into
facts + episodes. The memory system is active only when both a store
(history-directory) and a memory-model are configured — otherwise
the legacy memory string is used read-only (MEM-10).
MEM-01 — Events become observation rows (coverage: test)
User messages, bot answers, reactions (add/remove/clear), edits and deletes are recorded as observation rows (channel, user, kind, content excerpt) — cheap writes, no LLM call per event.
MEM-02 — Consolidation is batched, never per message (coverage: test)
Consolidation triggers when memory-consolidate-every (default 20)
unconsumed observations have accumulated for a channel; it runs as a
background task guarded by a lock (no overlapping runs), consumes the
observations it processed, and leaves them in place when the model
call fails (retry next trigger).
MEM-03 — Only self-authored facts persist (coverage: test)
The consolidator stores a fact only when its subject user is among
the authors of the consumed observations, with provenance
source='self'; facts the model attributes to absent third parties
are discarded and logged. Operator pins carry source='operator'.
"Bob says Alice likes X" must never become Alice's profile
(review consensus C2).
MEM-04 — Recall is participant-scoped (coverage: test)
The memory block assembled into the system prompt contains: pinned facts (global + this channel), user facts of conversation participants only (current author + authors in the recent history tail), and the channel's recent episodes. Facts of non-participants never enter the prompt — the model cannot leak what it cannot see.
MEM-05 — Episodes decay (coverage: test)
At most memory-episodes-per-channel (default 10) episodes are kept
per channel; consolidation drops the oldest beyond the cap.
MEM-06 — User facts have a retention limit (coverage: test)
Facts not updated within memory-fact-retention-days (default 180)
are purged during consolidation. Durable is not indefinite (GDPR
storage limitation).
MEM-07 — Staff review and edit memory (coverage: test)
Staff commands: !bot memory <user> lists the user's facts with ids;
!bot forget-fact <id> deletes one; !bot pin <channel|global> <fact> adds an operator pin; !bot unpin <id> removes one.
MEM-08 — Legacy memory strings migrate to episodes (coverage: test)
Schema v3 migration copies existing per-channel memory strings into an episode row each; pickle migration does the same. Deployments keep their accumulated context through the upgrade.
MEM-09 — !forgetme erases facts, observations and episode traces (coverage: test)
!forgetme now deletes the user's facts, their observation rows, and
episodes mentioning the user's name — in addition to the SAF-08
history purge. This completes the erasure that SAF-08 v1 could not.
MEM-10 — Memory system off degrades gracefully (coverage: test)
Without memory-model (or without a store) no observations are
written, no consolidation runs, and {memory} falls back to the
legacy memory string — no crash, no behavior change for
unconfigured deployments.