The Redis configuration is defined in configs/connections.json. Current topic queue names:
{
"chat_history": "llm-chat",
"prompt_queue": "prompt-queue",
"memory_chunker": "memory-chunker-queue",
"episodic_memory": "episodic-memory-queue"
}
"topics": {
"chat_history": "llm-chat",
"prompt_queue": "prompt-queue",
"memory_chunker": "memory-chunker-queue",
"episodic_memory": "episodic-memory-queue"
}
Each key maps to a queue name that the worker services consume from.
The episodic_storage_service.py inserts rows into the episodes table. The table schema (partial) is:
CREATE TABLE episodes (
id UUID PRIMARY KEY,
intent JSONB NOT NULL,
context JSONB NOT NULL,
action TEXT NOT NULL,
emotion JSONB NOT NULL,
outcome TEXT NOT NULL,
gist TEXT NOT NULL,
salience FLOAT NOT NULL,
freshness FLOAT NOT NULL,
embedding vector(768),
topic TEXT NOT NULL,
exchange_id TEXT,
activation_score FLOAT DEFAULT 1.0,
salience_factors JSONB NOT NULL,
open_loops JSONB DEFAULT '[]'::jsonb,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
last_accessed_at TIMESTAMP,
access_count INTEGER DEFAULT 0,
deleted_at TIMESTAMP
);
Core Episode Content:
intent (JSONB) – Intent structure: {"type": "exploration|...", "direction": "open-ended|..."}context (JSONB) – Context: {"situational": "...", "conversational": "...", "constraints": [...]}action (TEXT) – Concrete actions taken or discussedemotion (JSONB) – Emotion: {"type": "...", "valence": "positive|...", "intensity": "low|...", "arc": "..."}outcome (TEXT) – Result or conclusiongist (TEXT) – Concise 1-3 sentence summarySalience & Retrieval:
salience (FLOAT) – Computed [0.1,1.0]: Base = 0.4·novelty + 0.4·emotional + 0.2·commitment, then ×1.25 if unresolved. Reconsolidation: Retrieved episodes get boosted by 0.2 (configurable)freshness (FLOAT) – Initially salience; dynamic at retrieval: e^(-decay × (1-salience) × hours)salience_factors (JSONB) – LLM factors (0-3 scale): {"novelty": 2, "emotional": 2, "commitment": 1, "unresolved": true}open_loops (JSONB) – Array of unresolved items: ["Question X remains unresolved", ...]Search & Tracking:
embedding (vector) – 768-dim semantic vector for similarity searchtopic (TEXT) – Conversation topicactivation_score (FLOAT) – ACT-R activation scorelast_accessed_at (TIMESTAMP) – Last retrieval time (for freshness decay)access_count (INTEGER) – Number of accessesConversations are stored as Redis-backed threads with metadata in PostgreSQL.
Threads Table:
CREATE TABLE threads (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
topic TEXT NOT NULL,
title TEXT,
status TEXT DEFAULT 'active', -- active, archived, deleted
metadata JSONB DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
last_message_at TIMESTAMP,
expires_at TIMESTAMP
);
Fields:
id: Unique thread identifiertopic: Active conversation topic (used for memory scoping)metadata: Thread state including confidence, classifier infoexpires_at: Thread expiry time (managed by thread_expiry_service)Conversation history is stored in Redis via ThreadConversationService with a 24h TTL. Thread metadata is persisted in PostgreSQL for durability.
Three tables provide deterministic list management with full history (list_service.py).
lists — List containers
CREATE TABLE lists (
id TEXT PRIMARY KEY, -- 8-char hex
user_id TEXT NOT NULL DEFAULT 'primary',
name TEXT NOT NULL,
list_type TEXT NOT NULL DEFAULT 'checklist',
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ -- soft delete
);
-- Unique name per user (case-insensitive, active lists only)
CREATE UNIQUE INDEX idx_lists_user_name_unique ON lists (user_id, lower(name)) WHERE deleted_at IS NULL;
list_items — Items within lists
CREATE TABLE list_items (
id TEXT PRIMARY KEY, -- 8-char hex
list_id TEXT NOT NULL REFERENCES lists(id),
content TEXT NOT NULL,
checked BOOLEAN NOT NULL DEFAULT FALSE,
position INTEGER NOT NULL DEFAULT 0,
metadata JSONB NOT NULL DEFAULT '{}',
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
removed_at TIMESTAMPTZ -- soft delete (preserves history)
);
list_events — Audit log for history queries
CREATE TABLE list_events (
id TEXT PRIMARY KEY, -- 8-char hex
list_id TEXT NOT NULL REFERENCES lists(id),
event_type TEXT NOT NULL, -- item_added, item_removed, item_checked, item_unchecked, list_created, list_cleared, list_deleted, list_renamed
item_content TEXT,
details JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
Design notes:
removed_at) rather than hard-deleted — history is preserved for temporal reasoningremoved_at) instead of inserting a duplicatelists.updated_at is touched on every item mutation for recency-based resolutionlist_service._resolve_list() tries exact ID first, then name matchlist_service.get_lists_for_prompt() formats a compact summary injected as `` into all four mode prompts (RESPOND, ACT, CLARIFY, ACKNOWLEDGE)CREATE TABLE scheduled_items (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
scheduled_for TIMESTAMP NOT NULL,
recurrence TEXT, -- none, daily, weekly, monthly
status TEXT DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE curiosity_threads (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
rationale TEXT,
thread_type TEXT NOT NULL CHECK (thread_type IN ('learning', 'behavioral')),
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'dormant', 'abandoned')),
seed_topic TEXT,
learning_notes JSONB NOT NULL DEFAULT '[]',
last_explored_at TIMESTAMPTZ,
exploration_count INTEGER NOT NULL DEFAULT 0,
last_surfaced_at TIMESTAMPTZ,
engagement_score FLOAT NOT NULL DEFAULT 0.5,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE autobiography (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
content TEXT NOT NULL,
sections JSONB, -- identity, values, patterns, etc.
version INTEGER DEFAULT 1,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE routing_decisions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
selected_mode TEXT NOT NULL,
scores JSONB NOT NULL,
signals JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE semantic_concepts (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
definition TEXT,
embedding vector(768),
strength FLOAT DEFAULT 1.0,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE semantic_relationships (
id TEXT PRIMARY KEY,
concept_a_id TEXT NOT NULL REFERENCES semantic_concepts(id),
concept_b_id TEXT NOT NULL REFERENCES semantic_concepts(id),
relationship_type TEXT NOT NULL,
strength FLOAT DEFAULT 1.0,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE user_traits (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
category TEXT NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL,
confidence FLOAT DEFAULT 1.0,
decay_rate FLOAT DEFAULT 0.05,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE providers (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
type TEXT NOT NULL, -- ollama, openai, anthropic, gemini
endpoint TEXT,
config JSONB,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE job_provider_assignments (
id TEXT PRIMARY KEY,
job_name TEXT NOT NULL,
provider_id TEXT NOT NULL REFERENCES providers(id),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE tool_configs (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
tool_name TEXT NOT NULL,
config JSONB,
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE master_account (
id TEXT PRIMARY KEY,
password_hash TEXT NOT NULL,
encryption_key TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE triage_calibration (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
metric_name TEXT NOT NULL,
score FLOAT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);