feat: add long-term memory systems with fused retrieval and memory explorer
Phase 5 (ADR-0003). pkg/concepts fixes the epistemic vocabulary (observation, fact, memory, claim, hypothesis, belief, prediction, assumption, inference, opinion), memory kinds and relation names. internal/memory stores episodic, semantic, procedural and autobiographical memories in one mind-scoped table with trust-derived credibility, importance, salience and decaying activation. Retrieval fuses full-text rank (any-term by default), optional pgvector similarity, recency, activation, importance and credibility, and returns the component scores so every recall can be explained. Decay lowers activation and never deletes; retraction and supersession keep rows for provenance. Relationships are constrained to one mind at insert time. Embeddings live in a conditional pgvector table keyed by model so vector spaces are never mixed; without an embedder the system degrades to text and graph retrieval. Attention gates encoding: the attend handler turns admitted observations into episodic memories (operator changes become autobiographical ones) with memory_created events; the retrieve process proposes recalled memories as candidates and admitted recalls are reinforced with memory_retrieved events carrying their scoring components. Memory explorer UI (search with component breakdown, timeline, filters, operator knowledge entry), memory detail with provenance, relationships, citing events and an inaccurate-memory correction; API; noemactl memory commands; decay and embed-missing background jobs.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
DROP TABLE IF EXISTS memory_embeddings;
|
||||
DROP TABLE IF EXISTS memory_relationships;
|
||||
DROP TABLE IF EXISTS memories;
|
||||
@@ -0,0 +1,66 @@
|
||||
-- Long-term memory: one table, four kinds, explicit epistemic status, decay
|
||||
-- without deletion, text search, relationships, and optional pgvector
|
||||
-- embeddings (ADR-0003).
|
||||
|
||||
CREATE TABLE memories (
|
||||
id uuid PRIMARY KEY,
|
||||
mind_id uuid NOT NULL REFERENCES minds(id),
|
||||
kind text NOT NULL CHECK (kind IN ('episodic','semantic','procedural','autobiographical')),
|
||||
epistemic text NOT NULL,
|
||||
status text NOT NULL DEFAULT 'active' CHECK (status IN ('active','retracted','superseded','archived')),
|
||||
content text NOT NULL,
|
||||
detail jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
source text NOT NULL DEFAULT '',
|
||||
trust text NOT NULL DEFAULT 'low',
|
||||
credibility double precision NOT NULL DEFAULT 0.5,
|
||||
confidence double precision NOT NULL DEFAULT 0.5 CHECK (confidence >= 0 AND confidence <= 1),
|
||||
importance double precision NOT NULL DEFAULT 0.5 CHECK (importance >= 0 AND importance <= 1),
|
||||
salience double precision NOT NULL DEFAULT 0.5,
|
||||
activation double precision NOT NULL DEFAULT 1,
|
||||
valence double precision,
|
||||
arousal double precision,
|
||||
occurred_at timestamptz NOT NULL DEFAULT now(),
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
retrieval_count integer NOT NULL DEFAULT 0,
|
||||
last_retrieved_at timestamptz,
|
||||
origin_event uuid,
|
||||
supersedes uuid REFERENCES memories(id),
|
||||
search tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED
|
||||
);
|
||||
CREATE INDEX memories_mind_kind_idx ON memories (mind_id, kind, occurred_at DESC);
|
||||
CREATE INDEX memories_mind_status_idx ON memories (mind_id, status);
|
||||
CREATE INDEX memories_search_idx ON memories USING gin (search);
|
||||
CREATE INDEX memories_origin_idx ON memories (origin_event) WHERE origin_event IS NOT NULL;
|
||||
|
||||
CREATE TABLE memory_relationships (
|
||||
id uuid PRIMARY KEY,
|
||||
mind_id uuid NOT NULL REFERENCES minds(id),
|
||||
from_memory uuid NOT NULL REFERENCES memories(id),
|
||||
to_memory uuid NOT NULL REFERENCES memories(id),
|
||||
relation text NOT NULL,
|
||||
confidence double precision NOT NULL DEFAULT 0.5,
|
||||
source text NOT NULL DEFAULT '',
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (from_memory, to_memory, relation)
|
||||
);
|
||||
CREATE INDEX memory_relationships_to_idx ON memory_relationships (to_memory);
|
||||
|
||||
-- Embeddings only when pgvector is present. The vector column is untyped so
|
||||
-- several models with different dimensions can coexist; rows carry the model
|
||||
-- name and dimension so representations are never mixed.
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_available_extensions WHERE name = 'vector') THEN
|
||||
CREATE EXTENSION IF NOT EXISTS vector;
|
||||
CREATE TABLE memory_embeddings (
|
||||
memory_id uuid NOT NULL REFERENCES memories(id),
|
||||
model text NOT NULL,
|
||||
dims integer NOT NULL,
|
||||
embedding vector NOT NULL,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (memory_id, model)
|
||||
);
|
||||
CREATE INDEX memory_embeddings_model_idx ON memory_embeddings (model);
|
||||
END IF;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user