-- Second brain: Telegram graph + pgvector (768 = nomic-embed-text) CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE IF NOT EXISTS telegram_conversations ( id SERIAL PRIMARY KEY, chat_id BIGINT NOT NULL UNIQUE, chat_type VARCHAR(32) DEFAULT 'private', user_name TEXT, user_role VARCHAR(32), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS telegram_messages ( id SERIAL PRIMARY KEY, conversation_id INT NOT NULL REFERENCES telegram_conversations(id) ON DELETE CASCADE, telegram_message_id BIGINT, direction VARCHAR(8) NOT NULL CHECK (direction IN ('in', 'out')), role VARCHAR(16) NOT NULL DEFAULT 'user', content_type VARCHAR(32) DEFAULT 'text', content_text TEXT, content_json JSONB DEFAULT '{}', reply_to_message_id INT REFERENCES telegram_messages(id) ON DELETE SET NULL, agent_name VARCHAR(64), agent_event_id INT REFERENCES agent_events(id) ON DELETE SET NULL, channel VARCHAR(32) DEFAULT 'telegram', created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_tg_msg_conv_created ON telegram_messages(conversation_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_tg_msg_telegram_id ON telegram_messages(telegram_message_id); CREATE INDEX IF NOT EXISTS idx_tg_msg_fts ON telegram_messages USING gin(to_tsvector('simple', coalesce(content_text, ''))); CREATE TABLE IF NOT EXISTS telegram_message_embeddings ( id SERIAL PRIMARY KEY, message_id INT NOT NULL REFERENCES telegram_messages(id) ON DELETE CASCADE, chunk_index INT DEFAULT 0, embedding vector(768) NOT NULL, model VARCHAR(64) DEFAULT 'nomic-embed-text', created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE (message_id, chunk_index) ); CREATE INDEX IF NOT EXISTS idx_tg_emb_hnsw ON telegram_message_embeddings USING hnsw (embedding vector_cosine_ops); CREATE TABLE IF NOT EXISTS telegram_message_edges ( id SERIAL PRIMARY KEY, source_message_id INT NOT NULL REFERENCES telegram_messages(id) ON DELETE CASCADE, target_message_id INT REFERENCES telegram_messages(id) ON DELETE SET NULL, target_entity_type VARCHAR(64), target_entity_id INT, edge_type VARCHAR(64) NOT NULL, weight FLOAT DEFAULT 1.0, metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_tg_edges_source ON telegram_message_edges(source_message_id); CREATE INDEX IF NOT EXISTS idx_tg_edges_target ON telegram_message_edges(target_message_id); CREATE INDEX IF NOT EXISTS idx_tg_edges_type ON telegram_message_edges(edge_type); CREATE INDEX IF NOT EXISTS idx_tg_edges_entity ON telegram_message_edges(target_entity_type, target_entity_id); CREATE OR REPLACE VIEW telegram_graph_view AS SELECT e.id AS edge_id, e.edge_type, e.weight, e.target_entity_type, e.target_entity_id, sm.id AS source_id, sm.content_text AS source_text, sm.direction AS source_direction, sm.agent_name AS source_agent, tm.id AS target_id, tm.content_text AS target_text, c.chat_id, e.created_at FROM telegram_message_edges e JOIN telegram_messages sm ON sm.id = e.source_message_id LEFT JOIN telegram_messages tm ON tm.id = e.target_message_id JOIN telegram_conversations c ON c.id = sm.conversation_id;