fleet-memory/schema.sql
2025-10-30 12:53:12 +01:00

99 lines
4.9 KiB
SQL

-- Enable the pgvector extension and uuid extension
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- ============================================================================
-- TEMPORAL + SEMANTIC + ENTITY MEMORY ARCHITECTURE
-- ============================================================================
-- Memory Units: Individual sentence-level memories
CREATE TABLE IF NOT EXISTS memory_units (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
agent_id TEXT NOT NULL,
text TEXT NOT NULL,
embedding vector(384), -- bge-small-en-v1.5 dimension
context TEXT, -- What was happening when this memory was formed
event_date TIMESTAMPTZ NOT NULL, -- When the event occurred
access_count INTEGER DEFAULT 0, -- For recency/frequency weighting
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Entities: Resolved entities (people, organizations, locations, etc.)
CREATE TABLE IF NOT EXISTS entities (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
canonical_name TEXT NOT NULL, -- "Alice", "Google", "San Francisco"
entity_type TEXT NOT NULL, -- PERSON, ORG, GPE, etc.
agent_id TEXT NOT NULL, -- Entities are scoped to agents
metadata JSONB DEFAULT '{}'::jsonb, -- Additional entity info
first_seen TIMESTAMPTZ DEFAULT NOW(),
last_seen TIMESTAMPTZ DEFAULT NOW(),
mention_count INTEGER DEFAULT 1
);
-- Unit-Entity associations: Which entities appear in which units
CREATE TABLE IF NOT EXISTS unit_entities (
unit_id UUID REFERENCES memory_units(id) ON DELETE CASCADE,
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE,
PRIMARY KEY (unit_id, entity_id)
);
-- Entity Co-occurrences: Materialized cache of which entities appear together
-- This dramatically speeds up entity resolution by avoiding expensive joins
CREATE TABLE IF NOT EXISTS entity_cooccurrences (
entity_id_1 UUID REFERENCES entities(id) ON DELETE CASCADE,
entity_id_2 UUID REFERENCES entities(id) ON DELETE CASCADE,
cooccurrence_count INTEGER DEFAULT 1,
last_cooccurred TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (entity_id_1, entity_id_2),
CHECK (entity_id_1 < entity_id_2) -- Enforce ordering to avoid duplicates
);
-- Memory Links: Temporal, semantic, AND entity connections
CREATE TABLE IF NOT EXISTS memory_links (
from_unit_id UUID REFERENCES memory_units(id) ON DELETE CASCADE,
to_unit_id UUID REFERENCES memory_units(id) ON DELETE CASCADE,
link_type TEXT NOT NULL, -- 'temporal', 'semantic', or 'entity'
weight FLOAT NOT NULL DEFAULT 1.0, -- Link strength
entity_id UUID REFERENCES entities(id) ON DELETE CASCADE, -- Set for entity links
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Unique constraint to prevent duplicate links
CREATE UNIQUE INDEX IF NOT EXISTS idx_memory_links_unique
ON memory_links (from_unit_id, to_unit_id, link_type, COALESCE(entity_id, '00000000-0000-0000-0000-000000000000'::uuid));
-- ============================================================================
-- INDEXES
-- ============================================================================
-- Memory unit indexes
CREATE INDEX IF NOT EXISTS idx_memory_units_agent_id ON memory_units(agent_id);
CREATE INDEX IF NOT EXISTS idx_memory_units_event_date ON memory_units(event_date DESC);
CREATE INDEX IF NOT EXISTS idx_memory_units_agent_date ON memory_units(agent_id, event_date DESC);
CREATE INDEX IF NOT EXISTS idx_memory_units_access_count ON memory_units(access_count DESC);
-- Vector similarity index (HNSW for fast approximate nearest neighbor)
CREATE INDEX IF NOT EXISTS idx_memory_units_embedding ON memory_units
USING hnsw (embedding vector_cosine_ops);
-- Entity indexes
CREATE INDEX IF NOT EXISTS idx_entities_agent_id ON entities(agent_id);
CREATE INDEX IF NOT EXISTS idx_entities_canonical_name ON entities(canonical_name);
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(entity_type);
CREATE INDEX IF NOT EXISTS idx_entities_agent_name_type ON entities(agent_id, canonical_name, entity_type);
-- Unit-entity indexes
CREATE INDEX IF NOT EXISTS idx_unit_entities_unit ON unit_entities(unit_id);
CREATE INDEX IF NOT EXISTS idx_unit_entities_entity ON unit_entities(entity_id);
-- Entity co-occurrence indexes for fast lookups
CREATE INDEX IF NOT EXISTS idx_entity_cooccurrences_entity1 ON entity_cooccurrences(entity_id_1);
CREATE INDEX IF NOT EXISTS idx_entity_cooccurrences_entity2 ON entity_cooccurrences(entity_id_2);
CREATE INDEX IF NOT EXISTS idx_entity_cooccurrences_count ON entity_cooccurrences(cooccurrence_count DESC);
-- Link indexes for graph traversal
CREATE INDEX IF NOT EXISTS idx_memory_links_from ON memory_links(from_unit_id);
CREATE INDEX IF NOT EXISTS idx_memory_links_to ON memory_links(to_unit_id);
CREATE INDEX IF NOT EXISTS idx_memory_links_type ON memory_links(link_type);
CREATE INDEX IF NOT EXISTS idx_memory_links_entity ON memory_links(entity_id) WHERE entity_id IS NOT NULL;