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.
Files changed (60) hide show
  1. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/PKG-INFO +1 -1
  2. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/chat_service.py +1 -1
  3. omni_cortex-1.0.7/dashboard/backend/logging_config.py +92 -0
  4. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/main.py +80 -45
  5. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/pyproject.toml +1 -1
  6. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/.gitignore +0 -0
  7. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/LICENSE +0 -0
  8. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/README.md +0 -0
  9. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/database.py +0 -0
  10. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/models.py +0 -0
  11. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/project_scanner.py +0 -0
  12. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/pyproject.toml +0 -0
  13. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/uv.lock +0 -0
  14. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/dashboard/backend/websocket_manager.py +0 -0
  15. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/post_tool_use.py +0 -0
  16. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/pre_tool_use.py +0 -0
  17. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/stop.py +0 -0
  18. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/hooks/subagent_stop.py +0 -0
  19. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/__init__.py +0 -0
  20. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/__init__.py +0 -0
  21. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/auto_tags.py +0 -0
  22. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/categorization/auto_type.py +0 -0
  23. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/config.py +0 -0
  24. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/dashboard.py +0 -0
  25. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/__init__.py +0 -0
  26. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/connection.py +0 -0
  27. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/migrations.py +0 -0
  28. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/schema.py +0 -0
  29. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/database/sync.py +0 -0
  30. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/decay/__init__.py +0 -0
  31. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/decay/importance.py +0 -0
  32. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/embeddings/__init__.py +0 -0
  33. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/embeddings/local.py +0 -0
  34. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/__init__.py +0 -0
  35. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/activity.py +0 -0
  36. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/agent.py +0 -0
  37. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/memory.py +0 -0
  38. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/relationship.py +0 -0
  39. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/models/session.py +0 -0
  40. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/resources/__init__.py +0 -0
  41. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/__init__.py +0 -0
  42. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/hybrid.py +0 -0
  43. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/keyword.py +0 -0
  44. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/ranking.py +0 -0
  45. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/search/semantic.py +0 -0
  46. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/server.py +0 -0
  47. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/setup.py +0 -0
  48. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/__init__.py +0 -0
  49. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/activities.py +0 -0
  50. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/memories.py +0 -0
  51. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/sessions.py +0 -0
  52. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/tools/utilities.py +0 -0
  53. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/__init__.py +0 -0
  54. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/formatting.py +0 -0
  55. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/ids.py +0 -0
  56. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/timestamps.py +0 -0
  57. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/omni_cortex/utils/truncation.py +0 -0
  58. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/scripts/import_ken_memories.py +0 -0
  59. {omni_cortex-1.0.5 → omni_cortex-1.0.7}/scripts/populate_session_data.py +0 -0
  60. {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.5
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-2.0-flash-exp")
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
- if not Path(project).exists():
164
- raise HTTPException(status_code=404, detail="Database not found")
165
-
166
- filters = FilterParams(
167
- memory_type=memory_type,
168
- status=status,
169
- tags=tags.split(",") if tags else None,
170
- search=search,
171
- min_importance=min_importance,
172
- max_importance=max_importance,
173
- sort_by=sort_by,
174
- sort_order=sort_order,
175
- limit=limit,
176
- offset=offset,
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
- return get_memories(project, filters)
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
- if not Path(project).exists():
241
- raise HTTPException(status_code=404, detail="Database not found")
242
-
243
- updated = update_memory(project, memory_id, updates)
244
- if not updated:
245
- raise HTTPException(status_code=404, detail="Memory not found")
246
-
247
- # Notify connected clients
248
- await manager.broadcast("memory_updated", updated.model_dump(by_alias=True))
249
- return updated
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
- if not Path(project).exists():
259
- raise HTTPException(status_code=404, detail="Database not found")
260
-
261
- deleted = delete_memory(project, memory_id)
262
- if not deleted:
263
- raise HTTPException(status_code=404, detail="Memory not found")
264
-
265
- # Notify connected clients
266
- await manager.broadcast("memory_deleted", {"id": memory_id})
267
- return {"message": "Memory deleted", "id": memory_id}
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
- if not Path(project).exists():
458
- raise HTTPException(status_code=404, detail="Database not found")
459
-
460
- result = await chat_service.ask_about_memories(
461
- project,
462
- request.question,
463
- request.max_memories,
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
- return ChatResponse(**result)
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 ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "omni-cortex"
7
- version = "1.0.5"
7
+ version = "1.0.7"
8
8
  description = "Universal Memory MCP for Claude Code - dual-layer activity logging and knowledge storage"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes
File without changes
File without changes