powermem 0.1.0__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 (123) hide show
  1. powermem/__init__.py +103 -0
  2. powermem/agent/__init__.py +35 -0
  3. powermem/agent/abstract/__init__.py +22 -0
  4. powermem/agent/abstract/collaboration.py +259 -0
  5. powermem/agent/abstract/context.py +187 -0
  6. powermem/agent/abstract/manager.py +232 -0
  7. powermem/agent/abstract/permission.py +217 -0
  8. powermem/agent/abstract/privacy.py +267 -0
  9. powermem/agent/abstract/scope.py +199 -0
  10. powermem/agent/agent.py +791 -0
  11. powermem/agent/components/__init__.py +18 -0
  12. powermem/agent/components/collaboration_coordinator.py +645 -0
  13. powermem/agent/components/permission_controller.py +586 -0
  14. powermem/agent/components/privacy_protector.py +767 -0
  15. powermem/agent/components/scope_controller.py +685 -0
  16. powermem/agent/factories/__init__.py +16 -0
  17. powermem/agent/factories/agent_factory.py +266 -0
  18. powermem/agent/factories/config_factory.py +308 -0
  19. powermem/agent/factories/memory_factory.py +229 -0
  20. powermem/agent/implementations/__init__.py +16 -0
  21. powermem/agent/implementations/hybrid.py +728 -0
  22. powermem/agent/implementations/multi_agent.py +1040 -0
  23. powermem/agent/implementations/multi_user.py +1020 -0
  24. powermem/agent/types.py +53 -0
  25. powermem/agent/wrappers/__init__.py +14 -0
  26. powermem/agent/wrappers/agent_memory_wrapper.py +427 -0
  27. powermem/agent/wrappers/compatibility_wrapper.py +520 -0
  28. powermem/config_loader.py +318 -0
  29. powermem/configs.py +249 -0
  30. powermem/core/__init__.py +19 -0
  31. powermem/core/async_memory.py +1493 -0
  32. powermem/core/audit.py +258 -0
  33. powermem/core/base.py +165 -0
  34. powermem/core/memory.py +1567 -0
  35. powermem/core/setup.py +162 -0
  36. powermem/core/telemetry.py +215 -0
  37. powermem/integrations/__init__.py +17 -0
  38. powermem/integrations/embeddings/__init__.py +13 -0
  39. powermem/integrations/embeddings/aws_bedrock.py +100 -0
  40. powermem/integrations/embeddings/azure_openai.py +55 -0
  41. powermem/integrations/embeddings/base.py +31 -0
  42. powermem/integrations/embeddings/config/base.py +132 -0
  43. powermem/integrations/embeddings/configs.py +31 -0
  44. powermem/integrations/embeddings/factory.py +48 -0
  45. powermem/integrations/embeddings/gemini.py +39 -0
  46. powermem/integrations/embeddings/huggingface.py +41 -0
  47. powermem/integrations/embeddings/langchain.py +35 -0
  48. powermem/integrations/embeddings/lmstudio.py +29 -0
  49. powermem/integrations/embeddings/mock.py +11 -0
  50. powermem/integrations/embeddings/ollama.py +53 -0
  51. powermem/integrations/embeddings/openai.py +49 -0
  52. powermem/integrations/embeddings/qwen.py +102 -0
  53. powermem/integrations/embeddings/together.py +31 -0
  54. powermem/integrations/embeddings/vertexai.py +54 -0
  55. powermem/integrations/llm/__init__.py +18 -0
  56. powermem/integrations/llm/anthropic.py +87 -0
  57. powermem/integrations/llm/base.py +132 -0
  58. powermem/integrations/llm/config/anthropic.py +56 -0
  59. powermem/integrations/llm/config/azure.py +56 -0
  60. powermem/integrations/llm/config/base.py +62 -0
  61. powermem/integrations/llm/config/deepseek.py +56 -0
  62. powermem/integrations/llm/config/ollama.py +56 -0
  63. powermem/integrations/llm/config/openai.py +79 -0
  64. powermem/integrations/llm/config/qwen.py +68 -0
  65. powermem/integrations/llm/config/qwen_asr.py +46 -0
  66. powermem/integrations/llm/config/vllm.py +56 -0
  67. powermem/integrations/llm/configs.py +26 -0
  68. powermem/integrations/llm/deepseek.py +106 -0
  69. powermem/integrations/llm/factory.py +118 -0
  70. powermem/integrations/llm/gemini.py +201 -0
  71. powermem/integrations/llm/langchain.py +65 -0
  72. powermem/integrations/llm/ollama.py +106 -0
  73. powermem/integrations/llm/openai.py +166 -0
  74. powermem/integrations/llm/openai_structured.py +80 -0
  75. powermem/integrations/llm/qwen.py +207 -0
  76. powermem/integrations/llm/qwen_asr.py +171 -0
  77. powermem/integrations/llm/vllm.py +106 -0
  78. powermem/integrations/rerank/__init__.py +20 -0
  79. powermem/integrations/rerank/base.py +43 -0
  80. powermem/integrations/rerank/config/__init__.py +7 -0
  81. powermem/integrations/rerank/config/base.py +27 -0
  82. powermem/integrations/rerank/configs.py +23 -0
  83. powermem/integrations/rerank/factory.py +68 -0
  84. powermem/integrations/rerank/qwen.py +159 -0
  85. powermem/intelligence/__init__.py +17 -0
  86. powermem/intelligence/ebbinghaus_algorithm.py +354 -0
  87. powermem/intelligence/importance_evaluator.py +361 -0
  88. powermem/intelligence/intelligent_memory_manager.py +284 -0
  89. powermem/intelligence/manager.py +148 -0
  90. powermem/intelligence/plugin.py +229 -0
  91. powermem/prompts/__init__.py +29 -0
  92. powermem/prompts/graph/graph_prompts.py +217 -0
  93. powermem/prompts/graph/graph_tools_prompts.py +469 -0
  94. powermem/prompts/importance_evaluation.py +246 -0
  95. powermem/prompts/intelligent_memory_prompts.py +163 -0
  96. powermem/prompts/templates.py +193 -0
  97. powermem/storage/__init__.py +14 -0
  98. powermem/storage/adapter.py +896 -0
  99. powermem/storage/base.py +109 -0
  100. powermem/storage/config/base.py +13 -0
  101. powermem/storage/config/oceanbase.py +58 -0
  102. powermem/storage/config/pgvector.py +52 -0
  103. powermem/storage/config/sqlite.py +27 -0
  104. powermem/storage/configs.py +159 -0
  105. powermem/storage/factory.py +59 -0
  106. powermem/storage/migration_manager.py +438 -0
  107. powermem/storage/oceanbase/__init__.py +8 -0
  108. powermem/storage/oceanbase/constants.py +162 -0
  109. powermem/storage/oceanbase/oceanbase.py +1384 -0
  110. powermem/storage/oceanbase/oceanbase_graph.py +1441 -0
  111. powermem/storage/pgvector/__init__.py +7 -0
  112. powermem/storage/pgvector/pgvector.py +420 -0
  113. powermem/storage/sqlite/__init__.py +0 -0
  114. powermem/storage/sqlite/sqlite.py +218 -0
  115. powermem/storage/sqlite/sqlite_vector_store.py +311 -0
  116. powermem/utils/__init__.py +35 -0
  117. powermem/utils/utils.py +605 -0
  118. powermem/version.py +23 -0
  119. powermem-0.1.0.dist-info/METADATA +187 -0
  120. powermem-0.1.0.dist-info/RECORD +123 -0
  121. powermem-0.1.0.dist-info/WHEEL +5 -0
  122. powermem-0.1.0.dist-info/licenses/LICENSE +206 -0
  123. powermem-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,728 @@
