omni-cortex 1.17.3__py3-none-any.whl → 1.17.5__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/_bundled/dashboard/backend/main.py +2 -2
- omni_cortex/_bundled/dashboard/backend/test_database.py +301 -0
- omni_cortex/_bundled/dashboard/backend/tmpclaude-2dfa-cwd +1 -0
- omni_cortex/_bundled/dashboard/backend/tmpclaude-c460-cwd +1 -0
- omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CQlQK3nE.js +551 -0
- omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CmUNNfe4.css +1 -0
- omni_cortex/_bundled/dashboard/frontend/dist/index.html +14 -0
- omni_cortex/_bundled/hooks/post_tool_use.py +2 -0
- omni_cortex/_bundled/hooks/pre_tool_use.py +2 -0
- omni_cortex/_bundled/hooks/stop.py +2 -0
- omni_cortex/_bundled/hooks/subagent_stop.py +2 -0
- omni_cortex/_bundled/hooks/user_prompt.py +117 -2
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/main.py +2 -2
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/post_tool_use.py +2 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/pre_tool_use.py +2 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/stop.py +2 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/subagent_stop.py +2 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/user_prompt.py +117 -2
- {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/METADATA +6 -1
- omni_cortex-1.17.5.dist-info/RECORD +53 -0
- omni_cortex/__init__.py +0 -3
- omni_cortex/categorization/__init__.py +0 -9
- omni_cortex/categorization/auto_tags.py +0 -166
- omni_cortex/categorization/auto_type.py +0 -165
- omni_cortex/config.py +0 -141
- omni_cortex/dashboard.py +0 -238
- omni_cortex/database/__init__.py +0 -24
- omni_cortex/database/connection.py +0 -137
- omni_cortex/database/migrations.py +0 -210
- omni_cortex/database/schema.py +0 -212
- omni_cortex/database/sync.py +0 -421
- omni_cortex/decay/__init__.py +0 -7
- omni_cortex/decay/importance.py +0 -147
- omni_cortex/embeddings/__init__.py +0 -35
- omni_cortex/embeddings/local.py +0 -442
- omni_cortex/models/__init__.py +0 -20
- omni_cortex/models/activity.py +0 -265
- omni_cortex/models/agent.py +0 -144
- omni_cortex/models/memory.py +0 -395
- omni_cortex/models/relationship.py +0 -206
- omni_cortex/models/session.py +0 -290
- omni_cortex/resources/__init__.py +0 -1
- omni_cortex/search/__init__.py +0 -22
- omni_cortex/search/hybrid.py +0 -197
- omni_cortex/search/keyword.py +0 -204
- omni_cortex/search/ranking.py +0 -127
- omni_cortex/search/semantic.py +0 -232
- omni_cortex/server.py +0 -360
- omni_cortex/setup.py +0 -284
- omni_cortex/tools/__init__.py +0 -13
- omni_cortex/tools/activities.py +0 -453
- omni_cortex/tools/memories.py +0 -536
- omni_cortex/tools/sessions.py +0 -311
- omni_cortex/tools/utilities.py +0 -477
- omni_cortex/utils/__init__.py +0 -13
- omni_cortex/utils/formatting.py +0 -282
- omni_cortex/utils/ids.py +0 -72
- omni_cortex/utils/timestamps.py +0 -129
- omni_cortex/utils/truncation.py +0 -111
- omni_cortex-1.17.3.dist-info/RECORD +0 -86
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
- {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
- {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/WHEEL +0 -0
- {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/entry_points.txt +0 -0
- {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -131,10 +131,10 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
|
|
|
131
131
|
response.headers["Content-Security-Policy"] = (
|
|
132
132
|
"default-src 'self'; "
|
|
133
133
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval'; " # Vue needs these
|
|
134
|
-
"style-src 'self' 'unsafe-inline'; " # Tailwind
|
|
134
|
+
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " # Tailwind + Google Fonts
|
|
135
135
|
"img-src 'self' data: blob: https:; " # Allow AI-generated images
|
|
136
136
|
"connect-src 'self' ws: wss: https://generativelanguage.googleapis.com; "
|
|
137
|
-
"font-src 'self'; "
|
|
137
|
+
"font-src 'self' https://fonts.gstatic.com; " # Google Fonts
|
|
138
138
|
"frame-ancestors 'none';"
|
|
139
139
|
)
|
|
140
140
|
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""Unit tests for dashboard database functions.
|
|
2
|
+
|
|
3
|
+
Run with: cd dashboard/backend && .venv/Scripts/python -m pytest test_database.py -v
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import sqlite3
|
|
9
|
+
import tempfile
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from database import create_memory, get_memories
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def test_db():
|
|
19
|
+
"""Create a temporary database with the required schema."""
|
|
20
|
+
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
|
21
|
+
db_path = f.name
|
|
22
|
+
|
|
23
|
+
# Create the database schema
|
|
24
|
+
conn = sqlite3.connect(db_path)
|
|
25
|
+
conn.execute("""
|
|
26
|
+
CREATE TABLE memories (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
content TEXT NOT NULL,
|
|
29
|
+
context TEXT,
|
|
30
|
+
type TEXT DEFAULT 'other',
|
|
31
|
+
status TEXT DEFAULT 'fresh',
|
|
32
|
+
importance_score INTEGER DEFAULT 50,
|
|
33
|
+
access_count INTEGER DEFAULT 0,
|
|
34
|
+
created_at TEXT NOT NULL,
|
|
35
|
+
last_accessed TEXT NOT NULL,
|
|
36
|
+
updated_at TEXT NOT NULL,
|
|
37
|
+
tags TEXT
|
|
38
|
+
)
|
|
39
|
+
""")
|
|
40
|
+
conn.execute("""
|
|
41
|
+
CREATE TABLE memory_relationships (
|
|
42
|
+
source_memory_id TEXT NOT NULL,
|
|
43
|
+
target_memory_id TEXT NOT NULL,
|
|
44
|
+
relationship_type TEXT NOT NULL,
|
|
45
|
+
strength REAL DEFAULT 0.5,
|
|
46
|
+
PRIMARY KEY (source_memory_id, target_memory_id)
|
|
47
|
+
)
|
|
48
|
+
""")
|
|
49
|
+
conn.commit()
|
|
50
|
+
conn.close()
|
|
51
|
+
|
|
52
|
+
yield db_path
|
|
53
|
+
|
|
54
|
+
# Cleanup
|
|
55
|
+
os.unlink(db_path)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TestCreateMemory:
|
|
59
|
+
"""Tests for the create_memory function."""
|
|
60
|
+
|
|
61
|
+
def test_create_memory_basic(self, test_db):
|
|
62
|
+
"""Test basic memory creation with minimal fields."""
|
|
63
|
+
memory_id = create_memory(
|
|
64
|
+
db_path=test_db,
|
|
65
|
+
content="Test memory content",
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
assert memory_id is not None
|
|
69
|
+
assert memory_id.startswith("mem_")
|
|
70
|
+
|
|
71
|
+
def test_create_memory_with_type(self, test_db):
|
|
72
|
+
"""Test memory creation with custom type."""
|
|
73
|
+
memory_id = create_memory(
|
|
74
|
+
db_path=test_db,
|
|
75
|
+
content="A decision was made",
|
|
76
|
+
memory_type="decision",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Verify the type was saved
|
|
80
|
+
conn = sqlite3.connect(test_db)
|
|
81
|
+
conn.row_factory = sqlite3.Row
|
|
82
|
+
row = conn.execute(
|
|
83
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
84
|
+
).fetchone()
|
|
85
|
+
conn.close()
|
|
86
|
+
|
|
87
|
+
assert row["type"] == "decision"
|
|
88
|
+
|
|
89
|
+
def test_create_memory_with_tags(self, test_db):
|
|
90
|
+
"""Test memory creation with tags."""
|
|
91
|
+
tags = ["python", "testing", "database"]
|
|
92
|
+
memory_id = create_memory(
|
|
93
|
+
db_path=test_db,
|
|
94
|
+
content="Tagged memory",
|
|
95
|
+
tags=tags,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Verify tags were saved as JSON
|
|
99
|
+
conn = sqlite3.connect(test_db)
|
|
100
|
+
conn.row_factory = sqlite3.Row
|
|
101
|
+
row = conn.execute(
|
|
102
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
103
|
+
).fetchone()
|
|
104
|
+
conn.close()
|
|
105
|
+
|
|
106
|
+
saved_tags = json.loads(row["tags"])
|
|
107
|
+
assert saved_tags == tags
|
|
108
|
+
|
|
109
|
+
def test_create_memory_with_importance(self, test_db):
|
|
110
|
+
"""Test memory creation with custom importance score."""
|
|
111
|
+
memory_id = create_memory(
|
|
112
|
+
db_path=test_db,
|
|
113
|
+
content="Important memory",
|
|
114
|
+
importance_score=95,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
conn = sqlite3.connect(test_db)
|
|
118
|
+
conn.row_factory = sqlite3.Row
|
|
119
|
+
row = conn.execute(
|
|
120
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
121
|
+
).fetchone()
|
|
122
|
+
conn.close()
|
|
123
|
+
|
|
124
|
+
assert row["importance_score"] == 95
|
|
125
|
+
|
|
126
|
+
def test_create_memory_has_updated_at(self, test_db):
|
|
127
|
+
"""Test that created memory has updated_at field (regression test for bug)."""
|
|
128
|
+
memory_id = create_memory(
|
|
129
|
+
db_path=test_db,
|
|
130
|
+
content="Memory with updated_at",
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
conn = sqlite3.connect(test_db)
|
|
134
|
+
conn.row_factory = sqlite3.Row
|
|
135
|
+
row = conn.execute(
|
|
136
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
137
|
+
).fetchone()
|
|
138
|
+
conn.close()
|
|
139
|
+
|
|
140
|
+
# This was the bug - updated_at was missing from INSERT
|
|
141
|
+
assert row["updated_at"] is not None
|
|
142
|
+
assert len(row["updated_at"]) > 0
|
|
143
|
+
|
|
144
|
+
def test_create_memory_with_context(self, test_db):
|
|
145
|
+
"""Test memory creation with context."""
|
|
146
|
+
memory_id = create_memory(
|
|
147
|
+
db_path=test_db,
|
|
148
|
+
content="Memory with context",
|
|
149
|
+
context="This is additional context",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
conn = sqlite3.connect(test_db)
|
|
153
|
+
conn.row_factory = sqlite3.Row
|
|
154
|
+
row = conn.execute(
|
|
155
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
156
|
+
).fetchone()
|
|
157
|
+
conn.close()
|
|
158
|
+
|
|
159
|
+
assert row["context"] == "This is additional context"
|
|
160
|
+
|
|
161
|
+
def test_create_memory_default_status_is_fresh(self, test_db):
|
|
162
|
+
"""Test that new memories have 'fresh' status by default."""
|
|
163
|
+
memory_id = create_memory(
|
|
164
|
+
db_path=test_db,
|
|
165
|
+
content="Fresh memory",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
conn = sqlite3.connect(test_db)
|
|
169
|
+
conn.row_factory = sqlite3.Row
|
|
170
|
+
row = conn.execute(
|
|
171
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
172
|
+
).fetchone()
|
|
173
|
+
conn.close()
|
|
174
|
+
|
|
175
|
+
assert row["status"] == "fresh"
|
|
176
|
+
|
|
177
|
+
def test_create_memory_default_access_count_is_zero(self, test_db):
|
|
178
|
+
"""Test that new memories have access_count of 0."""
|
|
179
|
+
memory_id = create_memory(
|
|
180
|
+
db_path=test_db,
|
|
181
|
+
content="New memory",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
conn = sqlite3.connect(test_db)
|
|
185
|
+
conn.row_factory = sqlite3.Row
|
|
186
|
+
row = conn.execute(
|
|
187
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
188
|
+
).fetchone()
|
|
189
|
+
conn.close()
|
|
190
|
+
|
|
191
|
+
assert row["access_count"] == 0
|
|
192
|
+
|
|
193
|
+
def test_create_memory_all_fields(self, test_db):
|
|
194
|
+
"""Test memory creation with all fields populated."""
|
|
195
|
+
memory_id = create_memory(
|
|
196
|
+
db_path=test_db,
|
|
197
|
+
content="Complete memory",
|
|
198
|
+
memory_type="solution",
|
|
199
|
+
context="Full context here",
|
|
200
|
+
tags=["tag1", "tag2"],
|
|
201
|
+
importance_score=80,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
conn = sqlite3.connect(test_db)
|
|
205
|
+
conn.row_factory = sqlite3.Row
|
|
206
|
+
row = conn.execute(
|
|
207
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
208
|
+
).fetchone()
|
|
209
|
+
conn.close()
|
|
210
|
+
|
|
211
|
+
assert row["content"] == "Complete memory"
|
|
212
|
+
assert row["type"] == "solution"
|
|
213
|
+
assert row["context"] == "Full context here"
|
|
214
|
+
assert json.loads(row["tags"]) == ["tag1", "tag2"]
|
|
215
|
+
assert row["importance_score"] == 80
|
|
216
|
+
assert row["status"] == "fresh"
|
|
217
|
+
assert row["access_count"] == 0
|
|
218
|
+
assert row["created_at"] is not None
|
|
219
|
+
assert row["last_accessed"] is not None
|
|
220
|
+
assert row["updated_at"] is not None
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class TestCreateMemoryEdgeCases:
|
|
224
|
+
"""Edge case tests for create_memory."""
|
|
225
|
+
|
|
226
|
+
def test_create_memory_empty_tags_list(self, test_db):
|
|
227
|
+
"""Test memory creation with empty tags list.
|
|
228
|
+
|
|
229
|
+
Note: Current behavior stores empty list as None (falsy check in code).
|
|
230
|
+
This is intentional - empty tags are treated same as no tags.
|
|
231
|
+
"""
|
|
232
|
+
memory_id = create_memory(
|
|
233
|
+
db_path=test_db,
|
|
234
|
+
content="Memory with empty tags",
|
|
235
|
+
tags=[],
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
conn = sqlite3.connect(test_db)
|
|
239
|
+
conn.row_factory = sqlite3.Row
|
|
240
|
+
row = conn.execute(
|
|
241
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
242
|
+
).fetchone()
|
|
243
|
+
conn.close()
|
|
244
|
+
|
|
245
|
+
# Empty list is treated as None (falsy) in the code
|
|
246
|
+
assert row["tags"] is None
|
|
247
|
+
|
|
248
|
+
def test_create_memory_none_tags(self, test_db):
|
|
249
|
+
"""Test memory creation with None tags (default)."""
|
|
250
|
+
memory_id = create_memory(
|
|
251
|
+
db_path=test_db,
|
|
252
|
+
content="Memory with no tags",
|
|
253
|
+
tags=None,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
conn = sqlite3.connect(test_db)
|
|
257
|
+
conn.row_factory = sqlite3.Row
|
|
258
|
+
row = conn.execute(
|
|
259
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
260
|
+
).fetchone()
|
|
261
|
+
conn.close()
|
|
262
|
+
|
|
263
|
+
assert row["tags"] is None
|
|
264
|
+
|
|
265
|
+
def test_create_memory_unicode_content(self, test_db):
|
|
266
|
+
"""Test memory creation with unicode content."""
|
|
267
|
+
content = "Memory with unicode: 日本語 🚀 émojis"
|
|
268
|
+
memory_id = create_memory(
|
|
269
|
+
db_path=test_db,
|
|
270
|
+
content=content,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
conn = sqlite3.connect(test_db)
|
|
274
|
+
conn.row_factory = sqlite3.Row
|
|
275
|
+
row = conn.execute(
|
|
276
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
277
|
+
).fetchone()
|
|
278
|
+
conn.close()
|
|
279
|
+
|
|
280
|
+
assert row["content"] == content
|
|
281
|
+
|
|
282
|
+
def test_create_memory_long_content(self, test_db):
|
|
283
|
+
"""Test memory creation with very long content."""
|
|
284
|
+
content = "A" * 100000 # 100KB of content
|
|
285
|
+
memory_id = create_memory(
|
|
286
|
+
db_path=test_db,
|
|
287
|
+
content=content,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
conn = sqlite3.connect(test_db)
|
|
291
|
+
conn.row_factory = sqlite3.Row
|
|
292
|
+
row = conn.execute(
|
|
293
|
+
"SELECT * FROM memories WHERE id = ?", (memory_id,)
|
|
294
|
+
).fetchone()
|
|
295
|
+
conn.close()
|
|
296
|
+
|
|
297
|
+
assert len(row["content"]) == 100000
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
if __name__ == "__main__":
|
|
301
|
+
pytest.main([__file__, "-v"])
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/d/Projects/omni-cortex/dashboard/backend
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/d/Projects/omni-cortex/dashboard/backend
|