Files
microdao-daarion/migrations/049_memory_v3_human_memory_model.sql
Apple 0c8bef82f4 feat: Add Alateya, Clan, Eonarch agents + fix gateway-router connection
## Agents Added
- Alateya: R&D, biotech, innovations
- Clan (Spirit): Community spirit agent
- Eonarch: Consciousness evolution agent

## Changes
- docker-compose.node1.yml: Added tokens for all 3 new agents
- gateway-bot/http_api.py: Added configs and webhook endpoints
- gateway-bot/clan_prompt.txt: New prompt file
- gateway-bot/eonarch_prompt.txt: New prompt file

## Fixes
- Fixed ROUTER_URL from :9102 to :8000 (internal container port)
- All 9 Telegram agents now working

## Documentation
- Created PROJECT-MASTER-INDEX.md - single entry point
- Added various status documents and scripts

Tokens configured:
- Helion, NUTRA, Agromatrix (existing)
- Alateya, Clan, Eonarch (new)
- Druid, GreenFood, DAARWIZZ (configured)
2026-01-28 06:40:34 -08:00

408 lines
16 KiB
PL/PgSQL

-- Migration 049: Human Memory Model v3.0 for Helion
-- Full identity, roles, session state, and organizational memory schema
-- Created: 2026-01-17
-- ============================================================================
-- L2: PLATFORM IDENTITY & ROLES (PIR)
-- ============================================================================
-- Global platform users (cross-channel identity)
CREATE TABLE IF NOT EXISTS platform_users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
status TEXT DEFAULT 'active', -- active, inactive, banned, deleted
-- Aggregated profile (derived from channel_identities)
preferred_language TEXT DEFAULT 'uk',
timezone TEXT,
metadata JSONB DEFAULT '{}'
);
-- Channel-specific identities (Telegram, Discord, Email, etc.)
CREATE TABLE IF NOT EXISTS channel_identities (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
platform_user_id UUID NOT NULL REFERENCES platform_users(id) ON DELETE CASCADE,
channel TEXT NOT NULL, -- telegram, discord, email, web
channel_user_id TEXT NOT NULL, -- Telegram from.id, Discord user_id, etc.
username TEXT, -- @username
display_name TEXT, -- first_name + last_name
avatar_url TEXT,
verified BOOLEAN DEFAULT FALSE,
first_seen_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_seen_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
metadata JSONB DEFAULT '{}', -- channel-specific data
UNIQUE(channel, channel_user_id)
);
CREATE INDEX IF NOT EXISTS idx_channel_identities_platform_user ON channel_identities(platform_user_id);
CREATE INDEX IF NOT EXISTS idx_channel_identities_channel_user ON channel_identities(channel, channel_user_id);
-- Platform roles (mentor, dev, investor, ops, moderator)
CREATE TABLE IF NOT EXISTS platform_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
code TEXT NOT NULL UNIQUE, -- mentor, developer, investor, ops, moderator, admin
display_name TEXT NOT NULL,
scope TEXT NOT NULL DEFAULT 'platform', -- platform, group, thread
description TEXT,
permissions JSONB DEFAULT '[]', -- list of permission codes
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- User-role assignments
CREATE TABLE IF NOT EXISTS user_roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
platform_user_id UUID NOT NULL REFERENCES platform_users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES platform_roles(id) ON DELETE CASCADE,
scope_ref TEXT, -- group_id for group-scoped roles, null for platform-wide
confidence REAL DEFAULT 1.0, -- 0.0-1.0, lower for inferred roles
assigned_by TEXT, -- 'system', 'admin', 'helion_inferred', user_id
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
revoked_at TIMESTAMP WITH TIME ZONE, -- null if active
notes TEXT,
UNIQUE(platform_user_id, role_id, scope_ref)
);
CREATE INDEX IF NOT EXISTS idx_user_roles_platform_user ON user_roles(platform_user_id);
CREATE INDEX IF NOT EXISTS idx_user_roles_active ON user_roles(platform_user_id) WHERE revoked_at IS NULL;
-- ============================================================================
-- L1: SESSION STATE MEMORY (SSM)
-- ============================================================================
-- Conversations (chat sessions)
CREATE TABLE IF NOT EXISTS helion_conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
channel TEXT NOT NULL, -- telegram, discord, web
chat_id TEXT NOT NULL, -- Telegram chat_id, Discord channel_id
thread_id TEXT, -- Optional thread within chat
platform_user_id UUID REFERENCES platform_users(id), -- Primary user (for DMs)
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
status TEXT DEFAULT 'active', -- active, archived, deleted
metadata JSONB DEFAULT '{}',
UNIQUE(channel, chat_id, thread_id)
);
CREATE INDEX IF NOT EXISTS idx_conversations_chat ON helion_conversations(channel, chat_id);
CREATE INDEX IF NOT EXISTS idx_conversations_user ON helion_conversations(platform_user_id);
-- Session state (SSM) - per conversation
CREATE TABLE IF NOT EXISTS helion_conversation_state (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES helion_conversations(id) ON DELETE CASCADE,
-- Addressing state
last_addressed_to_helion BOOLEAN DEFAULT FALSE,
last_user_id TEXT,
last_user_nick TEXT,
-- Topic/context tracking
active_topic_id TEXT,
active_context_open BOOLEAN DEFAULT FALSE,
closed_context_ids TEXT[] DEFAULT '{}',
-- Media handling
last_media_id TEXT,
last_media_type TEXT,
last_media_handled BOOLEAN DEFAULT FALSE,
-- Anti-repeat mechanism
last_answer_fingerprint TEXT,
last_answer_at TIMESTAMP WITH TIME ZONE,
-- Group settings
group_trust_mode BOOLEAN DEFAULT FALSE,
apprentice_mode BOOLEAN DEFAULT FALSE,
-- Proactive question limits
proactive_questions_today INTEGER DEFAULT 0,
last_proactive_question_at TIMESTAMP WITH TIME ZONE,
proactive_question_reset_date DATE DEFAULT CURRENT_DATE,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
state_json JSONB DEFAULT '{}', -- Additional flexible state
UNIQUE(conversation_id)
);
CREATE INDEX IF NOT EXISTS idx_conversation_state_conv ON helion_conversation_state(conversation_id);
-- Media index (for tracking processed media)
CREATE TABLE IF NOT EXISTS helion_media_index (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES helion_conversations(id) ON DELETE CASCADE,
message_id TEXT NOT NULL,
media_type TEXT NOT NULL, -- photo, voice, video, document, video_note
file_id TEXT NOT NULL,
file_hash TEXT, -- For deduplication
handled BOOLEAN DEFAULT FALSE,
handled_at TIMESTAMP WITH TIME ZONE,
result_summary TEXT, -- Brief summary of what was extracted
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(conversation_id, file_id)
);
CREATE INDEX IF NOT EXISTS idx_media_index_conv ON helion_media_index(conversation_id);
CREATE INDEX IF NOT EXISTS idx_media_index_file ON helion_media_index(file_id);
-- ============================================================================
-- L3: ORGANIZATIONAL MEMORY (OM)
-- ============================================================================
-- Extended memory items (long-term facts)
CREATE TABLE IF NOT EXISTS helion_memory_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
platform_user_id UUID REFERENCES platform_users(id) ON DELETE SET NULL,
-- Memory classification
type TEXT NOT NULL, -- preference, decision, agreement, profile_fact, mentor_lesson, project_fact
category TEXT, -- personal, technical, organizational, stylistic
-- Content
text TEXT NOT NULL,
summary TEXT, -- Short summary for retrieval brief
-- Source tracking
source_ref TEXT, -- conversation_id, message_id, or external source
source_type TEXT, -- conversation, manual, import, inferred
-- Confidence and verification
confidence REAL DEFAULT 0.7, -- 0.0-1.0
verified BOOLEAN DEFAULT FALSE,
verified_by TEXT,
verified_at TIMESTAMP WITH TIME ZONE,
-- Visibility and scope
visibility TEXT DEFAULT 'platform', -- private_dm, group_only, platform
scope_ref TEXT, -- group_id if group_only
-- Lifecycle
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
expires_at TIMESTAMP WITH TIME ZONE, -- null = never expires
archived_at TIMESTAMP WITH TIME ZONE,
-- Vector reference
embedding_id TEXT, -- Qdrant point ID
metadata JSONB DEFAULT '{}'
);
CREATE INDEX IF NOT EXISTS idx_memory_items_user ON helion_memory_items(platform_user_id);
CREATE INDEX IF NOT EXISTS idx_memory_items_type ON helion_memory_items(type);
CREATE INDEX IF NOT EXISTS idx_memory_items_visibility ON helion_memory_items(visibility);
CREATE INDEX IF NOT EXISTS idx_memory_items_active ON helion_memory_items(platform_user_id)
WHERE archived_at IS NULL AND (expires_at IS NULL OR expires_at > NOW());
-- Memory events (audit log)
CREATE TABLE IF NOT EXISTS helion_memory_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
platform_user_id UUID REFERENCES platform_users(id),
memory_item_id UUID REFERENCES helion_memory_items(id) ON DELETE SET NULL,
event_type TEXT NOT NULL, -- add, update, verify, revoke, retrieve, archive
actor TEXT NOT NULL, -- user, helion, admin, system
actor_ref TEXT, -- user_id or service name
payload_json JSONB DEFAULT '{}',
ts TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_memory_events_user ON helion_memory_events(platform_user_id);
CREATE INDEX IF NOT EXISTS idx_memory_events_item ON helion_memory_events(memory_item_id);
CREATE INDEX IF NOT EXISTS idx_memory_events_ts ON helion_memory_events(ts);
-- ============================================================================
-- MENTORS & TRUSTED GROUPS (Updated from v2.3)
-- ============================================================================
-- Mentors table (platform-wide or group-specific)
CREATE TABLE IF NOT EXISTS helion_mentors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
platform_user_id UUID REFERENCES platform_users(id),
scope TEXT DEFAULT 'platform', -- platform, group
scope_ref TEXT, -- group chat_id if group-scoped
-- Telegram info (for matching)
telegram_user_id TEXT,
telegram_username TEXT,
display_name TEXT,
phone_hash TEXT, -- Hashed phone for matching (privacy)
-- Status
confidence TEXT DEFAULT 'configured', -- configured, confirmed, inferred
active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(platform_user_id, scope, scope_ref)
);
CREATE INDEX IF NOT EXISTS idx_mentors_telegram ON helion_mentors(telegram_user_id);
CREATE INDEX IF NOT EXISTS idx_mentors_username ON helion_mentors(telegram_username);
-- Trusted groups/chats
CREATE TABLE IF NOT EXISTS helion_trusted_groups (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
channel TEXT NOT NULL DEFAULT 'telegram',
chat_id TEXT NOT NULL,
chat_username TEXT, -- @energyunionofficial
chat_title TEXT,
-- Settings
trust_mode BOOLEAN DEFAULT TRUE,
apprentice_mode BOOLEAN DEFAULT TRUE,
auto_respond BOOLEAN DEFAULT FALSE, -- Respond even without mention
-- Limits
proactive_questions_per_day INTEGER DEFAULT 3,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(channel, chat_id)
);
-- ============================================================================
-- INITIAL DATA
-- ============================================================================
-- Insert default roles
INSERT INTO platform_roles (code, display_name, scope, description) VALUES
('admin', 'Administrator', 'platform', 'Full platform access'),
('mentor', 'Mentor', 'platform', 'Can teach Helion, elevated trust'),
('developer', 'Developer', 'platform', 'Technical team member'),
('investor', 'Investor', 'platform', 'Token holder or investor'),
('ops', 'Operations', 'platform', 'Operations team member'),
('moderator', 'Moderator', 'group', 'Group moderator'),
('member', 'Member', 'platform', 'Regular platform member')
ON CONFLICT (code) DO NOTHING;
-- Insert known mentors
INSERT INTO helion_mentors (telegram_username, display_name, confidence) VALUES
('@ivantytar', 'Іван Титар', 'configured'),
('@archenvis', 'Александр Вертій', 'configured'),
('@olegarch88', 'Олег Ковальчук', 'configured')
ON CONFLICT DO NOTHING;
-- Insert trusted groups
INSERT INTO helion_trusted_groups (channel, chat_id, chat_username, chat_title, trust_mode, apprentice_mode) VALUES
('telegram', '-1001234567890', '@energyunionofficial', 'Energy Union Official', TRUE, TRUE),
('telegram', '-1009876543210', '@energyunionteam', 'Energy Union Team', TRUE, TRUE)
ON CONFLICT (channel, chat_id) DO UPDATE SET
chat_username = EXCLUDED.chat_username,
chat_title = EXCLUDED.chat_title;
-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================
-- Function to resolve or create platform user from channel identity
CREATE OR REPLACE FUNCTION resolve_platform_user(
p_channel TEXT,
p_channel_user_id TEXT,
p_username TEXT DEFAULT NULL,
p_display_name TEXT DEFAULT NULL
) RETURNS UUID AS $$
DECLARE
v_platform_user_id UUID;
v_identity_id UUID;
BEGIN
-- Check if identity exists
SELECT platform_user_id INTO v_platform_user_id
FROM channel_identities
WHERE channel = p_channel AND channel_user_id = p_channel_user_id;
IF v_platform_user_id IS NULL THEN
-- Create new platform user
INSERT INTO platform_users (status) VALUES ('active')
RETURNING id INTO v_platform_user_id;
-- Create channel identity
INSERT INTO channel_identities (platform_user_id, channel, channel_user_id, username, display_name)
VALUES (v_platform_user_id, p_channel, p_channel_user_id, p_username, p_display_name);
ELSE
-- Update last seen and username if changed
UPDATE channel_identities
SET last_seen_at = NOW(),
username = COALESCE(p_username, username),
display_name = COALESCE(p_display_name, display_name)
WHERE channel = p_channel AND channel_user_id = p_channel_user_id;
END IF;
RETURN v_platform_user_id;
END;
$$ LANGUAGE plpgsql;
-- Function to get or create conversation
CREATE OR REPLACE FUNCTION get_or_create_conversation(
p_channel TEXT,
p_chat_id TEXT,
p_thread_id TEXT DEFAULT NULL,
p_platform_user_id UUID DEFAULT NULL
) RETURNS UUID AS $$
DECLARE
v_conversation_id UUID;
BEGIN
SELECT id INTO v_conversation_id
FROM helion_conversations
WHERE channel = p_channel
AND chat_id = p_chat_id
AND COALESCE(thread_id, '') = COALESCE(p_thread_id, '');
IF v_conversation_id IS NULL THEN
INSERT INTO helion_conversations (channel, chat_id, thread_id, platform_user_id)
VALUES (p_channel, p_chat_id, p_thread_id, p_platform_user_id)
RETURNING id INTO v_conversation_id;
ELSE
UPDATE helion_conversations
SET last_activity_at = NOW()
WHERE id = v_conversation_id;
END IF;
RETURN v_conversation_id;
END;
$$ LANGUAGE plpgsql;
-- Function to check if user is mentor
CREATE OR REPLACE FUNCTION is_mentor(
p_telegram_user_id TEXT DEFAULT NULL,
p_telegram_username TEXT DEFAULT NULL
) RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (
SELECT 1 FROM helion_mentors
WHERE active = TRUE
AND (telegram_user_id = p_telegram_user_id OR telegram_username = p_telegram_username)
);
END;
$$ LANGUAGE plpgsql;
-- Function to check if chat is trusted
CREATE OR REPLACE FUNCTION is_trusted_group(
p_channel TEXT,
p_chat_id TEXT
) RETURNS BOOLEAN AS $$
BEGIN
RETURN EXISTS (
SELECT 1 FROM helion_trusted_groups
WHERE channel = p_channel AND chat_id = p_chat_id AND trust_mode = TRUE
);
END;
$$ LANGUAGE plpgsql;
-- ============================================================================
-- COMMENTS
-- ============================================================================
COMMENT ON TABLE platform_users IS 'Global user identity across all channels (L2 PIR)';
COMMENT ON TABLE channel_identities IS 'Channel-specific user identities linked to platform users';
COMMENT ON TABLE platform_roles IS 'Available roles in the platform';
COMMENT ON TABLE user_roles IS 'User role assignments with scope and confidence';
COMMENT ON TABLE helion_conversations IS 'Chat sessions/conversations';
COMMENT ON TABLE helion_conversation_state IS 'Session state memory (L1 SSM) per conversation';
COMMENT ON TABLE helion_media_index IS 'Index of processed media to avoid re-processing';
COMMENT ON TABLE helion_memory_items IS 'Long-term memory facts (L3 OM)';
COMMENT ON TABLE helion_memory_events IS 'Audit log of memory operations';
COMMENT ON TABLE helion_mentors IS 'Configured and confirmed mentors';
COMMENT ON TABLE helion_trusted_groups IS 'Trusted groups with special settings';