omni-cortex 1.17.3__py3-none-any.whl → 1.17.4__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 (74) hide show
  1. omni_cortex/_bundled/dashboard/backend/main.py +2 -2
  2. omni_cortex/_bundled/dashboard/backend/test_database.py +301 -0
  3. omni_cortex/_bundled/dashboard/backend/tmpclaude-2dfa-cwd +1 -0
  4. omni_cortex/_bundled/dashboard/backend/tmpclaude-c460-cwd +1 -0
  5. omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CQlQK3nE.js +551 -0
  6. omni_cortex/_bundled/dashboard/frontend/dist/assets/index-CmUNNfe4.css +1 -0
  7. omni_cortex/_bundled/dashboard/frontend/dist/index.html +14 -0
  8. omni_cortex/_bundled/hooks/user_prompt.py +113 -2
  9. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/main.py +2 -2
  10. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/user_prompt.py +113 -2
  11. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/METADATA +6 -1
  12. omni_cortex-1.17.4.dist-info/RECORD +53 -0
  13. omni_cortex/__init__.py +0 -3
  14. omni_cortex/categorization/__init__.py +0 -9
  15. omni_cortex/categorization/auto_tags.py +0 -166
  16. omni_cortex/categorization/auto_type.py +0 -165
  17. omni_cortex/config.py +0 -141
  18. omni_cortex/dashboard.py +0 -238
  19. omni_cortex/database/__init__.py +0 -24
  20. omni_cortex/database/connection.py +0 -137
  21. omni_cortex/database/migrations.py +0 -210
  22. omni_cortex/database/schema.py +0 -212
  23. omni_cortex/database/sync.py +0 -421
  24. omni_cortex/decay/__init__.py +0 -7
  25. omni_cortex/decay/importance.py +0 -147
  26. omni_cortex/embeddings/__init__.py +0 -35
  27. omni_cortex/embeddings/local.py +0 -442
  28. omni_cortex/models/__init__.py +0 -20
  29. omni_cortex/models/activity.py +0 -265
  30. omni_cortex/models/agent.py +0 -144
  31. omni_cortex/models/memory.py +0 -395
  32. omni_cortex/models/relationship.py +0 -206
  33. omni_cortex/models/session.py +0 -290
  34. omni_cortex/resources/__init__.py +0 -1
  35. omni_cortex/search/__init__.py +0 -22
  36. omni_cortex/search/hybrid.py +0 -197
  37. omni_cortex/search/keyword.py +0 -204
  38. omni_cortex/search/ranking.py +0 -127
  39. omni_cortex/search/semantic.py +0 -232
  40. omni_cortex/server.py +0 -360
  41. omni_cortex/setup.py +0 -284
  42. omni_cortex/tools/__init__.py +0 -13
  43. omni_cortex/tools/activities.py +0 -453
  44. omni_cortex/tools/memories.py +0 -536
  45. omni_cortex/tools/sessions.py +0 -311
  46. omni_cortex/tools/utilities.py +0 -477
  47. omni_cortex/utils/__init__.py +0 -13
  48. omni_cortex/utils/formatting.py +0 -282
  49. omni_cortex/utils/ids.py +0 -72
  50. omni_cortex/utils/timestamps.py +0 -129
  51. omni_cortex/utils/truncation.py +0 -111
  52. omni_cortex-1.17.3.dist-info/RECORD +0 -86
  53. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
  54. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
  55. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
  56. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
  57. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
  58. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
  59. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
  60. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
  61. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
  62. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
  63. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
  64. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
  65. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
  66. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
  67. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/post_tool_use.py +0 -0
  68. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/pre_tool_use.py +0 -0
  69. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
  70. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/stop.py +0 -0
  71. {omni_cortex-1.17.3.data → omni_cortex-1.17.4.data}/data/share/omni-cortex/hooks/subagent_stop.py +0 -0
  72. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/WHEEL +0 -0
  73. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/entry_points.txt +0 -0
  74. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,282 +0,0 @@