1
+ """
2
+ Hybrid Memory Manager Implementation
3
+
4
+ This module provides the concrete implementation of the hybrid memory manager,
5
+ which dynamically switches between multi-agent and multi-user modes based on context.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from typing import Any, Dict
13
+ from powermem.intelligence.intelligent_memory_manager import IntelligentMemoryManager
14
+ from powermem.agent.abstract.manager import AgentMemoryManagerBase
15
+ from powermem.agent.implementations.multi_agent import MultiAgentMemoryManager
16
+ from powermem.agent.implementations.multi_user import MultiUserMemoryManager
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class HybridMemoryManager(AgentMemoryManagerBase):
22
+ """
23
+ Hybrid memory manager implementation.
24
+
25
+ Dynamically switches between multi-agent and multi-user modes based on context,
26
+ providing intelligent mode selection and seamless transitions.
27
+ """
28
+
29
+ def __init__(self, config: Dict[str, Any]):
30
+ """
31
+ Initialize the hybrid memory manager.
32
+
33
+ Args:
34
+ config: Memory configuration object
35
+ """
36
+ super().__init__(config)
37
+ self.hybrid_config = config.agent_memory.hybrid_config
38
+
39
+ # Initialize components
40
+ self.intelligent_manager = None
41
+ self.multi_agent_manager = None
42
+ self.multi_user_manager = None
43
+
44
+ # Mode management
45
+ self.current_mode = self.hybrid_config.primary_mode
46
+ self.mode_switch_history = []
47
+ self.mode_switch_cooldown = {}
48
+
49
+ # Context analysis
50
+ self.context_analyzer = None
51
+ self.mode_confidence_scores = {}
52
+
53
+ # Unified memory storage for cross-mode access
54
+ self.unified_memory_index = {}
55
+ self.mode_specific_memories = {
56
+ 'multi_agent': {},
57
+ 'multi_user': {},
58
+ }
59
+
60
+ def initialize(self) -> None:
61
+ """
62
+ Initialize the memory manager and all components.
63
+ """
64
+ try:
65
+ # Initialize intelligent memory manager
66
+ self.intelligent_manager = IntelligentMemoryManager(self.config)
67
+
68
+ # Initialize mode-specific managers
69
+ self._initialize_mode_managers()
70
+
71
+ # Initialize context analyzer
72
+ self._initialize_context_analyzer()
73
+
74
+ # Set initial mode
75
+ self._switch_mode(self.hybrid_config.primary_mode, "initialization")
76
+
77
+ self.initialized = True
78
+ logger.info(f"Hybrid memory manager initialized with primary mode: {self.current_mode}")
79
+
80
+ except Exception as e:
81
+ logger.error(f"Failed to initialize hybrid memory manager: {e}")
82
+ raise
83
+
84
+ def _initialize_mode_managers(self) -> None:
85
+ """Initialize mode-specific managers."""
86
+ # Create multi-agent manager
87
+ multi_agent_config = self.config.copy()
88
+ # Ensure multi_agent_config exists
89
+ if 'multi_agent_config' not in multi_agent_config.agent_memory._data:
90
+ multi_agent_config.agent_memory._data['multi_agent_config'] = {
91
+ 'enabled': True,
92
+ 'default_permissions': {
93
+ 'owner': ['read', 'write', 'delete', 'admin'],
94
+ 'collaborator': ['read', 'write'],
95
+ 'viewer': ['read']
96
+ },
97
+ 'collaborative_memory_config': {
98
+ 'enabled': True,
99
+ 'auto_collaboration': True,
100
+ 'collaboration_threshold': 0.7,
101
+ 'max_collaborators': 5,
102
+ 'collaboration_timeout': 3600
103
+ },
104
+ 'privacy_config': {
105
+ 'enabled': True,
106
+ 'default_privacy_level': 'standard',
107
+ 'encryption_enabled': False,
108
+ 'anonymization_enabled': True
109
+ },
110
+ 'default_scope': 'private'
111
+ }
112
+ multi_agent_config.agent_memory.mode = "multi_agent"
113
+ multi_agent_config.agent_memory.enabled = True
114
+ self.multi_agent_manager = MultiAgentMemoryManager(multi_agent_config)
115
+ self.multi_agent_manager.initialize()
116
+
117
+ # Create multi-user manager
118
+ multi_user_config = self.config.copy()
119
+ # Ensure multi_user_config exists
120
+ if 'multi_user_config' not in multi_user_config.agent_memory._data:
121
+ multi_user_config.agent_memory._data['multi_user_config'] = {
122
+ 'enabled': True,
123
+ 'user_isolation': True,
124
+ 'cross_user_sharing': True,
125
+ 'privacy_protection': True,
126
+ 'default_permissions': {
127
+ 'owner': ['read', 'write', 'delete', 'admin'],
128
+ 'collaborator': ['read', 'write'],
129
+ 'viewer': ['read']
130
+ },
131
+ 'user_context_config': {
132
+ 'max_user_memories': 10000,
133
+ 'context_retention_days': 30,
134
+ 'auto_cleanup': True,
135
+ 'context_sharing_enabled': True
136
+ }
137
+ }
138
+ multi_user_config.agent_memory.mode = "multi_user"
139
+ multi_user_config.agent_memory.enabled = True
140
+ self.multi_user_manager = MultiUserMemoryManager(multi_user_config)
141
+ self.multi_user_manager.initialize()
142
+
143
+ def _initialize_context_analyzer(self) -> None:
144
+ """Initialize context analyzer for mode switching."""
145
+ self.context_analyzer = {
146
+ 'collaboration_keywords': [
147
+ 'team', 'collaborate', 'meeting', 'discuss', 'share', 'group',
148
+ 'project', 'work together', 'joint', 'collective'
149
+ ],
150
+ 'personal_keywords': [
151
+ 'personal', 'private', 'individual', 'my', 'own', 'self',
152
+ 'personal preference', 'private note', 'individual task'
153
+ ],
154
+ 'context_weights': {
155
+ 'collaboration_level': 0.4,
156
+ 'participants_count': 0.3,
157
+ 'content_keywords': 0.2,
158
+ 'metadata_hints': 0.1,
159
+ }
160
+ }
161
+
162
+ def process_memory(
163
+ self,
164
+ content: str,
165
+ agent_id: str,
166
+ context: Optional[Dict[str, Any]] = None,
167
+ metadata: Optional[Dict[str, Any]] = None
168
+ ) -> Dict[str, Any]:
169
+ """
170
+ Process and store a new memory with intelligent mode selection.
171
+
172
+ Args:
173
+ content: The memory content to store
174
+ agent_id: ID of the agent/user creating the memory
175
+ context: Additional context information
176
+ metadata: Additional metadata for the memory
177
+
178
+ Returns:
179
+ Dictionary containing the processed memory information
180
+ """
181
+ try:
182
+ # Analyze context to determine optimal mode
183
+ optimal_mode = self._analyze_context_for_mode(content, context, metadata)
184
+
185
+ # Switch mode if necessary
186
+ if optimal_mode != self.current_mode:
187
+ self._switch_mode(optimal_mode, "context_analysis")
188
+
189
+ # Process memory with current mode manager
190
+ if self.current_mode == "multi_agent":
191
+ result = self.multi_agent_manager.process_memory(content, agent_id, context, metadata)
192
+ else:
193
+ result = self.multi_user_manager.process_memory(content, agent_id, context, metadata)
194
+
195
+ # Store in unified index
196
+ memory_id = result['id']
197
+ self.unified_memory_index[memory_id] = {
198
+ 'id': memory_id,
199
+ 'content': content,
200
+ 'agent_id': agent_id,
201
+ 'mode': self.current_mode,
202
+ 'processed_at': datetime.now().isoformat(),
203
+ 'context': context or {},
204
+ 'metadata': metadata or {},
205
+ }
206
+
207
+ # Store in mode-specific storage
208
+ if self.current_mode not in self.mode_specific_memories:
209
+ self.mode_specific_memories[self.current_mode] = {}
210
+ self.mode_specific_memories[self.current_mode][memory_id] = result
211
+
212
+ # Add mode information to result
213
+ result['processed_in_mode'] = self.current_mode
214
+ result['mode_switch_reason'] = "context_analysis" if optimal_mode != self.hybrid_config.primary_mode else "primary_mode"
215
+
216
+ logger.info(f"Processed memory {memory_id} in {self.current_mode} mode")
217
+ return result
218
+
219
+ except Exception as e:
220
+ logger.error(f"Failed to process memory for {agent_id}: {e}")
221
+ raise
222
+
223
+ def _analyze_context_for_mode(
224
+ self,
225
+ content: str,
226
+ context: Optional[Dict[str, Any]],
227
+ metadata: Optional[Dict[str, Any]]
228
+ ) -> str:
229
+ """
230
+ Analyze context to determine the optimal mode for processing.
231
+
232
+ Args:
233
+ content: Memory content
234
+ context: Context information
235
+ metadata: Metadata information
236
+
237
+ Returns:
238
+ Optimal mode ('multi_agent' or 'multi_user')
239
+ """
240
+ try:
241
+ scores = {
242
+ 'multi_agent': 0.0,
243
+ 'multi_user': 0.0,
244
+ }
245
+
246
+ # Analyze collaboration level
247
+ collaboration_level = context.get('collaboration_level', 'none') if context else 'none'
248
+ if collaboration_level in ['high', 'medium']:
249
+ scores['multi_agent'] += 0.4
250
+ else:
251
+ scores['multi_user'] += 0.3
252
+
253
+ # Analyze participants
254
+ participants = context.get('participants', []) if context else []
255
+ if len(participants) > 1:
256
+ scores['multi_agent'] += 0.3
257
+ else:
258
+ scores['multi_user'] += 0.2
259
+
260
+ # Analyze content keywords
261
+ content_lower = content.lower()
262
+ collaboration_keywords = sum(1 for keyword in self.context_analyzer['collaboration_keywords']
263
+ if keyword in content_lower)
264
+ personal_keywords = sum(1 for keyword in self.context_analyzer['personal_keywords']
265
+ if keyword in content_lower)
266
+
267
+ if collaboration_keywords > personal_keywords:
268
+ scores['multi_agent'] += 0.2
269
+ else:
270
+ scores['multi_user'] += 0.2
271
+
272
+ # Analyze metadata hints
273
+ if metadata:
274
+ if metadata.get('collaboration') or metadata.get('meeting_type'):
275
+ scores['multi_agent'] += 0.1
276
+ elif metadata.get('personal') or metadata.get('privacy_level') == 'private':
277
+ scores['multi_user'] += 0.1
278
+
279
+ # Apply confidence threshold
280
+ confidence_threshold = self.hybrid_config.mode_switching_config.get('confidence_threshold', 0.7)
281
+
282
+ if scores['multi_agent'] > scores['multi_user'] and scores['multi_agent'] > confidence_threshold:
283
+ return 'multi_agent'
284
+ elif scores['multi_user'] > scores['multi_agent'] and scores['multi_user'] > confidence_threshold:
285
+ return 'multi_user'
286
+ else:
287
+ # Default to primary mode if confidence is low
288
+ return self.hybrid_config.primary_mode
289
+
290
+ except Exception as e:
291
+ logger.error(f"Failed to analyze context for mode: {e}")
292
+ return self.hybrid_config.primary_mode
293
+
294
+ def _switch_mode(self, new_mode: str, reason: str) -> None:
295
+ """
296
+ Switch to a new mode.
297
+
298
+ Args:
299
+ new_mode: New mode to switch to
300
+ reason: Reason for the switch
301
+ """
302
+ try:
303
+ # Check cooldown
304
+ if self._is_in_cooldown(new_mode):
305
+ logger.info(f"Mode switch to {new_mode} blocked by cooldown")
306
+ return
307
+
308
+ old_mode = self.current_mode
309
+ self.current_mode = new_mode
310
+
311
+ # Record switch
312
+ switch_record = {
313
+ 'from_mode': old_mode,
314
+ 'to_mode': new_mode,
315
+ 'reason': reason,
316
+ 'timestamp': datetime.now().isoformat(),
317
+ }
318
+ self.mode_switch_history.append(switch_record)
319
+
320
+ # Set cooldown
321
+ cooldown_seconds = self.hybrid_config.mode_switching_config.get('switch_cooldown_seconds', 300)
322
+ self.mode_switch_cooldown[new_mode] = datetime.now().timestamp() + cooldown_seconds
323
+
324
+ logger.info(f"Switched from {old_mode} to {new_mode} mode (reason: {reason})")
325
+
326
+ except Exception as e:
327
+ logger.error(f"Failed to switch mode to {new_mode}: {e}")
328
+
329
+ def _is_in_cooldown(self, mode: str) -> bool:
330
+ """Check if a mode is in cooldown."""
331
+ if mode not in self.mode_switch_cooldown:
332
+ return False
333
+
334
+ return datetime.now().timestamp() < self.mode_switch_cooldown[mode]
335
+
336
+ def get_memories(
337
+ self,
338
+ agent_id: str,
339
+ query: Optional[str] = None,
340
+ filters: Optional[Dict[str, Any]] = None
341
+ ) -> List[Dict[str, Any]]:
342
+ """
343
+ Retrieve memories for a specific agent/user from both modes.
344
+
345
+ Args:
346
+ agent_id: ID of the agent/user
347
+ query: Optional query string for filtering
348
+ filters: Optional additional filters
349
+
350
+ Returns:
351
+ List of memory dictionaries from both modes
352
+ """
353
+ try:
354
+ all_memories = []
355
+
356
+ # Get memories from current mode
357
+ if self.current_mode == "multi_agent":
358
+ current_memories = self.multi_agent_manager.get_memories(agent_id, query, filters)
359
+ else:
360
+ current_memories = self.multi_user_manager.get_memories(agent_id, query, filters)
361
+
362
+ all_memories.extend(current_memories)
363
+
364
+ # Get memories from other mode if cross-mode access is enabled
365
+ if self.hybrid_config.mode_switching_config.get('enable_cross_mode_access', True):
366
+ other_mode = "multi_user" if self.current_mode == "multi_agent" else "multi_agent"
367
+
368
+ if other_mode == "multi_agent":
369
+ other_memories = self.multi_agent_manager.get_memories(agent_id, query, filters)
370
+ else:
371
+ other_memories = self.multi_user_manager.get_memories(agent_id, query, filters)
372
+
373
+ # Mark memories from other mode
374
+ for memory in other_memories:
375
+ memory['source_mode'] = other_mode
376
+ memory['cross_mode_access'] = True
377
+
378
+ all_memories.extend(other_memories)
379
+
380
+ # Remove duplicates based on content
381
+ unique_memories = []
382
+ seen_content = set()
383
+
384
+ for memory in all_memories:
385
+ content = memory.get('content', '')
386
+ if content not in seen_content:
387
+ seen_content.add(content)
388
+ unique_memories.append(memory)
389
+
390
+ logger.info(f"Retrieved {len(unique_memories)} memories for {agent_id} (current mode: {self.current_mode})")
391
+ return unique_memories
392
+
393
+ except Exception as e:
394
+ logger.error(f"Failed to get memories for {agent_id}: {e}")
395
+ raise
396
+
397
+ def update_memory(
398
+ self,
399
+ memory_id: str,
400
+ agent_id: str,
401
+ updates: Dict[str, Any]
402
+ ) -> Dict[str, Any]:
403
+ """
404
+ Update an existing memory.
405
+
406
+ Args:
407
+ memory_id: ID of the memory to update
408
+ agent_id: ID of the agent/user making the update
409
+ updates: Dictionary of updates to apply
410
+
411
+ Returns:
412
+ Dictionary containing the updated memory information
413
+ """
414
+ try:
415
+ # Find which mode the memory belongs to
416
+ memory_mode = self._get_memory_mode(memory_id)
417
+
418
+ if not memory_mode:
419
+ raise ValueError(f"Memory {memory_id} not found in any mode")
420
+
421
+ # Update with appropriate manager
422
+ if memory_mode == "multi_agent":
423
+ result = self.multi_agent_manager.update_memory(memory_id, agent_id, updates)
424
+ else:
425
+ result = self.multi_user_manager.update_memory(memory_id, agent_id, updates)
426
+
427
+ # Update unified index
428
+ if memory_id in self.unified_memory_index:
429
+ self.unified_memory_index[memory_id]['updated_at'] = datetime.now().isoformat()
430
+ self.unified_memory_index[memory_id]['updated_by'] = agent_id
431
+
432
+ result['updated_in_mode'] = memory_mode
433
+ logger.info(f"Updated memory {memory_id} in {memory_mode} mode")
434
+ return result
435
+
436
+ except Exception as e:
437
+ logger.error(f"Failed to update memory {memory_id}: {e}")
438
+ raise
439
+
440
+ def delete_memory(
441
+ self,
442
+ memory_id: str,
443
+ agent_id: str
444
+ ) -> Dict[str, Any]:
445
+ """
446
+ Delete a memory.
447
+
448
+ Args:
449
+ memory_id: ID of the memory to delete
450
+ agent_id: ID of the agent/user making the deletion
451
+
452
+ Returns:
453
+ Dictionary containing the deletion result
454
+ """
455
+ try:
456
+ # Find which mode the memory belongs to
457
+ memory_mode = self._get_memory_mode(memory_id)
458
+
459
+ if not memory_mode:
460
+ raise ValueError(f"Memory {memory_id} not found in any mode")
461
+
462
+ # Delete with appropriate manager
463
+ if memory_mode == "multi_agent":
464
+ result = self.multi_agent_manager.delete_memory(memory_id, agent_id)
465
+ else:
466
+ result = self.multi_user_manager.delete_memory(memory_id, agent_id)
467
+
468
+ # Clean up unified index
469
+ if memory_id in self.unified_memory_index:
470
+ del self.unified_memory_index[memory_id]
471
+
472
+ # Clean up mode-specific storage
473
+ if memory_mode in self.mode_specific_memories:
474
+ if memory_id in self.mode_specific_memories[memory_mode]:
475
+ del self.mode_specific_memories[memory_mode][memory_id]
476
+
477
+ result['deleted_from_mode'] = memory_mode
478
+ logger.info(f"Deleted memory {memory_id} from {memory_mode} mode")
479
+ return result
480
+
481
+ except Exception as e:
482
+ logger.error(f"Failed to delete memory {memory_id}: {e}")
483
+ raise
484
+
485
+ def share_memory(
486
+ self,
487
+ memory_id: str,
488
+ from_agent: str,
489
+ to_agents: List[str],
490
+ permissions: Optional[List[str]] = None
491
+ ) -> Dict[str, Any]:
492
+ """
493
+ Share a memory with other agents/users.
494
+
495
+ Args:
496
+ memory_id: ID of the memory to share
497
+ from_agent: ID of the agent/user sharing the memory
498
+ to_agents: List of agent/user IDs to share with
499
+ permissions: Optional list of permissions to grant
500
+
501
+ Returns:
502
+ Dictionary containing the sharing result
503
+ """
504
+ try:
505
+ # Find which mode the memory belongs to
506
+ memory_mode = self._get_memory_mode(memory_id)
507
+
508
+ if not memory_mode:
509
+ raise ValueError(f"Memory {memory_id} not found in any mode")
510
+
511
+ # Share with appropriate manager
512
+ if memory_mode == "multi_agent":
513
+ result = self.multi_agent_manager.share_memory(memory_id, from_agent, to_agents, permissions)
514
+ else:
515
+ result = self.multi_user_manager.share_memory(memory_id, from_agent, to_agents, permissions)
516
+
517
+ result['shared_from_mode'] = memory_mode
518
+ logger.info(f"Shared memory {memory_id} from {memory_mode} mode")
519
+ return result
520
+
521
+ except Exception as e:
522
+ logger.error(f"Failed to share memory {memory_id}: {e}")
523
+ raise
524
+
525
+ def get_context_info(self, agent_id: str) -> Dict[str, Any]:
526
+ """
527
+ Get context information for an agent/user from both modes.
528
+
529
+ Args:
530
+ agent_id: ID of the agent/user
531
+
532
+ Returns:
533
+ Dictionary containing context information from both modes
534
+ """
535
+ try:
536
+ # Get context from both modes
537
+ multi_agent_context = self.multi_agent_manager.get_context_info(agent_id)
538
+ multi_user_context = self.multi_user_manager.get_context_info(agent_id)
539
+
540
+ # Combine context information
541
+ combined_context = {
542
+ 'agent_id': agent_id,
543
+ 'current_mode': self.current_mode,
544
+ 'mode_switch_history': self.mode_switch_history[-5:], # Last 5 switches
545
+ 'multi_agent_context': multi_agent_context,
546
+ 'multi_user_context': multi_user_context,
547
+ 'hybrid_stats': {
548
+ 'total_memories': len(self.unified_memory_index),
549
+ 'mode_breakdown': {
550
+ 'multi_agent': len(self.mode_specific_memories.get('multi_agent', {})),
551
+ 'multi_user': len(self.mode_specific_memories.get('multi_user', {})),
552
+ },
553
+ 'switch_count': len(self.mode_switch_history),
554
+ },
555
+ }
556
+
557
+ return combined_context
558
+
559
+ except Exception as e:
560
+ logger.error(f"Failed to get context info for {agent_id}: {e}")
561
+ raise
562
+
563
+ def update_memory_decay(self) -> Dict[str, Any]:
564
+ """
565
+ Update memory decay for both modes.
566
+
567
+ Returns:
568
+ Dictionary containing the decay update results
569
+ """
570
+ try:
571
+ # Update decay for both modes
572
+ multi_agent_decay = self.multi_agent_manager.update_memory_decay()
573
+ multi_user_decay = self.multi_user_manager.update_memory_decay()
574
+
575
+ # Combine results
576
+ combined_decay = {
577
+ 'multi_agent_decay': multi_agent_decay,
578
+ 'multi_user_decay': multi_user_decay,
579
+ 'total_updated': multi_agent_decay.get('updated_memories', 0) + multi_user_decay.get('updated_memories', 0),
580
+ 'total_forgotten': multi_agent_decay.get('forgotten_memories', 0) + multi_user_decay.get('forgotten_memories', 0),
581
+ 'total_reinforced': multi_agent_decay.get('reinforced_memories', 0) + multi_user_decay.get('reinforced_memories', 0),
582
+ }
583
+
584
+ logger.info(f"Updated memory decay for both modes: {combined_decay}")
585
+ return combined_decay
586
+
587
+ except Exception as e:
588
+ logger.error(f"Failed to update memory decay: {e}")
589
+ raise
590
+
591
+ def cleanup_forgotten_memories(self) -> Dict[str, Any]:
592
+ """
593
+ Clean up forgotten memories from both modes.
594
+
595
+ Returns:
596
+ Dictionary containing the cleanup results
597
+ """
598
+ try:
599
+ # Clean up both modes
600
+ multi_agent_cleanup = self.multi_agent_manager.cleanup_forgotten_memories()
601
+ multi_user_cleanup = self.multi_user_manager.cleanup_forgotten_memories()
602
+
603
+ # Combine results
604
+ combined_cleanup = {
605
+ 'multi_agent_cleanup': multi_agent_cleanup,
606
+ 'multi_user_cleanup': multi_user_cleanup,
607
+ 'total_cleaned': multi_agent_cleanup.get('cleaned_memories', 0) + multi_user_cleanup.get('cleaned_memories', 0),
608
+ 'total_archived': multi_agent_cleanup.get('archived_memories', 0) + multi_user_cleanup.get('archived_memories', 0),
609
+ 'total_deleted': multi_agent_cleanup.get('deleted_memories', 0) + multi_user_cleanup.get('deleted_memories', 0),
610
+ }
611
+
612
+ # Clean up unified index
613
+ cleaned_memory_ids = set()
614
+ for cleanup_result in [multi_agent_cleanup, multi_user_cleanup]:
615
+ if 'cleaned_memory_ids' in cleanup_result:
616
+ cleaned_memory_ids.update(cleanup_result['cleaned_memory_ids'])
617
+
618
+ for memory_id in cleaned_memory_ids:
619
+ if memory_id in self.unified_memory_index:
620
+ del self.unified_memory_index[memory_id]
621
+
622
+ logger.info(f"Cleaned up forgotten memories from both modes: {combined_cleanup}")
623
+ return combined_cleanup
624
+
625
+ except Exception as e:
626
+ logger.error(f"Failed to cleanup forgotten memories: {e}")
627
+ raise
628
+
629
+ def get_memory_statistics(self) -> Dict[str, Any]:
630
+ """
631
+ Get statistics about the memory system from both modes.
632
+
633
+ Returns:
634
+ Dictionary containing memory statistics
635
+ """
636
+ try:
637
+ # Get statistics from both modes
638
+ multi_agent_stats = self.multi_agent_manager.get_memory_statistics()
639
+ multi_user_stats = self.multi_user_manager.get_memory_statistics()
640
+
641
+ # Combine statistics
642
+ combined_stats = {
643
+ 'current_mode': self.current_mode,
644
+ 'mode_switch_history': len(self.mode_switch_history),
645
+ 'unified_memory_count': len(self.unified_memory_index),
646
+ 'multi_agent_stats': multi_agent_stats,
647
+ 'multi_user_stats': multi_user_stats,
648
+ 'hybrid_stats': {
649
+ 'total_memories': multi_agent_stats.get('total_memories', 0) + multi_user_stats.get('total_memories', 0),
650
+ 'mode_breakdown': {
651
+ 'multi_agent': multi_agent_stats.get('total_memories', 0),
652
+ 'multi_user': multi_user_stats.get('total_memories', 0),
653
+ },
654
+ 'switch_frequency': len(self.mode_switch_history) / max(1, (datetime.now() - datetime.fromisoformat(self.mode_switch_history[0]['timestamp'])).days) if self.mode_switch_history else 0,
655
+ },
656
+ }
657
+
658
+ return combined_stats
659
+
660
+ except Exception as e:
661
+ logger.error(f"Failed to get memory statistics: {e}")
662
+ raise
663
+
664
+ def check_permission(
665
+ self,
666
+ agent_id: str,
667
+ memory_id: str,
668
+ permission: str
669
+ ) -> bool:
670
+ """
671
+ Check if an agent/user has a specific permission for a memory.
672
+
673
+ Args:
674
+ agent_id: ID of the agent/user
675
+ memory_id: ID of the memory
676
+ permission: Permission to check
677
+
678
+ Returns:
679
+ True if the agent/user has the permission, False otherwise
680
+ """
681
+ try:
682
+ # Find which mode the memory belongs to
683
+ memory_mode = self._get_memory_mode(memory_id)
684
+
685
+ if not memory_mode:
686
+ return False
687
+
688
+ # Check permission with appropriate manager
689
+ if memory_mode == "multi_agent":
690
+ return self.multi_agent_manager.check_permission(agent_id, memory_id, permission)
691
+ else:
692
+ return self.multi_user_manager.check_permission(agent_id, memory_id, permission)
693
+
694
+ except Exception:
695
+ return False
696
+
697
+ def _get_memory_mode(self, memory_id: str) -> Optional[str]:
698
+ """Get the mode that a memory belongs to."""
699
+ # Check unified index first
700
+ if memory_id in self.unified_memory_index:
701
+ return self.unified_memory_index[memory_id]['mode']
702
+
703
+ # Check mode-specific storage
704
+ for mode, memories in self.mode_specific_memories.items():
705
+ if memory_id in memories:
706
+ return mode
707
+
708
+ return None
709
+
710
+ def get_mode_info(self) -> Dict[str, Any]:
711
+ """
712
+ Get information about the current mode and switching history.
713
+
714
+ Returns:
715
+ Dictionary containing mode information
716
+ """
717
+ return {
718
+ 'current_mode': self.current_mode,
719
+ 'primary_mode': self.hybrid_config.primary_mode,
720
+ 'fallback_mode': self.hybrid_config.fallback_mode,
721
+ 'auto_switch_enabled': self.hybrid_config.mode_switching_config.get('enable_auto_switch', True),
722
+ 'switch_history': self.mode_switch_history[-10:], # Last 10 switches
723
+ 'cooldown_status': {
724
+ mode: self._is_in_cooldown(mode)
725
+ for mode in ['multi_agent', 'multi_user']
726
+ },
727
+ 'confidence_threshold': self.hybrid_config.mode_switching_config.get('confidence_threshold', 0.7),
728
+ }