omni-cortex 1.0.5__tar.gz → 1.0.7__tar.gz
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-1.0.5 → omni_cortex-1.0.7}/PKG-INFO +1 -1
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/chat_service.py +1 -1
- omni_cortex-1.0.7/dashboard/backend/logging_config.py +92 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/main.py +80 -45
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/pyproject.toml +1 -1
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/.gitignore +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/LICENSE +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/README.md +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/database.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/models.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/project_scanner.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/pyproject.toml +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/uv.lock +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/websocket_manager.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/post_tool_use.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/pre_tool_use.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/stop.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/subagent_stop.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/auto_tags.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/auto_type.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/config.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/dashboard.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/connection.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/migrations.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/schema.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/sync.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/decay/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/decay/importance.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/embeddings/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/embeddings/local.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/activity.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/agent.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/memory.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/relationship.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/session.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/resources/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/hybrid.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/keyword.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/ranking.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/semantic.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/server.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/setup.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/activities.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/memories.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/sessions.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/utilities.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/__init__.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/formatting.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/ids.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/timestamps.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/truncation.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/scripts/import_ken_memories.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/scripts/populate_session_data.py +0 -0
- {omni_cortex-1.0.5 → omni_cortex-1.0.7}/scripts/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: omni-cortex
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: Universal Memory MCP for Claude Code - dual-layer activity logging and knowledge storage
|
|
5
5
|
Project-URL: Homepage, https://github.com/AllCytes/Omni-Cortex
|
|
6
6
|
Project-URL: Repository, https://github.com/AllCytes/Omni-Cortex
|
|
@@ -22,7 +22,7 @@ def get_model() -> Optional[genai.GenerativeModel]:
|
|
|
22
22
|
global _model
|
|
23
23
|
if _model is None and _api_key:
|
|
24
24
|
genai.configure(api_key=_api_key)
|
|
25
|
-
_model = genai.GenerativeModel("gemini-
|
|
25
|
+
_model = genai.GenerativeModel("gemini-3-flash-preview")
|
|
26
26
|
return _model
|
|
27
27
|
|
|
28
28
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Logging configuration for Omni-Cortex Dashboard.
|
|
2
|
+
|
|
3
|
+
Following IndyDevDan's logging philosophy:
|
|
4
|
+
- Agent visibility through structured stdout
|
|
5
|
+
- [SUCCESS] and [ERROR] prefixes for machine parsing
|
|
6
|
+
- Key metrics in success logs
|
|
7
|
+
- Full tracebacks in error logs
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
import sys
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StructuredFormatter(logging.Formatter):
|
|
16
|
+
"""Custom formatter for structured agent-readable logs."""
|
|
17
|
+
|
|
18
|
+
def format(self, record):
|
|
19
|
+
# Format: [YYYY-MM-DD HH:MM:SS] [LEVEL] message
|
|
20
|
+
timestamp = datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S")
|
|
21
|
+
level = record.levelname
|
|
22
|
+
message = record.getMessage()
|
|
23
|
+
|
|
24
|
+
# Add exception info if present
|
|
25
|
+
if record.exc_info:
|
|
26
|
+
import traceback
|
|
27
|
+
exc_text = ''.join(traceback.format_exception(*record.exc_info))
|
|
28
|
+
message = f"{message}\n[ERROR] Traceback:\n{exc_text}"
|
|
29
|
+
|
|
30
|
+
return f"[{timestamp}] [{level}] {message}"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def setup_logging():
|
|
34
|
+
"""Configure logging for dashboard backend."""
|
|
35
|
+
# Get or create logger
|
|
36
|
+
logger = logging.getLogger("omni_cortex_dashboard")
|
|
37
|
+
|
|
38
|
+
# Avoid duplicate handlers
|
|
39
|
+
if logger.handlers:
|
|
40
|
+
return logger
|
|
41
|
+
|
|
42
|
+
logger.setLevel(logging.INFO)
|
|
43
|
+
|
|
44
|
+
# Console handler with structured formatting
|
|
45
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
46
|
+
console_handler.setLevel(logging.INFO)
|
|
47
|
+
console_handler.setFormatter(StructuredFormatter())
|
|
48
|
+
|
|
49
|
+
logger.addHandler(console_handler)
|
|
50
|
+
|
|
51
|
+
return logger
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Create global logger instance
|
|
55
|
+
logger = setup_logging()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def log_success(endpoint: str, **metrics):
|
|
59
|
+
"""Log a successful operation with key metrics.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
endpoint: API endpoint (e.g., "/api/memories")
|
|
63
|
+
**metrics: Key-value pairs of metrics to log
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
log_success("/api/memories", count=150, time_ms=45)
|
|
67
|
+
# Output: [SUCCESS] /api/memories - count=150, time_ms=45
|
|
68
|
+
"""
|
|
69
|
+
metric_str = ", ".join(f"{k}={v}" for k, v in metrics.items())
|
|
70
|
+
logger.info(f"[SUCCESS] {endpoint} - {metric_str}")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def log_error(endpoint: str, exception: Exception, **context):
|
|
74
|
+
"""Log an error with exception details and context.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
endpoint: API endpoint (e.g., "/api/memories")
|
|
78
|
+
exception: The exception that occurred
|
|
79
|
+
**context: Additional context key-value pairs
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
log_error("/api/memories", exc, project="path/to/db")
|
|
83
|
+
# Output includes exception type, message, and full traceback
|
|
84
|
+
"""
|
|
85
|
+
context_str = ", ".join(f"{k}={v}" for k, v in context.items()) if context else ""
|
|
86
|
+
error_msg = f"[ERROR] {endpoint} - Exception: {type(exception).__name__}"
|
|
87
|
+
if context_str:
|
|
88
|
+
error_msg += f" - {context_str}"
|
|
89
|
+
error_msg += f"\n[ERROR] Details: {str(exception)}"
|
|
90
|
+
|
|
91
|
+
# Log with exception info to include traceback
|
|
92
|
+
logger.error(error_msg, exc_info=True)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import json
|
|
6
|
+
import traceback
|
|
6
7
|
from contextlib import asynccontextmanager
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from pathlib import Path
|
|
@@ -37,6 +38,7 @@ from database import (
|
|
|
37
38
|
search_memories,
|
|
38
39
|
update_memory,
|
|
39
40
|
)
|
|
41
|
+
from logging_config import log_success, log_error
|
|
40
42
|
from models import ChatRequest, ChatResponse, FilterParams, MemoryUpdate, ProjectInfo
|
|
41
43
|
from project_scanner import scan_projects
|
|
42
44
|
from websocket_manager import manager
|
|
@@ -160,23 +162,30 @@ async def list_memories(
|
|
|
160
162
|
offset: int = 0,
|
|
161
163
|
):
|
|
162
164
|
"""Get memories with filtering and pagination."""
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
try:
|
|
166
|
+
if not Path(project).exists():
|
|
167
|
+
log_error("/api/memories", FileNotFoundError("Database not found"), project=project)
|
|
168
|
+
raise HTTPException(status_code=404, detail="Database not found")
|
|
169
|
+
|
|
170
|
+
filters = FilterParams(
|
|
171
|
+
memory_type=memory_type,
|
|
172
|
+
status=status,
|
|
173
|
+
tags=tags.split(",") if tags else None,
|
|
174
|
+
search=search,
|
|
175
|
+
min_importance=min_importance,
|
|
176
|
+
max_importance=max_importance,
|
|
177
|
+
sort_by=sort_by,
|
|
178
|
+
sort_order=sort_order,
|
|
179
|
+
limit=limit,
|
|
180
|
+
offset=offset,
|
|
181
|
+
)
|
|
178
182
|
|
|
179
|
-
|
|
183
|
+
memories = get_memories(project, filters)
|
|
184
|
+
log_success("/api/memories", count=len(memories), offset=offset, filters=bool(search or memory_type))
|
|
185
|
+
return memories
|
|
186
|
+
except Exception as e:
|
|
187
|
+
log_error("/api/memories", e, project=project)
|
|
188
|
+
raise
|
|
180
189
|
|
|
181
190
|
|
|
182
191
|
# NOTE: These routes MUST be defined before /api/memories/{memory_id} to avoid path conflicts
|
|
@@ -237,16 +246,25 @@ async def update_memory_endpoint(
|
|
|
237
246
|
project: str = Query(..., description="Path to the database file"),
|
|
238
247
|
):
|
|
239
248
|
"""Update a memory."""
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
try:
|
|
250
|
+
if not Path(project).exists():
|
|
251
|
+
log_error("/api/memories/update", FileNotFoundError("Database not found"), memory_id=memory_id)
|
|
252
|
+
raise HTTPException(status_code=404, detail="Database not found")
|
|
253
|
+
|
|
254
|
+
updated = update_memory(project, memory_id, updates)
|
|
255
|
+
if not updated:
|
|
256
|
+
log_error("/api/memories/update", ValueError("Memory not found"), memory_id=memory_id)
|
|
257
|
+
raise HTTPException(status_code=404, detail="Memory not found")
|
|
258
|
+
|
|
259
|
+
# Notify connected clients
|
|
260
|
+
await manager.broadcast("memory_updated", updated.model_dump(by_alias=True))
|
|
261
|
+
log_success("/api/memories/update", memory_id=memory_id, fields_updated=len(updates.model_dump(exclude_unset=True)))
|
|
262
|
+
return updated
|
|
263
|
+
except HTTPException:
|
|
264
|
+
raise
|
|
265
|
+
except Exception as e:
|
|
266
|
+
log_error("/api/memories/update", e, memory_id=memory_id)
|
|
267
|
+
raise
|
|
250
268
|
|
|
251
269
|
|
|
252
270
|
@app.delete("/api/memories/{memory_id}")
|
|
@@ -255,16 +273,25 @@ async def delete_memory_endpoint(
|
|
|
255
273
|
project: str = Query(..., description="Path to the database file"),
|
|
256
274
|
):
|
|
257
275
|
"""Delete a memory."""
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
try:
|
|
277
|
+
if not Path(project).exists():
|
|
278
|
+
log_error("/api/memories/delete", FileNotFoundError("Database not found"), memory_id=memory_id)
|
|
279
|
+
raise HTTPException(status_code=404, detail="Database not found")
|
|
280
|
+
|
|
281
|
+
deleted = delete_memory(project, memory_id)
|
|
282
|
+
if not deleted:
|
|
283
|
+
log_error("/api/memories/delete", ValueError("Memory not found"), memory_id=memory_id)
|
|
284
|
+
raise HTTPException(status_code=404, detail="Memory not found")
|
|
285
|
+
|
|
286
|
+
# Notify connected clients
|
|
287
|
+
await manager.broadcast("memory_deleted", {"id": memory_id})
|
|
288
|
+
log_success("/api/memories/delete", memory_id=memory_id)
|
|
289
|
+
return {"message": "Memory deleted", "id": memory_id}
|
|
290
|
+
except HTTPException:
|
|
291
|
+
raise
|
|
292
|
+
except Exception as e:
|
|
293
|
+
log_error("/api/memories/delete", e, memory_id=memory_id)
|
|
294
|
+
raise
|
|
268
295
|
|
|
269
296
|
|
|
270
297
|
@app.get("/api/memories/stats/summary")
|
|
@@ -454,16 +481,24 @@ async def chat_with_memories(
|
|
|
454
481
|
project: str = Query(..., description="Path to the database file"),
|
|
455
482
|
):
|
|
456
483
|
"""Ask a natural language question about memories."""
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
484
|
+
try:
|
|
485
|
+
if not Path(project).exists():
|
|
486
|
+
log_error("/api/chat", FileNotFoundError("Database not found"), question=request.question[:50])
|
|
487
|
+
raise HTTPException(status_code=404, detail="Database not found")
|
|
488
|
+
|
|
489
|
+
result = await chat_service.ask_about_memories(
|
|
490
|
+
project,
|
|
491
|
+
request.question,
|
|
492
|
+
request.max_memories,
|
|
493
|
+
)
|
|
465
494
|
|
|
466
|
-
|
|
495
|
+
log_success("/api/chat", question_len=len(request.question), sources=len(result.get("sources", [])))
|
|
496
|
+
return ChatResponse(**result)
|
|
497
|
+
except HTTPException:
|
|
498
|
+
raise
|
|
499
|
+
except Exception as e:
|
|
500
|
+
log_error("/api/chat", e, question=request.question[:50])
|
|
501
|
+
raise
|
|
467
502
|
|
|
468
503
|
|
|
469
504
|
# --- WebSocket Endpoint ---
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|