omni-cortex 1.17.0__py3-none-any.whl → 1.17.2__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.
Files changed (66) hide show
  1. omni_cortex/__init__.py +3 -0
  2. omni_cortex/categorization/__init__.py +9 -0
  3. omni_cortex/categorization/auto_tags.py +166 -0
  4. omni_cortex/categorization/auto_type.py +165 -0
  5. omni_cortex/config.py +141 -0
  6. omni_cortex/dashboard.py +232 -0
  7. omni_cortex/database/__init__.py +24 -0
  8. omni_cortex/database/connection.py +137 -0
  9. omni_cortex/database/migrations.py +210 -0
  10. omni_cortex/database/schema.py +212 -0
  11. omni_cortex/database/sync.py +421 -0
  12. omni_cortex/decay/__init__.py +7 -0
  13. omni_cortex/decay/importance.py +147 -0
  14. omni_cortex/embeddings/__init__.py +35 -0
  15. omni_cortex/embeddings/local.py +442 -0
  16. omni_cortex/models/__init__.py +20 -0
  17. omni_cortex/models/activity.py +265 -0
  18. omni_cortex/models/agent.py +144 -0
  19. omni_cortex/models/memory.py +395 -0
  20. omni_cortex/models/relationship.py +206 -0
  21. omni_cortex/models/session.py +290 -0
  22. omni_cortex/resources/__init__.py +1 -0
  23. omni_cortex/search/__init__.py +22 -0
  24. omni_cortex/search/hybrid.py +197 -0
  25. omni_cortex/search/keyword.py +204 -0
  26. omni_cortex/search/ranking.py +127 -0
  27. omni_cortex/search/semantic.py +232 -0
  28. omni_cortex/server.py +360 -0
  29. omni_cortex/setup.py +278 -0
  30. omni_cortex/tools/__init__.py +13 -0
  31. omni_cortex/tools/activities.py +453 -0
  32. omni_cortex/tools/memories.py +536 -0
  33. omni_cortex/tools/sessions.py +311 -0
  34. omni_cortex/tools/utilities.py +477 -0
  35. omni_cortex/utils/__init__.py +13 -0
  36. omni_cortex/utils/formatting.py +282 -0
  37. omni_cortex/utils/ids.py +72 -0
  38. omni_cortex/utils/timestamps.py +129 -0
  39. omni_cortex/utils/truncation.py +111 -0
  40. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/main.py +43 -13
  41. {omni_cortex-1.17.0.dist-info → omni_cortex-1.17.2.dist-info}/METADATA +1 -1
  42. omni_cortex-1.17.2.dist-info/RECORD +65 -0
  43. omni_cortex-1.17.0.dist-info/RECORD +0 -26
  44. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
  45. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
  46. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
  47. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
  48. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
  49. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
  50. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
  51. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
  52. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
  53. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
  54. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
  55. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
  56. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
  57. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
  58. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
  59. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
  60. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
  61. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/stop.py +0 -0
  62. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
  63. {omni_cortex-1.17.0.data → omni_cortex-1.17.2.data}/data/share/omni-cortex/hooks/user_prompt.py +0 -0
  64. {omni_cortex-1.17.0.dist-info → omni_cortex-1.17.2.dist-info}/WHEEL +0 -0
  65. {omni_cortex-1.17.0.dist-info → omni_cortex-1.17.2.dist-info}/entry_points.txt +0 -0
  66. {omni_cortex-1.17.0.dist-info → omni_cortex-1.17.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,311 @@
1
+ """Session continuity tools for Omni Cortex MCP."""
2
+
3
+ import json
4
+ from typing import Optional
5
+ from pydantic import BaseModel, Field, ConfigDict
6
+
7
+ from mcp.server.fastmcp import FastMCP
8
+
9
+ from ..database.connection import init_database
10
+ from ..config import get_project_path, get_session_id
11
+ from ..models.session import (
12
+ Session,
13
+ SessionCreate,
14
+ SessionSummary,
15
+ create_session,
16
+ get_session,
17
+ end_session,
18
+ get_recent_sessions,
19
+ get_session_summary,
20
+ )
21
+ from ..models.memory import list_memories
22
+ from ..utils.formatting import format_session_context_markdown
23
+ from ..utils.timestamps import format_relative_time
24
+
25
+
26
+ # === Input Models ===
27
+
28
+ class StartSessionInput(BaseModel):
29
+ """Input for starting a session."""
30
+
31
+ model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True)
32
+
33
+ session_id: Optional[str] = Field(None, description="Custom session ID (auto-generated if not provided)")
34
+ project_path: Optional[str] = Field(None, description="Project path (uses current directory if not provided)")
35
+ provide_context: bool = Field(True, description="Return context from previous sessions")
36
+ context_depth: int = Field(3, description="Number of past sessions to summarize", ge=1, le=10)
37
+
38
+
39
+ class EndSessionInput(BaseModel):
40
+ """Input for ending a session."""
41
+
42
+ model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True)
43
+
44
+ session_id: str = Field(..., description="Session ID to end")
45
+ summary: Optional[str] = Field(None, description="Manual summary (auto-generated if not provided)")
46
+ key_learnings: Optional[list[str]] = Field(None, description="Key learnings from the session")
47
+
48
+
49
+ class SessionContextInput(BaseModel):
50
+ """Input for getting session context."""
51
+
52
+ model_config = ConfigDict(str_strip_whitespace=True, validate_assignment=True)
53
+
54
+ project_path: Optional[str] = Field(None, description="Filter by project path")
55
+ session_count: int = Field(5, description="Number of past sessions to include", ge=1, le=20)
56
+ include_learnings: bool = Field(True, description="Include key learnings")
57
+ include_decisions: bool = Field(True, description="Include key decisions")
58
+ include_errors: bool = Field(True, description="Include errors encountered")
59
+
60
+
61
+ def register_session_tools(mcp: FastMCP) -> None:
62
+ """Register all session tools with the MCP server."""
63
+
64
+ @mcp.tool(
65
+ name="cortex_start_session",
66
+ annotations={
67
+ "title": "Start Session",
68
+ "readOnlyHint": False,
69
+ "destructiveHint": False,
70
+ "idempotentHint": False,
71
+ "openWorldHint": False,
72
+ },
73
+ )
74
+ async def cortex_start_session(params: StartSessionInput) -> str:
75
+ """Start a new session and optionally get context from previous sessions.
76
+
77
+ A session groups related activities and memories. Starting a new session
78
+ establishes context and can provide a summary of what happened before.
79
+
80
+ Args:
81
+ params: StartSessionInput with optional session_id and context settings
82
+
83
+ Returns:
84
+ Session info and context from previous sessions
85
+ """
86
+ try:
87
+ conn = init_database()
88
+ project_path = params.project_path or str(get_project_path())
89
+
90
+ # Create new session
91
+ session_data = SessionCreate(
92
+ session_id=params.session_id,
93
+ project_path=project_path,
94
+ provide_context=params.provide_context,
95
+ context_depth=params.context_depth,
96
+ )
97
+
98
+ session = create_session(conn, session_data)
99
+
100
+ lines = [
101
+ f"# Session Started: {session.id}",
102
+ f"Project: {session.project_path}",
103
+ f"Started: {session.started_at}",
104
+ "",
105
+ ]
106
+
107
+ # Get context from previous sessions if requested
108
+ if params.provide_context:
109
+ recent = get_recent_sessions(
110
+ conn,
111
+ project_path=project_path,
112
+ limit=params.context_depth + 1, # +1 because current session is included
113
+ )
114
+
115
+ # Exclude current session
116
+ past_sessions = [s for s in recent if s.id != session.id]
117
+
118
+ if past_sessions:
119
+ lines.append("## Previous Sessions")
120
+ lines.append("")
121
+
122
+ learnings = []
123
+ decisions = []
124
+ errors = []
125
+
126
+ for prev in past_sessions[:params.context_depth]:
127
+ summary = get_session_summary(conn, prev.id)
128
+ if summary:
129
+ if summary.key_learnings:
130
+ learnings.extend(summary.key_learnings)
131
+ if summary.key_decisions:
132
+ decisions.extend(summary.key_decisions)
133
+ if summary.key_errors:
134
+ errors.extend(summary.key_errors)
135
+
136
+ ended = prev.ended_at
137
+ if ended:
138
+ lines.append(f"- Ended {format_relative_time(ended)}")
139
+ if prev.summary:
140
+ lines.append(f" Summary: {prev.summary[:100]}...")
141
+
142
+ if learnings or decisions or errors:
143
+ lines.append("")
144
+ lines.append(format_session_context_markdown(
145
+ [s.model_dump() for s in past_sessions],
146
+ learnings[:5],
147
+ decisions[:5],
148
+ errors[:5],
149
+ ))
150
+
151
+ return "\n".join(lines)
152
+
153
+ except Exception as e:
154
+ return f"Error starting session: {e}"
155
+
156
+ @mcp.tool(
157
+ name="cortex_end_session",
158
+ annotations={
159
+ "title": "End Session",
160
+ "readOnlyHint": False,
161
+ "destructiveHint": False,
162
+ "idempotentHint": True,
163
+ "openWorldHint": False,
164
+ },
165
+ )
166
+ async def cortex_end_session(params: EndSessionInput) -> str:
167
+ """End a session and generate summary statistics.
168
+
169
+ This closes the session and creates a summary of activities,
170
+ memories created, tools used, and files modified.
171
+
172
+ Args:
173
+ params: EndSessionInput with session_id and optional summary
174
+
175
+ Returns:
176
+ Session summary
177
+ """
178
+ try:
179
+ conn = init_database()
180
+
181
+ session = end_session(
182
+ conn,
183
+ session_id=params.session_id,
184
+ summary=params.summary,
185
+ key_learnings=params.key_learnings,
186
+ )
187
+
188
+ if not session:
189
+ return f"Session not found: {params.session_id}"
190
+
191
+ # Get the summary
192
+ summary = get_session_summary(conn, params.session_id)
193
+
194
+ lines = [
195
+ f"# Session Ended: {session.id}",
196
+ f"Duration: {session.started_at} to {session.ended_at}",
197
+ "",
198
+ ]
199
+
200
+ if summary:
201
+ lines.append(f"## Statistics")
202
+ lines.append(f"- Total activities: {summary.total_activities}")
203
+ lines.append(f"- Memories created: {summary.total_memories_created}")
204
+
205
+ if summary.tools_used:
206
+ lines.append(f"- Tools used: {len(summary.tools_used)}")
207
+ for tool, count in list(summary.tools_used.items())[:5]:
208
+ lines.append(f" - {tool}: {count} calls")
209
+
210
+ if summary.files_modified:
211
+ lines.append(f"- Files modified: {len(summary.files_modified)}")
212
+
213
+ if summary.key_errors:
214
+ lines.append(f"- Errors encountered: {len(summary.key_errors)}")
215
+
216
+ if session.summary:
217
+ lines.append("")
218
+ lines.append(f"## Summary")
219
+ lines.append(session.summary)
220
+
221
+ return "\n".join(lines)
222
+
223
+ except Exception as e:
224
+ return f"Error ending session: {e}"
225
+
226
+ @mcp.tool(
227
+ name="cortex_get_session_context",
228
+ annotations={
229
+ "title": "Get Session Context",
230
+ "readOnlyHint": True,
231
+ "destructiveHint": False,
232
+ "idempotentHint": True,
233
+ "openWorldHint": False,
234
+ },
235
+ )
236
+ async def cortex_get_session_context(params: SessionContextInput) -> str:
237
+ """Get context from previous sessions for continuity.
238
+
239
+ This provides a "Last time you were working on..." summary
240
+ to help resume work on a project.
241
+
242
+ Args:
243
+ params: SessionContextInput with filters
244
+
245
+ Returns:
246
+ Context summary from previous sessions
247
+ """
248
+ try:
249
+ conn = init_database()
250
+ project_path = params.project_path or str(get_project_path())
251
+
252
+ recent = get_recent_sessions(
253
+ conn,
254
+ project_path=project_path,
255
+ limit=params.session_count,
256
+ )
257
+
258
+ if not recent:
259
+ return "No previous sessions found for this project."
260
+
261
+ learnings = []
262
+ decisions = []
263
+ errors = []
264
+
265
+ for session in recent:
266
+ summary = get_session_summary(conn, session.id)
267
+ if summary:
268
+ if params.include_learnings and summary.key_learnings:
269
+ learnings.extend(summary.key_learnings)
270
+ if params.include_decisions and summary.key_decisions:
271
+ decisions.extend(summary.key_decisions)
272
+ if params.include_errors and summary.key_errors:
273
+ errors.extend(summary.key_errors)
274
+
275
+ # Get recent important memories
276
+ memories_result, _ = list_memories(
277
+ conn,
278
+ sort_by="importance_score",
279
+ sort_order="desc",
280
+ limit=5,
281
+ )
282
+
283
+ lines = []
284
+
285
+ # Opening context
286
+ if recent:
287
+ last = recent[0]
288
+ if last.ended_at:
289
+ lines.append(f"Last session ended {format_relative_time(last.ended_at)}.")
290
+ if last.summary:
291
+ lines.append(f"Summary: {last.summary}")
292
+ lines.append("")
293
+
294
+ # Add formatted context
295
+ lines.append(format_session_context_markdown(
296
+ [s.model_dump() for s in recent],
297
+ learnings[:5],
298
+ decisions[:5],
299
+ errors[:5],
300
+ ))
301
+
302
+ # Add important memories
303
+ if memories_result:
304
+ lines.append("## Important Memories")
305
+ for mem in memories_result[:3]:
306
+ lines.append(f"- [{mem.type}] {mem.content[:100]}...")
307
+
308
+ return "\n".join(lines)
309
+
310
+ except Exception as e:
311
+ return f"Error getting session context: {e}"