1
- """Output formatting utilities for Omni Cortex."""
2
-
3
- import json
4
- import re
5
- from html import escape as html_escape
6
- from typing import Any, Optional
7
- from datetime import datetime
8
-
9
- from .timestamps import format_relative_time
10
-
11
-
12
- def xml_escape(text: str) -> str:
13
- """Escape text for safe inclusion in XML-structured outputs.
14
-
15
- Prevents prompt injection by escaping special characters that
16
- could be interpreted as XML/instruction delimiters.
17
- """
18
- return html_escape(text, quote=True)
19
-
20
-
21
- # Known prompt injection patterns
22
- _INJECTION_PATTERNS = [
23
- (r'(?i)(ignore|disregard|forget)\s+(all\s+)?(previous|prior|above)\s+instructions?',
24
- 'instruction override'),
25
- (r'(?i)(new\s+)?system\s+(prompt|instruction|message)',
26
- 'system prompt manipulation'),
27
- (r'(?i)\[/?system\]|\[/?inst\]|<\/?system>|<\/?instruction>',
28
- 'fake delimiter'),
29
- (r'(?i)bypass|jailbreak|DAN|GODMODE',
30
- 'jailbreak signature'),
31
- ]
32
-
33
-
34
- def detect_injection_patterns(content: str) -> list[str]:
35
- """Detect potential prompt injection patterns in content."""
36
- detected = []
37
- for pattern, description in _INJECTION_PATTERNS:
38
- if re.search(pattern, content):
39
- detected.append(description)
40
- return detected
41
-
42
-
43
- def format_memory_markdown(
44
- memory: dict[str, Any],
45
- related_memories: Optional[list[dict[str, Any]]] = None,
46
- ) -> str:
47
- """Format a memory as markdown.
48
-
49
- Args:
50
- memory: Memory dictionary
51
- related_memories: Optional list of related memory dicts with relationship info
52
-
53
- Returns:
54
- Markdown formatted string
55
- """
56
- lines = []
57
-
58
- # Header with ID and type
59
- mem_type = memory.get("type", "general")
60
- lines.append(f"## [{mem_type}] {memory.get('id', 'unknown')}")
61
- lines.append("")
62
-
63
- # Content - XML escape to prevent prompt injection when returned to Claude
64
- content = memory.get("content", "")
65
- # Detect and flag potential injection patterns
66
- injections = detect_injection_patterns(content)
67
- if injections:
68
- lines.append(f"[Security Note: Content contains patterns that may be injection attempts: {', '.join(injections)}]")
69
- lines.append(xml_escape(content))
70
- lines.append("")
71
-
72
- # Metadata
73
- lines.append("---")
74
-
75
- # Tags
76
- tags = memory.get("tags")
77
- if tags:
78
- if isinstance(tags, str):
79
- tags = json.loads(tags)
80
- if tags:
81
- lines.append(f"**Tags:** {', '.join(tags)}")
82
-
83
- # Context - also escape
84
- context = memory.get("context")
85
- if context:
86
- lines.append(f"**Context:** {xml_escape(context)}")
87
-
88
- # Timestamps
89
- created = memory.get("created_at")
90
- if created:
91
- lines.append(f"**Created:** {format_relative_time(created)}")
92
-
93
- accessed = memory.get("last_accessed")
94
- if accessed:
95
- lines.append(f"**Last accessed:** {format_relative_time(accessed)}")
96
-
97
- # Importance
98
- importance = memory.get("importance_score", 50)
99
- lines.append(f"**Importance:** {importance:.0f}/100")
100
-
101
- # Status
102
- status = memory.get("status", "fresh")
103
- lines.append(f"**Status:** {status}")
104
-
105
- # Related memories
106
- if related_memories:
107
- lines.append("")
108
- lines.append("**Related:**")
109
- for related in related_memories[:3]: # Limit to 3
110
- rel_type = related.get("relationship_type", "related_to")
111
- rel_id = related.get("id", "unknown")
112
- rel_content = xml_escape(related.get("content", "")[:50])
113
- lines.append(f" - [{rel_type}] {rel_id}: {rel_content}...")
114
-
115
- return "\n".join(lines)
116
-
117
-
118
- def format_memories_list_markdown(
119
- memories: list[dict[str, Any]],
120
- total: int = 0,
121
- related_map: Optional[dict[str, list[dict[str, Any]]]] = None,
122
- ) -> str:
123
- """Format a list of memories as markdown.
124
-
125
- Args:
126
- memories: List of memory dictionaries
127
- total: Total count (for pagination info)
128
- related_map: Optional dict mapping memory IDs to their related memories
129
-
130
- Returns:
131
- Markdown formatted string
132
- """
133
- if not memories:
134
- return "No memories found."
135
-
136
- lines = []
137
- lines.append(f"# Memories ({len(memories)}" + (f" of {total})" if total > len(memories) else ")"))
138
- lines.append("")
139
-
140
- for memory in memories:
141
- # Get related memories for this memory if available
142
- memory_id = memory.get("id")
143
- related = related_map.get(memory_id) if related_map and memory_id else None
144
- lines.append(format_memory_markdown(memory, related_memories=related))
145
- lines.append("")
146
-
147
- return "\n".join(lines)
148
-
149
-
150
- def format_activity_markdown(activity: dict[str, Any]) -> str:
151
- """Format an activity as markdown.
152
-
153
- Args:
154
- activity: Activity dictionary
155
-
156
- Returns:
157
- Markdown formatted string
158
- """
159
- lines = []
160
-
161
- timestamp = activity.get("timestamp", "")
162
- event_type = activity.get("event_type", "")
163
- tool_name = activity.get("tool_name", "")
164
-
165
- # Header
166
- header = f"**{event_type}**"
167
- if tool_name:
168
- header += f": `{tool_name}`"
169
- lines.append(header)
170
-
171
- lines.append(f" - Time: {format_relative_time(timestamp)}")
172
-
173
- # Success/Error
174
- success = activity.get("success", 1)
175
- if not success:
176
- error = activity.get("error_message", "Unknown error")
177
- lines.append(f" - Status: Failed - {error}")
178
- elif activity.get("duration_ms"):
179
- lines.append(f" - Duration: {activity['duration_ms']}ms")
180
-
181
- return "\n".join(lines)
182
-
183
-
184
- def format_timeline_markdown(
185
- activities: list[dict[str, Any]],
186
- memories: list[dict[str, Any]],
187
- group_by: str = "hour"
188
- ) -> str:
189
- """Format a timeline as markdown.
190
-
191
- Args:
192
- activities: List of activity dictionaries
193
- memories: List of memory dictionaries
194
- group_by: How to group items (hour, day, session)
195
-
196
- Returns:
197
- Markdown formatted string
198
- """
199
- lines = []
200
- lines.append("# Timeline")
201
- lines.append("")
202
-
203
- # Combine and sort by timestamp
204
- items = []
205
- for act in activities:
206
- items.append({
207
- "type": "activity",
208
- "timestamp": act.get("timestamp"),
209
- "data": act
210
- })
211
- for mem in memories:
212
- items.append({
213
- "type": "memory",
214
- "timestamp": mem.get("created_at"),
215
- "data": mem
216
- })
217
-
218
- items.sort(key=lambda x: x.get("timestamp", ""), reverse=True)
219
-
220
- if not items:
221
- return "# Timeline\n\nNo items found."
222
-
223
- for item in items:
224
- if item["type"] == "activity":
225
- lines.append(format_activity_markdown(item["data"]))
226
- else:
227
- mem = item["data"]
228
- lines.append(f"**Memory created**: [{mem.get('type')}] {mem.get('id')}")
229
- content = xml_escape(mem.get("content", "")[:100])
230
- lines.append(f" > {content}...")
231
- lines.append("")
232
-
233
- return "\n".join(lines)
234
-
235
-
236
- def format_session_context_markdown(
237
- sessions: list[dict[str, Any]],
238
- learnings: list[str],
239
- decisions: list[str],
240
- errors: list[str]
241
- ) -> str:
242
- """Format session context as markdown for continuity.
243
-
244
- Args:
245
- sessions: Recent sessions
246
- learnings: Key learnings
247
- decisions: Key decisions
248
- errors: Key errors encountered
249
-
250
- Returns:
251
- Markdown formatted context string
252
- """
253
- lines = []
254
- lines.append("# Session Context")
255
- lines.append("")
256
-
257
- if sessions:
258
- last = sessions[0]
259
- ended = last.get("ended_at")
260
- if ended:
261
- lines.append(f"Last session ended {format_relative_time(ended)}")
262
- lines.append("")
263
-
264
- if learnings:
265
- lines.append("## Key Learnings")
266
- for learning in learnings[:5]:
267
- lines.append(f"- {learning}")
268
- lines.append("")
269
-
270
- if decisions:
271
- lines.append("## Key Decisions")
272
- for decision in decisions[:5]:
273
- lines.append(f"- {decision}")
274
- lines.append("")
275
-
276
- if errors:
277
- lines.append("## Errors Encountered")
278
- for error in errors[:5]:
279
- lines.append(f"- {error}")
280
- lines.append("")
281
-
282
- return "\n".join(lines)
omni_cortex/utils/ids.py DELETED
@@ -1,72 +0,0 @@
1
- """ID generation utilities for Omni Cortex."""
2
-
3
- import os
4
- import time
5
- from typing import Literal
6
-
7
-
8
- IdPrefix = Literal["mem", "act", "sess", "rel", "emb", "sum"]
9
-
10
-
11
- def generate_id(prefix: IdPrefix) -> str:
12
- """Generate a unique ID with timestamp and random suffix.
13
-
14
- Format: {prefix}_{timestamp_ms}_{random_hex}
15
-
16
- Args:
17
- prefix: One of mem, act, sess, rel, emb, sum
18
-
19
- Returns:
20
- Unique ID string
21
- """
22
- timestamp_ms = int(time.time() * 1000)
23
- random_hex = os.urandom(4).hex()
24
- return f"{prefix}_{timestamp_ms}_{random_hex}"
25
-
26
-
27
- def generate_memory_id() -> str:
28
- """Generate a memory ID."""
29
- return generate_id("mem")
30
-
31
-
32
- def generate_activity_id() -> str:
33
- """Generate an activity ID."""
34
- return generate_id("act")
35
-
36
-
37
- def generate_session_id() -> str:
38
- """Generate a session ID."""
39
- return generate_id("sess")
40
-
41
-
42
- def generate_relationship_id() -> str:
43
- """Generate a relationship ID."""
44
- return generate_id("rel")
45
-
46
-
47
- def generate_embedding_id() -> str:
48
- """Generate an embedding ID."""
49
- return generate_id("emb")
50
-
51
-
52
- def generate_summary_id() -> str:
53
- """Generate a session summary ID."""
54
- return generate_id("sum")
55
-
56
-
57
- def parse_id_timestamp(id_str: str) -> int:
58
- """Extract timestamp from an ID.
59
-
60
- Args:
61
- id_str: ID string in format prefix_timestamp_random
62
-
63
- Returns:
64
- Timestamp in milliseconds
65
- """
66
- try:
67
- parts = id_str.split("_")
68
- if len(parts) >= 2:
69
- return int(parts[1])
70
- except (ValueError, IndexError):
71
- pass
72
- return 0
@@ -1,129 +0,0 @@
1
- """Timestamp utilities for Omni Cortex."""
2
-
3
- from datetime import datetime, timezone, timedelta
4
- from typing import Optional
5
-
6
-
7
- def now_iso() -> str:
8
- """Get current time as ISO 8601 string with timezone.
9
-
10
- Returns:
11
- ISO 8601 formatted timestamp with UTC timezone
12
- """
13
- return datetime.now(timezone.utc).isoformat()
14
-
15
-
16
- def parse_iso(iso_string: str) -> datetime:
17
- """Parse an ISO 8601 string to datetime.
18
-
19
- Args:
20
- iso_string: ISO 8601 formatted string
21
-
22
- Returns:
23
- datetime object with timezone info
24
- """
25
- # Handle various ISO formats
26
- dt = datetime.fromisoformat(iso_string.replace("Z", "+00:00"))
27
- if dt.tzinfo is None:
28
- dt = dt.replace(tzinfo=timezone.utc)
29
- return dt
30
-
31
-
32
- def format_relative_time(dt: datetime | str) -> str:
33
- """Format a datetime as relative time (e.g., '2 hours ago').
34
-
35
- Args:
36
- dt: datetime object or ISO string
37
-
38
- Returns:
39
- Human-readable relative time string
40
- """
41
- if isinstance(dt, str):
42
- dt = parse_iso(dt)
43
-
44
- now = datetime.now(timezone.utc)
45
- if dt.tzinfo is None:
46
- dt = dt.replace(tzinfo=timezone.utc)
47
-
48
- diff = now - dt
49
-
50
- if diff < timedelta(minutes=1):
51
- return "just now"
52
- elif diff < timedelta(hours=1):
53
- minutes = int(diff.total_seconds() / 60)
54
- return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
55
- elif diff < timedelta(days=1):
56
- hours = int(diff.total_seconds() / 3600)
57
- return f"{hours} hour{'s' if hours != 1 else ''} ago"
58
- elif diff < timedelta(days=7):
59
- days = diff.days
60
- return f"{days} day{'s' if days != 1 else ''} ago"
61
- elif diff < timedelta(days=30):
62
- weeks = diff.days // 7
63
- return f"{weeks} week{'s' if weeks != 1 else ''} ago"
64
- elif diff < timedelta(days=365):
65
- months = diff.days // 30
66
- return f"{months} month{'s' if months != 1 else ''} ago"
67
- else:
68
- years = diff.days // 365
69
- return f"{years} year{'s' if years != 1 else ''} ago"
70
-
71
-
72
- def format_duration(ms: int) -> str:
73
- """Format milliseconds as human-readable duration.
74
-
75
- Args:
76
- ms: Duration in milliseconds
77
-
78
- Returns:
79
- Human-readable duration string
80
- """
81
- if ms < 1000:
82
- return f"{ms}ms"
83
- elif ms < 60000:
84
- seconds = ms / 1000
85
- return f"{seconds:.1f}s"
86
- elif ms < 3600000:
87
- minutes = ms / 60000
88
- return f"{minutes:.1f}m"
89
- else:
90
- hours = ms / 3600000
91
- return f"{hours:.1f}h"
92
-
93
-
94
- def days_since(dt: datetime | str) -> int:
95
- """Calculate days since a given datetime.
96
-
97
- Args:
98
- dt: datetime object or ISO string
99
-
100
- Returns:
101
- Number of days since the datetime
102
- """
103
- if isinstance(dt, str):
104
- dt = parse_iso(dt)
105
-
106
- now = datetime.now(timezone.utc)
107
- if dt.tzinfo is None:
108
- dt = dt.replace(tzinfo=timezone.utc)
109
-
110
- return (now - dt).days
111
-
112
-
113
- def hours_since(dt: datetime | str) -> float:
114
- """Calculate hours since a given datetime.
115
-
116
- Args:
117
- dt: datetime object or ISO string
118
-
119
- Returns:
120
- Number of hours since the datetime
121
- """
122
- if isinstance(dt, str):
123
- dt = parse_iso(dt)
124
-
125
- now = datetime.now(timezone.utc)
126
- if dt.tzinfo is None:
127
- dt = dt.replace(tzinfo=timezone.utc)
128
-
129
- return (now - dt).total_seconds() / 3600
@@ -1,111 +0,0 @@
1
- """Output truncation utilities for Omni Cortex."""
2
-
3
- import json
4
- from typing import Any
5
-
6
-
7
- DEFAULT_MAX_LENGTH = 10000
8
- TRUNCATION_SUFFIX = "\n... [truncated]"
9
-
10
-
11
- def truncate_output(text: str, max_length: int = DEFAULT_MAX_LENGTH) -> str:
12
- """Truncate text to maximum length.
13
-
14
- Args:
15
- text: Text to truncate
16
- max_length: Maximum allowed length
17
-
18
- Returns:
19
- Truncated text with suffix if truncated
20
- """
21
- if len(text) <= max_length:
22
- return text
23
-
24
- # Reserve space for truncation suffix
25
- cut_length = max_length - len(TRUNCATION_SUFFIX)
26
- if cut_length <= 0:
27
- return text[:max_length]
28
-
29
- return text[:cut_length] + TRUNCATION_SUFFIX
30
-
31
-
32
- def truncate_json(data: Any, max_length: int = DEFAULT_MAX_LENGTH) -> str:
33
- """Serialize to JSON and truncate if necessary.
34
-
35
- Args:
36
- data: Data to serialize
37
- max_length: Maximum allowed length
38
-
39
- Returns:
40
- JSON string, truncated if necessary
41
- """
42
- json_str = json.dumps(data, default=str)
43
- return truncate_output(json_str, max_length)
44
-
45
-
46
- def truncate_dict_values(
47
- data: dict[str, Any],
48
- max_value_length: int = 1000
49
- ) -> dict[str, Any]:
50
- """Truncate string values in a dictionary.
51
-
52
- Args:
53
- data: Dictionary with values to truncate
54
- max_value_length: Maximum length for each string value
55
-
56
- Returns:
57
- Dictionary with truncated string values
58
- """
59
- result = {}
60
- for key, value in data.items():
61
- if isinstance(value, str) and len(value) > max_value_length:
62
- result[key] = value[:max_value_length] + "..."
63
- elif isinstance(value, dict):
64
- result[key] = truncate_dict_values(value, max_value_length)
65
- elif isinstance(value, list):
66
- result[key] = [
67
- truncate_dict_values(item, max_value_length) if isinstance(item, dict)
68
- else (item[:max_value_length] + "..." if isinstance(item, str) and len(item) > max_value_length else item)
69
- for item in value
70
- ]
71
- else:
72
- result[key] = value
73
- return result
74
-
75
-
76
- def smart_truncate(text: str, max_length: int = DEFAULT_MAX_LENGTH) -> str:
77
- """Truncate text at a sensible boundary (newline, sentence, word).
78
-
79
- Args:
80
- text: Text to truncate
81
- max_length: Maximum allowed length
82
-
83
- Returns:
84
- Truncated text at a natural boundary
85
- """
86
- if len(text) <= max_length:
87
- return text
88
-
89
- # Reserve space for suffix
90
- cut_length = max_length - len(TRUNCATION_SUFFIX)
91
- if cut_length <= 0:
92
- return text[:max_length]
93
-
94
- # Try to cut at a newline
95
- last_newline = text.rfind("\n", 0, cut_length)
96
- if last_newline > cut_length * 0.7: # Only if reasonably close to the end
97
- return text[:last_newline] + TRUNCATION_SUFFIX
98
-
99
- # Try to cut at a sentence boundary
100
- for char in [". ", "! ", "? "]:
101
- last_sentence = text.rfind(char, 0, cut_length)
102
- if last_sentence > cut_length * 0.7:
103
- return text[:last_sentence + 1] + TRUNCATION_SUFFIX
104
-
105
- # Try to cut at a word boundary
106
- last_space = text.rfind(" ", 0, cut_length)
107
- if last_space > cut_length * 0.8:
108
- return text[:last_space] + TRUNCATION_SUFFIX
109
-
110
- # Fall back to hard cut
111
- return text[:cut_length] + TRUNCATION_SUFFIX
@@ -1,86 +0,0 @@
1
- omni_cortex/__init__.py,sha256=l6tpzaA2jtei2B0cfc33f3k7vrZd1-VVPZi7_jGtcwE,89
2
- omni_cortex/config.py,sha256=oUxl6caRqkRXjMCjnhxgmjPJZGMllqrZTvZueZ1Rzjc,4125
3
- omni_cortex/dashboard.py,sha256=wAXzOdcSypjoGoNMg__ytAQRuY1LZTj7siz6-eVySBs,8139
4
- omni_cortex/server.py,sha256=y-knqn-rSJqK5houuV40nLtiBJJMlPkGIKE3HIQxHhA,11729
5
- omni_cortex/setup.py,sha256=ZHmoD9k_6LCACFCbNzU34NULREKOotRlsOBCBo305cI,8684
6
- omni_cortex/categorization/__init__.py,sha256=9W6kQqbnOVor8kcNz8gtOFx0g-iEK_7AaNhlv-W93VQ,180
7
- omni_cortex/categorization/auto_tags.py,sha256=oi6muOyzM9d7kPQwxgcMHIPkR4T-1ovVCQIQ7gJ9Zak,5517
8
- omni_cortex/categorization/auto_type.py,sha256=_EZUTA7TvUudQKCPICV2ImViM3SjMsQOM8vMxocfxHs,4953
9
- omni_cortex/database/__init__.py,sha256=Ek88hq_VHwWCJgGFe760N-k8MRkV9o9lEn_JSFT65v0,617
10
- omni_cortex/database/connection.py,sha256=iEhn3mzq6Nd__nv0EXDA_c0Ly3w7xvFRUqA6C0esZMI,3923
11
- omni_cortex/database/migrations.py,sha256=iv8k3igp65jjQvGVtJLUFFREwBoJ-K4VTQRrQ8iiDWw,8726
12
- omni_cortex/database/schema.py,sha256=KLV1R5zuW_FOWu4PhLyLp_H6wGT15Wkbq2Jt45ccuYY,7623
13
- omni_cortex/database/sync.py,sha256=g1F73m00sIHYYLUNm44TVvw9CbmpICfyvyLcnzXQ7JE,12089
14
- omni_cortex/decay/__init__.py,sha256=BNz6SI06xxFKYeGRqZ2JfLy3F_nS0cf3irecnyS2Qjc,140
15
- omni_cortex/decay/importance.py,sha256=VhKc6s2_S1jW1e-4mugTvbPQcwkvBrKbtZWzqFmFXgE,4177
16
- omni_cortex/embeddings/__init__.py,sha256=INEf4GdaDYzEaFjvorzs7ZUAs20rY7oo1_r50e05wBs,817
17
- omni_cortex/embeddings/local.py,sha256=rxChHaAVa0LRjIcejYLAieH9t7QZKba4KbK7eeDKAdM,11735
18
- omni_cortex/models/__init__.py,sha256=lbM04IwH5GA282W3ao4NKF3Q1AHDJsg96qqQFNRf9mU,485
19
- omni_cortex/models/activity.py,sha256=dasWcqtlGismHRMqlkSIYaAFYuVfgd9kPWLECpR8PBQ,8478
20
- omni_cortex/models/agent.py,sha256=s39ZfRbDVTwiTHcxOCHhNR0W7d3dD5d5UNuT5UO6M9k,3466
21
- omni_cortex/models/memory.py,sha256=QABTh3OxNas5hVgANEyLpO62hn8_yhRhHkVSYWUeaYU,11161
22
- omni_cortex/models/relationship.py,sha256=hidMnA3H0Ys05bZLIsr46PkwNWVsqfLvHHK_l0SyAZs,5874
23
- omni_cortex/models/session.py,sha256=y3EBGGeWSFEEDs2YHn_zNTng5Ai20P5GorSZi0QG5jo,7863
24
- omni_cortex/resources/__init__.py,sha256=WkwSxkri6e_atF4BW7zN0IJjcYOehzh5U955NVTyyks,37
25
- omni_cortex/search/__init__.py,sha256=-IiEnmswORW_47azMxhEMUYqrOyp4tAntSrbTYEdGkM,597
26
- omni_cortex/search/hybrid.py,sha256=qlKHuR9AbTgeFDrVj-1YoVlRcN7fPOBTwSOmVXg2POk,6662
27
- omni_cortex/search/keyword.py,sha256=U4u7bGbc7x8Bov0agS95V3BWstfBgb2oad-1K30eZuU,5773
28
- omni_cortex/search/ranking.py,sha256=5go81cqGjj6AWkFQXo2y7GoGpdq0QS-GAkqzS0Vua34,3639
29
- omni_cortex/search/semantic.py,sha256=qM6OsfOEJA8sjFEbOFOGt0IaCNy2Aez9NMIKTem-NAM,6588
30
- omni_cortex/tools/__init__.py,sha256=3KZc9Bo4AouHdt1p4H7gqXJ9qc2E5i0Hn38dPvLiaug,352
31
- omni_cortex/tools/activities.py,sha256=sW5_xqg9MTRt0VmrogcL81SuQBtGD01qPDwYKIQdXQg,16371
32
- omni_cortex/tools/memories.py,sha256=Rtf2tmE7I7B3NWyPx_MDs7U82WQ-U-fUzibsPODdb3w,19746
33
- omni_cortex/tools/sessions.py,sha256=Ji6uX9RLhpOxcm3E1yEn-b4Z_W0TkO8scva5mlIbkdg,11093
34
- omni_cortex/tools/utilities.py,sha256=B0qI4I58kW2dhBIrzuGvZjPgUlG4XDwlCcdAd-X6JAQ,16759
35
- omni_cortex/utils/__init__.py,sha256=X9BuOfIiWNXO3QjByuHmRnZIL4kYo5VqPOk3eT_bSGE,293
36
- omni_cortex/utils/formatting.py,sha256=FondMrbOav_IAhxeJ0b0tbDEOtI7Y6UssvSojQs5848,8059
37
- omni_cortex/utils/ids.py,sha256=moymnXvSoE-SSvlpnR8jGN009WudYVv4Ww3f5RB30aU,1555
38
- omni_cortex/utils/timestamps.py,sha256=DsT4o9HuhZ2GQ76HjAUrtaljWuKOEp4olO-lT8jY24o,3310
39
- omni_cortex/utils/truncation.py,sha256=LjW0IGBX8Mc3zA8uG4a_0nYktawTUynWHnvHRdROeec,3293
40
- omni_cortex/_bundled/hooks/post_tool_use.py,sha256=zdaKChi8zOghRlHswisCBSQE3kW1MtmM6AFfI_ivvpI,16581
41
- omni_cortex/_bundled/hooks/pre_tool_use.py,sha256=3_V6Qw5m40eGrMmm5i94vINzeVxmcJvivdPa69H3AOI,8585
42
- omni_cortex/_bundled/hooks/session_utils.py,sha256=3SKPCytqWuRPOupWdzmwBoKBDJqtLcT1Nle_pueDQUY,5746
43
- omni_cortex/_bundled/hooks/stop.py,sha256=UroliJsyIS9_lj29-1d_r-80V4AfTMUFCaOjJZv3lwM,6976
44
- omni_cortex/_bundled/hooks/subagent_stop.py,sha256=V9HQSFGNOfkg8ZCstPEy4h5V8BP4AbrVr8teFzN1kNk,3314
45
- omni_cortex/_bundled/hooks/user_prompt.py,sha256=WNHJvhnkb9rXQ_HDpr6eLpM5vwy1Y1xl1EUoqyNC-x8,6859
46
- omni_cortex/_bundled/dashboard/backend/.env.example,sha256=9xS7-UiWlMddRwzlyyyKNHAMlNTsgH-2sPV266guJpQ,372
47
- omni_cortex/_bundled/dashboard/backend/backfill_summaries.py,sha256=ElchfcBv4pmVr2PsePCgFlCyuvf4_jDJj_C3AmMhu7U,8973
48
- omni_cortex/_bundled/dashboard/backend/chat_service.py,sha256=iEDpAw8OVaHM2312VPcAM-w6dYabUpjaTvWl1jGhqi0,20948
49
- omni_cortex/_bundled/dashboard/backend/database.py,sha256=byISCVgVziqFhJ8j8FC99ueTAoo-E0BJ6bk8KUvW3Mg,57610
50
- omni_cortex/_bundled/dashboard/backend/image_service.py,sha256=NP6ojFpHb6iNTYRkXqYu1CL6WvooZpZ54mjLiWSWG_g,19205
51
- omni_cortex/_bundled/dashboard/backend/logging_config.py,sha256=WnunFGET9zlsn9WBpVsio2zI7BiUQanE0xzAQQxIhII,3944
52
- omni_cortex/_bundled/dashboard/backend/main.py,sha256=9-GDfhtqvYZuLaqgmEzn0t-dxCiLdntnD1JA2rNAeCg,67165
53
- omni_cortex/_bundled/dashboard/backend/models.py,sha256=mP_szTXuVE4ZWHGubLeCt1-ltroO8OO0vrGC3IM6AJ0,13122
54
- omni_cortex/_bundled/dashboard/backend/project_config.py,sha256=ZxGoeRpHvN5qQyf2hRxrAZiHrPSwdQp59f0di6O1LKM,4352
55
- omni_cortex/_bundled/dashboard/backend/project_scanner.py,sha256=lwFXS8iJbOoxf7FAyo2TjH25neaMHiJ8B3jS57XxtDI,5713
56
- omni_cortex/_bundled/dashboard/backend/prompt_security.py,sha256=LcdZhYy1CfpSq_4BPO6lMJ15phc2ZXLUSBAnAvODVCI,3423
57
- omni_cortex/_bundled/dashboard/backend/pyproject.toml,sha256=9pbbGQXLe1Xd06nZAtDySCHIlfMWvPaB-C6tGZR6umc,502
58
- omni_cortex/_bundled/dashboard/backend/security.py,sha256=nQsoPE0n5dtY9ive00d33W1gL48GgK7C5Ae0BK2oW2k,3479
59
- omni_cortex/_bundled/dashboard/backend/uv.lock,sha256=miB9zGGSirBkjDE-OZTPCnv43Yc98xuAz_Ne8vTNFHg,186004
60
- omni_cortex/_bundled/dashboard/backend/websocket_manager.py,sha256=gNQLd94AcC-InumGQmUolREhiogCzilYWpLN8SRZjHI,3645
61
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/post_tool_use.py,sha256=zdaKChi8zOghRlHswisCBSQE3kW1MtmM6AFfI_ivvpI,16581
62
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/pre_tool_use.py,sha256=3_V6Qw5m40eGrMmm5i94vINzeVxmcJvivdPa69H3AOI,8585
63
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/session_utils.py,sha256=3SKPCytqWuRPOupWdzmwBoKBDJqtLcT1Nle_pueDQUY,5746
64
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/stop.py,sha256=UroliJsyIS9_lj29-1d_r-80V4AfTMUFCaOjJZv3lwM,6976
65
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/subagent_stop.py,sha256=V9HQSFGNOfkg8ZCstPEy4h5V8BP4AbrVr8teFzN1kNk,3314
66
- omni_cortex-1.17.3.data/data/share/omni-cortex/hooks/user_prompt.py,sha256=WNHJvhnkb9rXQ_HDpr6eLpM5vwy1Y1xl1EUoqyNC-x8,6859
67
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/.env.example,sha256=9xS7-UiWlMddRwzlyyyKNHAMlNTsgH-2sPV266guJpQ,372
68
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/backfill_summaries.py,sha256=ElchfcBv4pmVr2PsePCgFlCyuvf4_jDJj_C3AmMhu7U,8973
69
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/chat_service.py,sha256=iEDpAw8OVaHM2312VPcAM-w6dYabUpjaTvWl1jGhqi0,20948
70
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/database.py,sha256=byISCVgVziqFhJ8j8FC99ueTAoo-E0BJ6bk8KUvW3Mg,57610
71
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/image_service.py,sha256=NP6ojFpHb6iNTYRkXqYu1CL6WvooZpZ54mjLiWSWG_g,19205
72
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/logging_config.py,sha256=WnunFGET9zlsn9WBpVsio2zI7BiUQanE0xzAQQxIhII,3944
73
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/main.py,sha256=9-GDfhtqvYZuLaqgmEzn0t-dxCiLdntnD1JA2rNAeCg,67165
74
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/models.py,sha256=mP_szTXuVE4ZWHGubLeCt1-ltroO8OO0vrGC3IM6AJ0,13122
75
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/project_config.py,sha256=ZxGoeRpHvN5qQyf2hRxrAZiHrPSwdQp59f0di6O1LKM,4352
76
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/project_scanner.py,sha256=lwFXS8iJbOoxf7FAyo2TjH25neaMHiJ8B3jS57XxtDI,5713
77
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/prompt_security.py,sha256=LcdZhYy1CfpSq_4BPO6lMJ15phc2ZXLUSBAnAvODVCI,3423
78
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/pyproject.toml,sha256=9pbbGQXLe1Xd06nZAtDySCHIlfMWvPaB-C6tGZR6umc,502
79
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/security.py,sha256=nQsoPE0n5dtY9ive00d33W1gL48GgK7C5Ae0BK2oW2k,3479
80
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/uv.lock,sha256=miB9zGGSirBkjDE-OZTPCnv43Yc98xuAz_Ne8vTNFHg,186004
81
- omni_cortex-1.17.3.data/data/share/omni-cortex/dashboard/backend/websocket_manager.py,sha256=gNQLd94AcC-InumGQmUolREhiogCzilYWpLN8SRZjHI,3645
82
- omni_cortex-1.17.3.dist-info/METADATA,sha256=IltAdBerajG7u8_js1_hZtmZ6h-j5DdpOXM5tQIMpbw,15712
83
- omni_cortex-1.17.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
84
- omni_cortex-1.17.3.dist-info/entry_points.txt,sha256=rohx4mFH2ffZmMb9QXPZmFf-ZGjA3jpKVDVeET-ttiM,150
85
- omni_cortex-1.17.3.dist-info/licenses/LICENSE,sha256=oG_397owMmi-Umxp5sYocJ6RPohp9_bDNnnEu9OUphg,1072
86
- omni_cortex-1.17.3.dist-info/RECORD,,