omni-cortex 1.17.1__py3-none-any.whl → 1.17.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omni_cortex/__init__.py +3 -0
- omni_cortex/_bundled/dashboard/backend/.env.example +12 -0
- omni_cortex/_bundled/dashboard/backend/backfill_summaries.py +280 -0
- omni_cortex/_bundled/dashboard/backend/chat_service.py +631 -0
- omni_cortex/_bundled/dashboard/backend/database.py +1773 -0
- omni_cortex/_bundled/dashboard/backend/image_service.py +552 -0
- omni_cortex/_bundled/dashboard/backend/logging_config.py +122 -0
- omni_cortex/_bundled/dashboard/backend/main.py +1888 -0
- omni_cortex/_bundled/dashboard/backend/models.py +472 -0
- omni_cortex/_bundled/dashboard/backend/project_config.py +170 -0
- omni_cortex/_bundled/dashboard/backend/project_scanner.py +164 -0
- omni_cortex/_bundled/dashboard/backend/prompt_security.py +111 -0
- omni_cortex/_bundled/dashboard/backend/pyproject.toml +23 -0
- omni_cortex/_bundled/dashboard/backend/security.py +104 -0
- omni_cortex/_bundled/dashboard/backend/uv.lock +1110 -0
- omni_cortex/_bundled/dashboard/backend/websocket_manager.py +104 -0
- omni_cortex/_bundled/hooks/post_tool_use.py +497 -0
- omni_cortex/_bundled/hooks/pre_tool_use.py +277 -0
- omni_cortex/_bundled/hooks/session_utils.py +186 -0
- omni_cortex/_bundled/hooks/stop.py +219 -0
- omni_cortex/_bundled/hooks/subagent_stop.py +120 -0
- omni_cortex/_bundled/hooks/user_prompt.py +220 -0
- omni_cortex/categorization/__init__.py +9 -0
- omni_cortex/categorization/auto_tags.py +166 -0
- omni_cortex/categorization/auto_type.py +165 -0
- omni_cortex/config.py +141 -0
- omni_cortex/dashboard.py +238 -0
- omni_cortex/database/__init__.py +24 -0
- omni_cortex/database/connection.py +137 -0
- omni_cortex/database/migrations.py +210 -0
- omni_cortex/database/schema.py +212 -0
- omni_cortex/database/sync.py +421 -0
- omni_cortex/decay/__init__.py +7 -0
- omni_cortex/decay/importance.py +147 -0
- omni_cortex/embeddings/__init__.py +35 -0
- omni_cortex/embeddings/local.py +442 -0
- omni_cortex/models/__init__.py +20 -0
- omni_cortex/models/activity.py +265 -0
- omni_cortex/models/agent.py +144 -0
- omni_cortex/models/memory.py +395 -0
- omni_cortex/models/relationship.py +206 -0
- omni_cortex/models/session.py +290 -0
- omni_cortex/resources/__init__.py +1 -0
- omni_cortex/search/__init__.py +22 -0
- omni_cortex/search/hybrid.py +197 -0
- omni_cortex/search/keyword.py +204 -0
- omni_cortex/search/ranking.py +127 -0
- omni_cortex/search/semantic.py +232 -0
- omni_cortex/server.py +360 -0
- omni_cortex/setup.py +284 -0
- omni_cortex/tools/__init__.py +13 -0
- omni_cortex/tools/activities.py +453 -0
- omni_cortex/tools/memories.py +536 -0
- omni_cortex/tools/sessions.py +311 -0
- omni_cortex/tools/utilities.py +477 -0
- omni_cortex/utils/__init__.py +13 -0
- omni_cortex/utils/formatting.py +282 -0
- omni_cortex/utils/ids.py +72 -0
- omni_cortex/utils/timestamps.py +129 -0
- omni_cortex/utils/truncation.py +111 -0
- {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/METADATA +1 -1
- omni_cortex-1.17.3.dist-info/RECORD +86 -0
- omni_cortex-1.17.1.dist-info/RECORD +0 -26
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/main.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/stop.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
- {omni_cortex-1.17.1.data → omni_cortex-1.17.3.data}/data/share/omni-cortex/hooks/user_prompt.py +0 -0
- {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/WHEEL +0 -0
- {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/entry_points.txt +0 -0
- {omni_cortex-1.17.1.dist-info → omni_cortex-1.17.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Database migration management for Omni Cortex."""
|
|
2
|
+
|
|
3
|
+
import sqlite3
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from .schema import SCHEMA_VERSION, get_schema_sql
|
|
8
|
+
from .connection import get_connection
|
|
9
|
+
from ..utils.timestamps import now_iso
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Migration definitions: version -> SQL
|
|
13
|
+
MIGRATIONS: dict[str, str] = {
|
|
14
|
+
# Command analytics columns for slash command/skill tracking
|
|
15
|
+
"1.1": """
|
|
16
|
+
-- Add command analytics columns to activities table
|
|
17
|
+
ALTER TABLE activities ADD COLUMN command_name TEXT;
|
|
18
|
+
ALTER TABLE activities ADD COLUMN command_scope TEXT;
|
|
19
|
+
ALTER TABLE activities ADD COLUMN mcp_server TEXT;
|
|
20
|
+
ALTER TABLE activities ADD COLUMN skill_name TEXT;
|
|
21
|
+
|
|
22
|
+
-- Create indexes for new columns
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_activities_command ON activities(command_name);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_activities_mcp ON activities(mcp_server);
|
|
25
|
+
CREATE INDEX IF NOT EXISTS idx_activities_skill ON activities(skill_name);
|
|
26
|
+
""",
|
|
27
|
+
# Natural language summary columns for activity display
|
|
28
|
+
"1.2": """
|
|
29
|
+
-- Add natural language summary columns to activities table
|
|
30
|
+
ALTER TABLE activities ADD COLUMN summary TEXT;
|
|
31
|
+
ALTER TABLE activities ADD COLUMN summary_detail TEXT;
|
|
32
|
+
""",
|
|
33
|
+
# Duration tracking columns for concrete time analysis
|
|
34
|
+
"1.3": """
|
|
35
|
+
-- Add duration tracking to sessions table
|
|
36
|
+
ALTER TABLE sessions ADD COLUMN duration_ms INTEGER;
|
|
37
|
+
|
|
38
|
+
-- Add duration tracking to session_summaries table
|
|
39
|
+
ALTER TABLE session_summaries ADD COLUMN duration_ms INTEGER;
|
|
40
|
+
ALTER TABLE session_summaries ADD COLUMN tool_duration_breakdown TEXT;
|
|
41
|
+
|
|
42
|
+
-- Create index for duration queries
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_activities_duration ON activities(duration_ms);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_duration ON sessions(duration_ms);
|
|
45
|
+
""",
|
|
46
|
+
# User message tracking for style analysis
|
|
47
|
+
"1.4": """
|
|
48
|
+
-- User messages table for tracking all user prompts
|
|
49
|
+
CREATE TABLE IF NOT EXISTS user_messages (
|
|
50
|
+
id TEXT PRIMARY KEY, -- msg_{timestamp}_{random}
|
|
51
|
+
session_id TEXT,
|
|
52
|
+
timestamp TEXT NOT NULL, -- ISO 8601
|
|
53
|
+
content TEXT NOT NULL, -- The full user message
|
|
54
|
+
word_count INTEGER,
|
|
55
|
+
char_count INTEGER,
|
|
56
|
+
line_count INTEGER,
|
|
57
|
+
has_code_blocks INTEGER DEFAULT 0,
|
|
58
|
+
has_questions INTEGER DEFAULT 0,
|
|
59
|
+
has_commands INTEGER DEFAULT 0, -- Starts with /
|
|
60
|
+
tone_indicators TEXT, -- JSON: detected tone markers
|
|
61
|
+
project_path TEXT,
|
|
62
|
+
metadata TEXT, -- JSON for extensibility
|
|
63
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
-- User style profile for aggregated style analysis
|
|
67
|
+
CREATE TABLE IF NOT EXISTS user_style_profiles (
|
|
68
|
+
id TEXT PRIMARY KEY, -- profile_{timestamp}_{random}
|
|
69
|
+
project_path TEXT, -- NULL for global profile
|
|
70
|
+
total_messages INTEGER DEFAULT 0,
|
|
71
|
+
avg_word_count REAL,
|
|
72
|
+
avg_char_count REAL,
|
|
73
|
+
common_phrases TEXT, -- JSON array of frequent phrases
|
|
74
|
+
vocabulary_richness REAL, -- Type-token ratio
|
|
75
|
+
formality_score REAL, -- 0-100 scale
|
|
76
|
+
question_frequency REAL, -- % of messages with questions
|
|
77
|
+
command_frequency REAL, -- % of messages starting with /
|
|
78
|
+
code_block_frequency REAL, -- % with code blocks
|
|
79
|
+
punctuation_style TEXT, -- JSON: punctuation patterns
|
|
80
|
+
greeting_patterns TEXT, -- JSON: how user starts conversations
|
|
81
|
+
instruction_style TEXT, -- JSON: how user gives instructions
|
|
82
|
+
sample_messages TEXT, -- JSON array of representative samples
|
|
83
|
+
created_at TEXT NOT NULL,
|
|
84
|
+
updated_at TEXT NOT NULL,
|
|
85
|
+
metadata TEXT
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
-- Indexes for user message queries
|
|
89
|
+
CREATE INDEX IF NOT EXISTS idx_user_messages_session ON user_messages(session_id);
|
|
90
|
+
CREATE INDEX IF NOT EXISTS idx_user_messages_timestamp ON user_messages(timestamp DESC);
|
|
91
|
+
CREATE INDEX IF NOT EXISTS idx_user_messages_project ON user_messages(project_path);
|
|
92
|
+
CREATE INDEX IF NOT EXISTS idx_user_style_project ON user_style_profiles(project_path);
|
|
93
|
+
""",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_current_version(conn: sqlite3.Connection) -> Optional[str]:
|
|
98
|
+
"""Get the current schema version from the database."""
|
|
99
|
+
try:
|
|
100
|
+
cursor = conn.execute(
|
|
101
|
+
"SELECT version FROM schema_migrations ORDER BY applied_at DESC LIMIT 1"
|
|
102
|
+
)
|
|
103
|
+
row = cursor.fetchone()
|
|
104
|
+
return row[0] if row else None
|
|
105
|
+
except sqlite3.OperationalError:
|
|
106
|
+
# Table doesn't exist yet
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def strip_sql_comments(sql: str) -> str:
|
|
111
|
+
"""Strip SQL comments from a statement while preserving inline comments in strings."""
|
|
112
|
+
import re
|
|
113
|
+
lines = sql.split('\n')
|
|
114
|
+
cleaned_lines = []
|
|
115
|
+
for line in lines:
|
|
116
|
+
# Remove line comments (-- ...) but only if not inside a string
|
|
117
|
+
# Simple approach: just strip everything after -- if not in CREATE TABLE definition
|
|
118
|
+
# For CREATE TABLE, we need to keep the structure
|
|
119
|
+
stripped = line.strip()
|
|
120
|
+
if stripped.startswith('--'):
|
|
121
|
+
continue # Skip pure comment lines
|
|
122
|
+
# Keep lines that have SQL content (even if they have trailing comments)
|
|
123
|
+
cleaned_lines.append(line)
|
|
124
|
+
return '\n'.join(cleaned_lines)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def apply_migration(conn: sqlite3.Connection, version: str, sql: str) -> None:
|
|
128
|
+
"""Apply a single migration.
|
|
129
|
+
|
|
130
|
+
Handles ALTER TABLE ADD COLUMN gracefully - if column exists, skips it.
|
|
131
|
+
"""
|
|
132
|
+
# First, strip pure comment lines from the SQL
|
|
133
|
+
sql = strip_sql_comments(sql)
|
|
134
|
+
|
|
135
|
+
# Split into individual statements and apply each
|
|
136
|
+
for statement in sql.strip().split(';'):
|
|
137
|
+
statement = statement.strip()
|
|
138
|
+
if not statement:
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
# Skip if the remaining statement is just whitespace or pure comments
|
|
142
|
+
non_comment_content = '\n'.join(
|
|
143
|
+
line for line in statement.split('\n')
|
|
144
|
+
if line.strip() and not line.strip().startswith('--')
|
|
145
|
+
).strip()
|
|
146
|
+
if not non_comment_content:
|
|
147
|
+
continue
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
conn.execute(statement)
|
|
151
|
+
conn.commit() # Commit each statement so next one sees the change
|
|
152
|
+
except sqlite3.OperationalError as e:
|
|
153
|
+
error_msg = str(e).lower()
|
|
154
|
+
# Ignore "duplicate column" errors - column already exists
|
|
155
|
+
if "duplicate column" in error_msg:
|
|
156
|
+
continue
|
|
157
|
+
# Ignore "index already exists" errors
|
|
158
|
+
if "already exists" in error_msg:
|
|
159
|
+
continue
|
|
160
|
+
# Ignore "no such column" for indexes on columns that may not exist yet
|
|
161
|
+
# (will be created in a later migration)
|
|
162
|
+
if "no such column" in error_msg and "CREATE INDEX" in statement.upper():
|
|
163
|
+
continue
|
|
164
|
+
# Ignore "table already exists" errors
|
|
165
|
+
if "already exists" in error_msg:
|
|
166
|
+
continue
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
conn.execute(
|
|
170
|
+
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
171
|
+
(version, now_iso())
|
|
172
|
+
)
|
|
173
|
+
conn.commit()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def migrate(db_path: Optional[Path] = None, is_global: bool = False) -> str:
|
|
177
|
+
"""Run all pending migrations.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
The final schema version
|
|
181
|
+
"""
|
|
182
|
+
conn = get_connection(db_path, is_global)
|
|
183
|
+
current = get_current_version(conn)
|
|
184
|
+
|
|
185
|
+
if current is None:
|
|
186
|
+
# Fresh database - apply full schema
|
|
187
|
+
conn.executescript(get_schema_sql())
|
|
188
|
+
conn.execute(
|
|
189
|
+
"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)",
|
|
190
|
+
(SCHEMA_VERSION, now_iso())
|
|
191
|
+
)
|
|
192
|
+
conn.commit()
|
|
193
|
+
return SCHEMA_VERSION
|
|
194
|
+
|
|
195
|
+
# Apply pending migrations in order
|
|
196
|
+
versions = sorted(MIGRATIONS.keys())
|
|
197
|
+
for version in versions:
|
|
198
|
+
if version > current:
|
|
199
|
+
apply_migration(conn, version, MIGRATIONS[version])
|
|
200
|
+
current = version
|
|
201
|
+
|
|
202
|
+
return current
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def needs_migration(conn: sqlite3.Connection) -> bool:
|
|
206
|
+
"""Check if database needs migration."""
|
|
207
|
+
current = get_current_version(conn)
|
|
208
|
+
if current is None:
|
|
209
|
+
return True
|
|
210
|
+
return any(v > current for v in MIGRATIONS.keys())
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Database schema definitions for Omni Cortex."""
|
|
2
|
+
|
|
3
|
+
SCHEMA_VERSION = "1.0"
|
|
4
|
+
|
|
5
|
+
# Main schema SQL
|
|
6
|
+
SCHEMA_SQL = """
|
|
7
|
+
-- ============================================
|
|
8
|
+
-- OMNI CORTEX MCP DATABASE SCHEMA v1.0
|
|
9
|
+
-- ============================================
|
|
10
|
+
|
|
11
|
+
-- Sessions Table
|
|
12
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
13
|
+
id TEXT PRIMARY KEY, -- sess_{timestamp}_{random}
|
|
14
|
+
project_path TEXT NOT NULL,
|
|
15
|
+
started_at TEXT NOT NULL, -- ISO 8601
|
|
16
|
+
ended_at TEXT,
|
|
17
|
+
summary TEXT,
|
|
18
|
+
tags TEXT, -- JSON array
|
|
19
|
+
metadata TEXT -- JSON object
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- Agents Table
|
|
23
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
24
|
+
id TEXT PRIMARY KEY, -- Agent ID from Claude Code
|
|
25
|
+
name TEXT,
|
|
26
|
+
type TEXT NOT NULL DEFAULT 'main', -- main, subagent, tool
|
|
27
|
+
first_seen TEXT NOT NULL,
|
|
28
|
+
last_seen TEXT NOT NULL,
|
|
29
|
+
total_activities INTEGER DEFAULT 0,
|
|
30
|
+
metadata TEXT
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
-- Activities Table (Layer 1)
|
|
34
|
+
CREATE TABLE IF NOT EXISTS activities (
|
|
35
|
+
id TEXT PRIMARY KEY, -- act_{timestamp}_{random}
|
|
36
|
+
session_id TEXT,
|
|
37
|
+
agent_id TEXT,
|
|
38
|
+
timestamp TEXT NOT NULL, -- ISO 8601 with timezone
|
|
39
|
+
event_type TEXT NOT NULL, -- pre_tool_use, post_tool_use, etc.
|
|
40
|
+
tool_name TEXT,
|
|
41
|
+
tool_input TEXT, -- JSON (truncated to 10KB)
|
|
42
|
+
tool_output TEXT, -- JSON (truncated to 10KB)
|
|
43
|
+
duration_ms INTEGER,
|
|
44
|
+
success INTEGER DEFAULT 1,
|
|
45
|
+
error_message TEXT,
|
|
46
|
+
project_path TEXT,
|
|
47
|
+
file_path TEXT,
|
|
48
|
+
metadata TEXT,
|
|
49
|
+
-- Command analytics columns (v1.1)
|
|
50
|
+
command_name TEXT,
|
|
51
|
+
command_scope TEXT,
|
|
52
|
+
mcp_server TEXT,
|
|
53
|
+
skill_name TEXT,
|
|
54
|
+
-- Natural language summaries (v1.2)
|
|
55
|
+
summary TEXT,
|
|
56
|
+
summary_detail TEXT,
|
|
57
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id),
|
|
58
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
-- Memories Table (Layer 2)
|
|
62
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
63
|
+
id TEXT PRIMARY KEY, -- mem_{timestamp}_{random}
|
|
64
|
+
content TEXT NOT NULL,
|
|
65
|
+
type TEXT NOT NULL DEFAULT 'general',
|
|
66
|
+
tags TEXT, -- JSON array
|
|
67
|
+
context TEXT,
|
|
68
|
+
|
|
69
|
+
-- Timestamps
|
|
70
|
+
created_at TEXT NOT NULL,
|
|
71
|
+
updated_at TEXT NOT NULL,
|
|
72
|
+
last_accessed TEXT NOT NULL,
|
|
73
|
+
last_verified TEXT,
|
|
74
|
+
|
|
75
|
+
-- Usage
|
|
76
|
+
access_count INTEGER DEFAULT 0,
|
|
77
|
+
|
|
78
|
+
-- Importance/Decay
|
|
79
|
+
importance_score REAL DEFAULT 50.0, -- 0-100
|
|
80
|
+
manual_importance INTEGER, -- User override
|
|
81
|
+
|
|
82
|
+
-- Freshness
|
|
83
|
+
status TEXT DEFAULT 'fresh', -- fresh, needs_review, outdated, archived
|
|
84
|
+
|
|
85
|
+
-- Attribution
|
|
86
|
+
source_session_id TEXT,
|
|
87
|
+
source_agent_id TEXT,
|
|
88
|
+
source_activity_id TEXT,
|
|
89
|
+
|
|
90
|
+
-- Project
|
|
91
|
+
project_path TEXT,
|
|
92
|
+
file_context TEXT, -- JSON array
|
|
93
|
+
|
|
94
|
+
-- Embedding
|
|
95
|
+
has_embedding INTEGER DEFAULT 0,
|
|
96
|
+
|
|
97
|
+
metadata TEXT,
|
|
98
|
+
|
|
99
|
+
FOREIGN KEY (source_session_id) REFERENCES sessions(id),
|
|
100
|
+
FOREIGN KEY (source_agent_id) REFERENCES agents(id),
|
|
101
|
+
FOREIGN KEY (source_activity_id) REFERENCES activities(id)
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
-- FTS5 for Full-Text Search
|
|
105
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
106
|
+
content, context, tags,
|
|
107
|
+
content=memories,
|
|
108
|
+
content_rowid=rowid,
|
|
109
|
+
tokenize='porter unicode61'
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
-- Triggers to keep FTS in sync with memories table
|
|
113
|
+
CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
|
|
114
|
+
INSERT INTO memories_fts(rowid, content, context, tags)
|
|
115
|
+
VALUES (NEW.rowid, NEW.content, NEW.context, NEW.tags);
|
|
116
|
+
END;
|
|
117
|
+
|
|
118
|
+
CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
|
|
119
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, context, tags)
|
|
120
|
+
VALUES ('delete', OLD.rowid, OLD.content, OLD.context, OLD.tags);
|
|
121
|
+
END;
|
|
122
|
+
|
|
123
|
+
CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
|
|
124
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, context, tags)
|
|
125
|
+
VALUES ('delete', OLD.rowid, OLD.content, OLD.context, OLD.tags);
|
|
126
|
+
INSERT INTO memories_fts(rowid, content, context, tags)
|
|
127
|
+
VALUES (NEW.rowid, NEW.content, NEW.context, NEW.tags);
|
|
128
|
+
END;
|
|
129
|
+
|
|
130
|
+
-- Memory Relationships
|
|
131
|
+
CREATE TABLE IF NOT EXISTS memory_relationships (
|
|
132
|
+
id TEXT PRIMARY KEY,
|
|
133
|
+
source_memory_id TEXT NOT NULL,
|
|
134
|
+
target_memory_id TEXT NOT NULL,
|
|
135
|
+
relationship_type TEXT NOT NULL, -- related_to, supersedes, derived_from, contradicts
|
|
136
|
+
strength REAL DEFAULT 1.0,
|
|
137
|
+
created_at TEXT NOT NULL,
|
|
138
|
+
metadata TEXT,
|
|
139
|
+
FOREIGN KEY (source_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
140
|
+
FOREIGN KEY (target_memory_id) REFERENCES memories(id) ON DELETE CASCADE,
|
|
141
|
+
UNIQUE(source_memory_id, target_memory_id, relationship_type)
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
-- Activity-Memory Links
|
|
145
|
+
CREATE TABLE IF NOT EXISTS activity_memory_links (
|
|
146
|
+
activity_id TEXT NOT NULL,
|
|
147
|
+
memory_id TEXT NOT NULL,
|
|
148
|
+
link_type TEXT NOT NULL, -- created, accessed, updated, referenced
|
|
149
|
+
created_at TEXT NOT NULL,
|
|
150
|
+
PRIMARY KEY (activity_id, memory_id, link_type),
|
|
151
|
+
FOREIGN KEY (activity_id) REFERENCES activities(id) ON DELETE CASCADE,
|
|
152
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
-- Embeddings
|
|
156
|
+
CREATE TABLE IF NOT EXISTS embeddings (
|
|
157
|
+
id TEXT PRIMARY KEY,
|
|
158
|
+
memory_id TEXT NOT NULL UNIQUE,
|
|
159
|
+
model_name TEXT NOT NULL, -- 'all-MiniLM-L6-v2'
|
|
160
|
+
vector BLOB NOT NULL, -- float32 array
|
|
161
|
+
dimensions INTEGER NOT NULL, -- 384
|
|
162
|
+
created_at TEXT NOT NULL,
|
|
163
|
+
FOREIGN KEY (memory_id) REFERENCES memories(id) ON DELETE CASCADE
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
-- Session Summaries
|
|
167
|
+
CREATE TABLE IF NOT EXISTS session_summaries (
|
|
168
|
+
id TEXT PRIMARY KEY,
|
|
169
|
+
session_id TEXT NOT NULL UNIQUE,
|
|
170
|
+
key_learnings TEXT, -- JSON array
|
|
171
|
+
key_decisions TEXT, -- JSON array
|
|
172
|
+
key_errors TEXT, -- JSON array
|
|
173
|
+
files_modified TEXT, -- JSON array
|
|
174
|
+
tools_used TEXT, -- JSON object
|
|
175
|
+
total_activities INTEGER DEFAULT 0,
|
|
176
|
+
total_memories_created INTEGER DEFAULT 0,
|
|
177
|
+
created_at TEXT NOT NULL,
|
|
178
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
-- Configuration
|
|
182
|
+
CREATE TABLE IF NOT EXISTS config (
|
|
183
|
+
key TEXT PRIMARY KEY,
|
|
184
|
+
value TEXT NOT NULL,
|
|
185
|
+
updated_at TEXT NOT NULL
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
-- Schema Migrations
|
|
189
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
190
|
+
version TEXT PRIMARY KEY,
|
|
191
|
+
applied_at TEXT NOT NULL
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
-- Indexes
|
|
195
|
+
CREATE INDEX IF NOT EXISTS idx_activities_session ON activities(session_id);
|
|
196
|
+
CREATE INDEX IF NOT EXISTS idx_activities_agent ON activities(agent_id);
|
|
197
|
+
CREATE INDEX IF NOT EXISTS idx_activities_timestamp ON activities(timestamp DESC);
|
|
198
|
+
CREATE INDEX IF NOT EXISTS idx_activities_tool ON activities(tool_name);
|
|
199
|
+
CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
|
|
200
|
+
CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status);
|
|
201
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project ON memories(project_path);
|
|
202
|
+
CREATE INDEX IF NOT EXISTS idx_memories_importance ON memories(importance_score DESC);
|
|
203
|
+
CREATE INDEX IF NOT EXISTS idx_memories_accessed ON memories(last_accessed DESC);
|
|
204
|
+
CREATE INDEX IF NOT EXISTS idx_memories_created ON memories(created_at DESC);
|
|
205
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_source ON memory_relationships(source_memory_id);
|
|
206
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_target ON memory_relationships(target_memory_id);
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def get_schema_sql() -> str:
|
|
211
|
+
"""Get the complete schema SQL."""
|
|
212
|
+
return SCHEMA_SQL
|