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.
Files changed (78) 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/post_tool_use.py +2 -0
  9. omni_cortex/_bundled/hooks/pre_tool_use.py +2 -0
  10. omni_cortex/_bundled/hooks/stop.py +2 -0
  11. omni_cortex/_bundled/hooks/subagent_stop.py +2 -0
  12. omni_cortex/_bundled/hooks/user_prompt.py +117 -2
  13. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/main.py +2 -2
  14. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/post_tool_use.py +2 -0
  15. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/pre_tool_use.py +2 -0
  16. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/stop.py +2 -0
  17. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/subagent_stop.py +2 -0
  18. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/user_prompt.py +117 -2
  19. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/METADATA +6 -1
  20. omni_cortex-1.17.5.dist-info/RECORD +53 -0
  21. omni_cortex/__init__.py +0 -3
  22. omni_cortex/categorization/__init__.py +0 -9
  23. omni_cortex/categorization/auto_tags.py +0 -166
  24. omni_cortex/categorization/auto_type.py +0 -165
  25. omni_cortex/config.py +0 -141
  26. omni_cortex/dashboard.py +0 -238
  27. omni_cortex/database/__init__.py +0 -24
  28. omni_cortex/database/connection.py +0 -137
  29. omni_cortex/database/migrations.py +0 -210
  30. omni_cortex/database/schema.py +0 -212
  31. omni_cortex/database/sync.py +0 -421
  32. omni_cortex/decay/__init__.py +0 -7
  33. omni_cortex/decay/importance.py +0 -147
  34. omni_cortex/embeddings/__init__.py +0 -35
  35. omni_cortex/embeddings/local.py +0 -442
  36. omni_cortex/models/__init__.py +0 -20
  37. omni_cortex/models/activity.py +0 -265
  38. omni_cortex/models/agent.py +0 -144
  39. omni_cortex/models/memory.py +0 -395
  40. omni_cortex/models/relationship.py +0 -206
  41. omni_cortex/models/session.py +0 -290
  42. omni_cortex/resources/__init__.py +0 -1
  43. omni_cortex/search/__init__.py +0 -22
  44. omni_cortex/search/hybrid.py +0 -197
  45. omni_cortex/search/keyword.py +0 -204
  46. omni_cortex/search/ranking.py +0 -127
  47. omni_cortex/search/semantic.py +0 -232
  48. omni_cortex/server.py +0 -360
  49. omni_cortex/setup.py +0 -284
  50. omni_cortex/tools/__init__.py +0 -13
  51. omni_cortex/tools/activities.py +0 -453
  52. omni_cortex/tools/memories.py +0 -536
  53. omni_cortex/tools/sessions.py +0 -311
  54. omni_cortex/tools/utilities.py +0 -477
  55. omni_cortex/utils/__init__.py +0 -13
  56. omni_cortex/utils/formatting.py +0 -282
  57. omni_cortex/utils/ids.py +0 -72
  58. omni_cortex/utils/timestamps.py +0 -129
  59. omni_cortex/utils/truncation.py +0 -111
  60. omni_cortex-1.17.3.dist-info/RECORD +0 -86
  61. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/.env.example +0 -0
  62. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/backfill_summaries.py +0 -0
  63. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/chat_service.py +0 -0
  64. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/database.py +0 -0
  65. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/image_service.py +0 -0
  66. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/logging_config.py +0 -0
  67. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/models.py +0 -0
  68. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/project_config.py +0 -0
  69. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/project_scanner.py +0 -0
  70. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/prompt_security.py +0 -0
  71. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/pyproject.toml +0 -0
  72. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/security.py +0 -0
  73. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/uv.lock +0 -0
  74. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/dashboard/backend/websocket_manager.py +0 -0
  75. {omni_cortex-1.17.3.data → omni_cortex-1.17.5.data}/data/share/omni-cortex/hooks/session_utils.py +0 -0
  76. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/WHEEL +0 -0
  77. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/entry_points.txt +0 -0
  78. {omni_cortex-1.17.3.dist-info → omni_cortex-1.17.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,395 +0,0 @@
1
- """Memory model and CRUD operations."""
2
-
3
- import json
4
- import sqlite3
5
- from typing import Optional, Any
6
- from pydantic import BaseModel, Field, ConfigDict, field_validator
7
-
8
- from ..utils.ids import generate_memory_id
9
- from ..utils.timestamps import now_iso
10
-
11
-
12
- class MemoryBase(BaseModel):
13
- """Base memory model."""
14
-
15
- model_config = ConfigDict(
16
- str_strip_whitespace=True,
17
- validate_assignment=True,
18
- )
19
-
20
- content: str = Field(..., description="The memory content", min_length=1)
21
- context: Optional[str] = Field(None, description="Additional context")
22
- tags: Optional[list[str]] = Field(default_factory=list, description="Tags for categorization")
23
- type: str = Field("general", description="Memory type")
24
-
25
-
26
- class MemoryCreate(MemoryBase):
27
- """Input model for creating a memory."""
28
-
29
- importance: Optional[int] = Field(
30
- None, description="Importance score 1-100", ge=1, le=100
31
- )
32
- related_activity_id: Optional[str] = Field(None, description="Related activity ID")
33
- related_memory_ids: Optional[list[str]] = Field(
34
- default_factory=list, description="Related memory IDs"
35
- )
36
-
37
- @field_validator("tags", mode="before")
38
- @classmethod
39
- def parse_tags(cls, v: Any) -> list[str]:
40
- if v is None:
41
- return []
42
- if isinstance(v, str):
43
- return [t.strip() for t in v.split(",") if t.strip()]
44
- return list(v)
45
-
46
-
47
- class MemoryUpdate(BaseModel):
48
- """Input model for updating a memory."""
49
-
50
- model_config = ConfigDict(
51
- str_strip_whitespace=True,
52
- validate_assignment=True,
53
- )
54
-
55
- content: Optional[str] = Field(None, description="New content")
56
- context: Optional[str] = Field(None, description="New context")
57
- tags: Optional[list[str]] = Field(None, description="Replace all tags")
58
- add_tags: Optional[list[str]] = Field(None, description="Tags to add")
59
- remove_tags: Optional[list[str]] = Field(None, description="Tags to remove")
60
- status: Optional[str] = Field(None, description="New status")
61
- importance: Optional[int] = Field(None, description="New importance", ge=1, le=100)
62
-
63
-
64
- class Memory(MemoryBase):
65
- """Full memory model from database."""
66
-
67
- id: str
68
- created_at: str
69
- updated_at: str
70
- last_accessed: str
71
- last_verified: Optional[str] = None
72
- access_count: int = 0
73
- importance_score: float = 50.0
74
- manual_importance: Optional[int] = None
75
- status: str = "fresh"
76
- source_session_id: Optional[str] = None
77
- source_agent_id: Optional[str] = None
78
- source_activity_id: Optional[str] = None
79
- project_path: Optional[str] = None
80
- file_context: Optional[list[str]] = None
81
- has_embedding: bool = False
82
- metadata: Optional[dict[str, Any]] = None
83
-
84
-
85
- def create_memory(
86
- conn: sqlite3.Connection,
87
- data: MemoryCreate,
88
- project_path: Optional[str] = None,
89
- session_id: Optional[str] = None,
90
- agent_id: Optional[str] = None,
91
- ) -> Memory:
92
- """Create a new memory in the database.
93
-
94
- Args:
95
- conn: Database connection
96
- data: Memory creation data
97
- project_path: Current project path
98
- session_id: Current session ID
99
- agent_id: Current agent ID
100
-
101
- Returns:
102
- Created memory object
103
- """
104
- from ..categorization import detect_memory_type, suggest_tags
105
-
106
- memory_id = generate_memory_id()
107
- now = now_iso()
108
-
109
- # Auto-detect type if not specified or is default
110
- mem_type = data.type
111
- if mem_type == "general":
112
- mem_type = detect_memory_type(data.content, data.context)
113
-
114
- # Auto-suggest tags and merge with provided
115
- suggested = suggest_tags(data.content, data.context)
116
- tags = list(set((data.tags or []) + suggested))
117
-
118
- # Determine importance
119
- importance = float(data.importance) if data.importance else 50.0
120
- manual_importance = data.importance
121
-
122
- cursor = conn.cursor()
123
- cursor.execute(
124
- """
125
- INSERT INTO memories (
126
- id, content, type, tags, context,
127
- created_at, updated_at, last_accessed,
128
- access_count, importance_score, manual_importance, status,
129
- source_session_id, source_agent_id, source_activity_id,
130
- project_path, has_embedding
131
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
132
- """,
133
- (
134
- memory_id,
135
- data.content,
136
- mem_type,
137
- json.dumps(tags),
138
- data.context,
139
- now,
140
- now,
141
- now,
142
- 0,
143
- importance,
144
- manual_importance,
145
- "fresh",
146
- session_id,
147
- agent_id,
148
- data.related_activity_id,
149
- project_path,
150
- 0,
151
- ),
152
- )
153
- conn.commit()
154
-
155
- return Memory(
156
- id=memory_id,
157
- content=data.content,
158
- type=mem_type,
159
- tags=tags,
160
- context=data.context,
161
- created_at=now,
162
- updated_at=now,
163
- last_accessed=now,
164
- access_count=0,
165
- importance_score=importance,
166
- manual_importance=manual_importance,
167
- status="fresh",
168
- source_session_id=session_id,
169
- source_activity_id=data.related_activity_id,
170
- project_path=project_path,
171
- )
172
-
173
-
174
- def get_memory(conn: sqlite3.Connection, memory_id: str) -> Optional[Memory]:
175
- """Get a memory by ID.
176
-
177
- Args:
178
- conn: Database connection
179
- memory_id: Memory ID
180
-
181
- Returns:
182
- Memory object or None if not found
183
- """
184
- cursor = conn.cursor()
185
- cursor.execute("SELECT * FROM memories WHERE id = ?", (memory_id,))
186
- row = cursor.fetchone()
187
-
188
- if not row:
189
- return None
190
-
191
- return _row_to_memory(row)
192
-
193
-
194
- def update_memory(
195
- conn: sqlite3.Connection,
196
- memory_id: str,
197
- data: MemoryUpdate,
198
- ) -> Optional[Memory]:
199
- """Update a memory.
200
-
201
- Args:
202
- conn: Database connection
203
- memory_id: Memory ID
204
- data: Update data
205
-
206
- Returns:
207
- Updated memory or None if not found
208
- """
209
- memory = get_memory(conn, memory_id)
210
- if not memory:
211
- return None
212
-
213
- updates = []
214
- params = []
215
-
216
- if data.content is not None:
217
- updates.append("content = ?")
218
- params.append(data.content)
219
-
220
- if data.context is not None:
221
- updates.append("context = ?")
222
- params.append(data.context)
223
-
224
- if data.status is not None:
225
- updates.append("status = ?")
226
- params.append(data.status)
227
-
228
- if data.importance is not None:
229
- updates.append("manual_importance = ?")
230
- params.append(data.importance)
231
- updates.append("importance_score = ?")
232
- params.append(float(data.importance))
233
-
234
- # Handle tags
235
- current_tags = memory.tags or []
236
- new_tags = current_tags
237
-
238
- if data.tags is not None:
239
- new_tags = data.tags
240
- else:
241
- if data.add_tags:
242
- new_tags = list(set(current_tags + data.add_tags))
243
- if data.remove_tags:
244
- new_tags = [t for t in new_tags if t not in data.remove_tags]
245
-
246
- if new_tags != current_tags:
247
- updates.append("tags = ?")
248
- params.append(json.dumps(new_tags))
249
-
250
- if updates:
251
- updates.append("updated_at = ?")
252
- params.append(now_iso())
253
- params.append(memory_id)
254
-
255
- cursor = conn.cursor()
256
- cursor.execute(
257
- f"UPDATE memories SET {', '.join(updates)} WHERE id = ?",
258
- params,
259
- )
260
- conn.commit()
261
-
262
- return get_memory(conn, memory_id)
263
-
264
-
265
- def delete_memory(conn: sqlite3.Connection, memory_id: str) -> bool:
266
- """Delete a memory.
267
-
268
- Args:
269
- conn: Database connection
270
- memory_id: Memory ID
271
-
272
- Returns:
273
- True if deleted, False if not found
274
- """
275
- cursor = conn.cursor()
276
- cursor.execute("DELETE FROM memories WHERE id = ?", (memory_id,))
277
- conn.commit()
278
- return cursor.rowcount > 0
279
-
280
-
281
- def list_memories(
282
- conn: sqlite3.Connection,
283
- type_filter: Optional[str] = None,
284
- tags_filter: Optional[list[str]] = None,
285
- status_filter: Optional[str] = None,
286
- sort_by: str = "last_accessed",
287
- sort_order: str = "desc",
288
- limit: int = 20,
289
- offset: int = 0,
290
- ) -> tuple[list[Memory], int]:
291
- """List memories with filters.
292
-
293
- Returns:
294
- Tuple of (memories list, total count)
295
- """
296
- where_clauses = []
297
- params: list[Any] = []
298
-
299
- if type_filter:
300
- where_clauses.append("type = ?")
301
- params.append(type_filter)
302
-
303
- if status_filter:
304
- where_clauses.append("status = ?")
305
- params.append(status_filter)
306
-
307
- if tags_filter:
308
- # Match any of the tags
309
- tag_conditions = []
310
- for tag in tags_filter:
311
- tag_conditions.append("tags LIKE ?")
312
- params.append(f'%"{tag}"%')
313
- where_clauses.append(f"({' OR '.join(tag_conditions)})")
314
-
315
- where_sql = ""
316
- if where_clauses:
317
- where_sql = "WHERE " + " AND ".join(where_clauses)
318
-
319
- # Validate sort column
320
- valid_sorts = ["last_accessed", "created_at", "importance_score", "access_count"]
321
- if sort_by not in valid_sorts:
322
- sort_by = "last_accessed"
323
-
324
- order = "DESC" if sort_order.lower() == "desc" else "ASC"
325
-
326
- # Get total count
327
- cursor = conn.cursor()
328
- cursor.execute(f"SELECT COUNT(*) FROM memories {where_sql}", params)
329
- total = cursor.fetchone()[0]
330
-
331
- # Get page
332
- params_page = params + [limit, offset]
333
- cursor.execute(
334
- f"""
335
- SELECT * FROM memories {where_sql}
336
- ORDER BY {sort_by} {order}
337
- LIMIT ? OFFSET ?
338
- """,
339
- params_page,
340
- )
341
-
342
- memories = [_row_to_memory(row) for row in cursor.fetchall()]
343
- return memories, total
344
-
345
-
346
- def touch_memory(conn: sqlite3.Connection, memory_id: str) -> None:
347
- """Update last_accessed and increment access_count."""
348
- cursor = conn.cursor()
349
- cursor.execute(
350
- """
351
- UPDATE memories
352
- SET last_accessed = ?, access_count = access_count + 1
353
- WHERE id = ?
354
- """,
355
- (now_iso(), memory_id),
356
- )
357
- conn.commit()
358
-
359
-
360
- def _row_to_memory(row: sqlite3.Row) -> Memory:
361
- """Convert database row to Memory object."""
362
- tags = row["tags"]
363
- if tags and isinstance(tags, str):
364
- tags = json.loads(tags)
365
-
366
- file_context = row["file_context"]
367
- if file_context and isinstance(file_context, str):
368
- file_context = json.loads(file_context)
369
-
370
- metadata = row["metadata"]
371
- if metadata and isinstance(metadata, str):
372
- metadata = json.loads(metadata)
373
-
374
- return Memory(
375
- id=row["id"],
376
- content=row["content"],
377
- type=row["type"],
378
- tags=tags or [],
379
- context=row["context"],
380
- created_at=row["created_at"],
381
- updated_at=row["updated_at"],
382
- last_accessed=row["last_accessed"],
383
- last_verified=row["last_verified"],
384
- access_count=row["access_count"],
385
- importance_score=row["importance_score"],
386
- manual_importance=row["manual_importance"],
387
- status=row["status"],
388
- source_session_id=row["source_session_id"],
389
- source_agent_id=row["source_agent_id"],
390
- source_activity_id=row["source_activity_id"],
391
- project_path=row["project_path"],
392
- file_context=file_context,
393
- has_embedding=bool(row["has_embedding"]),
394
- metadata=metadata,
395
- )
@@ -1,206 +0,0 @@
1
- """Memory relationship model and operations."""
2
-
3
- import json
4
- import sqlite3
5
- from typing import Optional, Any
6
- from pydantic import BaseModel, Field, ConfigDict
7
-
8
- from ..utils.ids import generate_relationship_id
9
- from ..utils.timestamps import now_iso
10
-
11
-
12
- class MemoryRelationship(BaseModel):
13
- """Memory relationship model."""
14
-
15
- model_config = ConfigDict(
16
- str_strip_whitespace=True,
17
- )
18
-
19
- id: str
20
- source_memory_id: str
21
- target_memory_id: str
22
- relationship_type: str # related_to, supersedes, derived_from, contradicts
23
- strength: float = 1.0
24
- created_at: str
25
- metadata: Optional[dict[str, Any]] = None
26
-
27
-
28
- class LinkMemoriesInput(BaseModel):
29
- """Input for linking two memories."""
30
-
31
- model_config = ConfigDict(
32
- str_strip_whitespace=True,
33
- validate_assignment=True,
34
- )
35
-
36
- source_id: str = Field(..., description="Source memory ID")
37
- target_id: str = Field(..., description="Target memory ID")
38
- relationship_type: str = Field(
39
- ...,
40
- description="Relationship type: related_to, supersedes, derived_from, contradicts",
41
- )
42
- strength: float = Field(1.0, description="Relationship strength 0.0-1.0", ge=0.0, le=1.0)
43
-
44
-
45
- VALID_RELATIONSHIP_TYPES = ["related_to", "supersedes", "derived_from", "contradicts"]
46
-
47
-
48
- def create_relationship(
49
- conn: sqlite3.Connection,
50
- source_id: str,
51
- target_id: str,
52
- relationship_type: str,
53
- strength: float = 1.0,
54
- ) -> Optional[MemoryRelationship]:
55
- """Create a relationship between two memories.
56
-
57
- Args:
58
- conn: Database connection
59
- source_id: Source memory ID
60
- target_id: Target memory ID
61
- relationship_type: Type of relationship
62
- strength: Relationship strength
63
-
64
- Returns:
65
- Created relationship or None if memories don't exist
66
- """
67
- if relationship_type not in VALID_RELATIONSHIP_TYPES:
68
- raise ValueError(f"Invalid relationship type: {relationship_type}")
69
-
70
- # Verify both memories exist
71
- cursor = conn.cursor()
72
- cursor.execute("SELECT id FROM memories WHERE id IN (?, ?)", (source_id, target_id))
73
- found = [row[0] for row in cursor.fetchall()]
74
- if len(found) != 2:
75
- return None
76
-
77
- rel_id = generate_relationship_id()
78
- now = now_iso()
79
-
80
- try:
81
- cursor.execute(
82
- """
83
- INSERT INTO memory_relationships (
84
- id, source_memory_id, target_memory_id,
85
- relationship_type, strength, created_at
86
- ) VALUES (?, ?, ?, ?, ?, ?)
87
- """,
88
- (rel_id, source_id, target_id, relationship_type, strength, now),
89
- )
90
- conn.commit()
91
- except sqlite3.IntegrityError:
92
- # Relationship already exists
93
- cursor.execute(
94
- """
95
- SELECT * FROM memory_relationships
96
- WHERE source_memory_id = ? AND target_memory_id = ? AND relationship_type = ?
97
- """,
98
- (source_id, target_id, relationship_type),
99
- )
100
- row = cursor.fetchone()
101
- if row:
102
- return _row_to_relationship(row)
103
- return None
104
-
105
- return MemoryRelationship(
106
- id=rel_id,
107
- source_memory_id=source_id,
108
- target_memory_id=target_id,
109
- relationship_type=relationship_type,
110
- strength=strength,
111
- created_at=now,
112
- )
113
-
114
-
115
- def get_relationships(
116
- conn: sqlite3.Connection,
117
- memory_id: str,
118
- as_source: bool = True,
119
- as_target: bool = True,
120
- ) -> list[MemoryRelationship]:
121
- """Get all relationships for a memory.
122
-
123
- Args:
124
- conn: Database connection
125
- memory_id: Memory ID
126
- as_source: Include relationships where memory is source
127
- as_target: Include relationships where memory is target
128
-
129
- Returns:
130
- List of relationships
131
- """
132
- cursor = conn.cursor()
133
- relationships = []
134
-
135
- if as_source:
136
- cursor.execute(
137
- "SELECT * FROM memory_relationships WHERE source_memory_id = ?",
138
- (memory_id,),
139
- )
140
- relationships.extend([_row_to_relationship(row) for row in cursor.fetchall()])
141
-
142
- if as_target:
143
- cursor.execute(
144
- "SELECT * FROM memory_relationships WHERE target_memory_id = ?",
145
- (memory_id,),
146
- )
147
- relationships.extend([_row_to_relationship(row) for row in cursor.fetchall()])
148
-
149
- return relationships
150
-
151
-
152
- def delete_relationship(
153
- conn: sqlite3.Connection,
154
- source_id: str,
155
- target_id: str,
156
- relationship_type: Optional[str] = None,
157
- ) -> int:
158
- """Delete relationships between memories.
159
-
160
- Args:
161
- conn: Database connection
162
- source_id: Source memory ID
163
- target_id: Target memory ID
164
- relationship_type: Optional type filter
165
-
166
- Returns:
167
- Number of relationships deleted
168
- """
169
- cursor = conn.cursor()
170
-
171
- if relationship_type:
172
- cursor.execute(
173
- """
174
- DELETE FROM memory_relationships
175
- WHERE source_memory_id = ? AND target_memory_id = ? AND relationship_type = ?
176
- """,
177
- (source_id, target_id, relationship_type),
178
- )
179
- else:
180
- cursor.execute(
181
- """
182
- DELETE FROM memory_relationships
183
- WHERE source_memory_id = ? AND target_memory_id = ?
184
- """,
185
- (source_id, target_id),
186
- )
187
-
188
- conn.commit()
189
- return cursor.rowcount
190
-
191
-
192
- def _row_to_relationship(row: sqlite3.Row) -> MemoryRelationship:
193
- """Convert database row to MemoryRelationship object."""
194
- metadata = row["metadata"]
195
- if metadata and isinstance(metadata, str):
196
- metadata = json.loads(metadata)
197
-
198
- return MemoryRelationship(
199
- id=row["id"],
200
- source_memory_id=row["source_memory_id"],
201
- target_memory_id=row["target_memory_id"],
202
- relationship_type=row["relationship_type"],
203
- strength=row["strength"],
204
- created_at=row["created_at"],
205
- metadata=metadata,
206
- )