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,791 @@
1
+ """
2
+ Unified Agent Memory Interface
3
+
4
+ This module provides a simplified, unified interface for all agent memory management
5
+ scenarios (Multi-Agent, Multi-User, Hybrid) with automatic mode detection and
6
+ seamless switching.
7
+ """
8
+
9
+ import logging
10
+ from typing import Any, Dict, List, Optional, Union
11
+ from datetime import datetime
12
+
13
+ from ..agent.types import AccessPermission, MemoryScope, MemoryType, PrivacyLevel, CollaborationLevel
14
+
15
+
16
+ class ConfigObject:
17
+ """Wrapper to provide attribute-like access to configuration dictionaries."""
18
+
19
+ def __init__(self, data: Dict[str, Any]):
20
+ self._data = data
21
+
22
+ def __getattr__(self, name: str):
23
+ if name in self._data:
24
+ value = self._data[name]
25
+ if isinstance(value, dict):
26
+ return ConfigObject(value)
27
+ return value
28
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
29
+
30
+ def to_dict(self):
31
+ """Convert ConfigObject to dictionary (recursively)."""
32
+ if hasattr(self, '_data'):
33
+ result = {}
34
+ for key, value in self._data.items():
35
+ if isinstance(value, ConfigObject):
36
+ result[key] = value.to_dict()
37
+ elif isinstance(value, dict):
38
+ result[key] = value
39
+ else:
40
+ result[key] = value
41
+ return result
42
+ return {}
43
+
44
+ def __dict__(self):
45
+ """Support dict() conversion."""
46
+ return self.to_dict()
47
+
48
+ def get(self, key: str, default=None):
49
+ """Dictionary-like get method."""
50
+ return self._data.get(key, default)
51
+
52
+ def items(self):
53
+ """Dictionary-like items method."""
54
+ return self._data.items()
55
+
56
+ def keys(self):
57
+ """Dictionary-like keys method."""
58
+ return self._data.keys()
59
+
60
+ def values(self):
61
+ """Dictionary-like values method."""
62
+ return self._data.values()
63
+
64
+ def __contains__(self, key):
65
+ """Support 'in' operator."""
66
+ return key in self._data
67
+
68
+ def __setitem__(self, key, value):
69
+ """Support item assignment."""
70
+ self._data[key] = value
71
+
72
+ def __getitem__(self, key):
73
+ """Support item access."""
74
+ if key in self._data:
75
+ value = self._data[key]
76
+ if isinstance(value, dict):
77
+ return ConfigObject(value)
78
+ return value
79
+ raise KeyError(key)
80
+
81
+ def copy(self):
82
+ """Support copy method with deep copy for nested dictionaries."""
83
+ import copy
84
+ return ConfigObject(copy.deepcopy(self._data))
85
+
86
+ logger = logging.getLogger(__name__)
87
+
88
+
89
+ class AgentMemory:
90
+ """
91
+ Unified Agent Memory Interface
92
+
93
+ This class provides a simplified interface for all agent memory scenarios:
94
+ - Multi-Agent: Multiple agents with collaboration
95
+ - Multi-User: Single agent with multiple users
96
+ - Hybrid: Dynamic switching between modes
97
+
98
+ The interface automatically detects the appropriate mode and provides
99
+ a consistent API regardless of the underlying implementation.
100
+ """
101
+
102
+ def __init__(self, config: Dict[str, Any], mode: Optional[str] = None):
103
+ """
104
+ Initialize the unified agent memory interface.
105
+
106
+ Args:
107
+ config: Memory configuration dictionary
108
+ mode: Optional mode override ('multi_agent', 'multi_user', 'hybrid', 'auto')
109
+ """
110
+ self.config = ConfigObject(config)
111
+ self.mode = mode or self._detect_mode(config)
112
+ self._memory = None
113
+ self._agent_manager = None
114
+ self._initialized = False
115
+
116
+ # Initialize based on detected mode
117
+ self._initialize()
118
+
119
+ def _detect_mode(self, config: Dict[str, Any]) -> str:
120
+ """Detect the appropriate mode based on configuration."""
121
+ # Check for explicit mode configuration
122
+ if 'agent_memory' in config:
123
+ agent_config = config['agent_memory']
124
+ if 'mode' in agent_config:
125
+ return agent_config['mode']
126
+
127
+ # Check for specific manager configurations
128
+ if 'multi_agent_config' in agent_config:
129
+ return 'multi_agent'
130
+ elif 'multi_user_config' in agent_config:
131
+ return 'multi_user'
132
+ elif 'hybrid_config' in agent_config:
133
+ return 'hybrid'
134
+
135
+ # Default to auto mode for intelligent detection
136
+ return 'auto'
137
+
138
+ def _initialize(self) -> None:
139
+ """Initialize the appropriate memory manager based on mode."""
140
+ try:
141
+ if self.mode == 'multi_agent':
142
+ self._initialize_multi_agent()
143
+ elif self.mode == 'multi_user':
144
+ self._initialize_multi_user()
145
+ elif self.mode == 'hybrid':
146
+ self._initialize_hybrid()
147
+ elif self.mode == 'auto':
148
+ self._initialize_auto()
149
+ else:
150
+ raise ValueError(f"Unknown mode: {self.mode}")
151
+
152
+ self._initialized = True
153
+ logger.info(f"AgentMemory initialized in {self.mode} mode")
154
+
155
+ except Exception as e:
156
+ logger.error(f"Failed to initialize AgentMemory: {e}")
157
+ raise
158
+
159
+ def _initialize_multi_agent(self) -> None:
160
+ """Initialize multi-agent mode."""
161
+ from .implementations.multi_agent import MultiAgentMemoryManager
162
+
163
+ # Ensure multi-agent config exists
164
+ if 'agent_memory' not in self.config:
165
+ self.config['agent_memory'] = {}
166
+
167
+ if 'multi_agent_config' not in self.config['agent_memory']:
168
+ self.config['agent_memory']['multi_agent_config'] = self._get_default_multi_agent_config()
169
+
170
+ # Create the manager with ConfigObject wrapper
171
+ original_config = self.config._data if hasattr(self.config, '_data') else self.config
172
+ config_obj = ConfigObject(original_config)
173
+ self._agent_manager = MultiAgentMemoryManager(config_obj)
174
+ self._agent_manager.initialize()
175
+
176
+ # Memory instance will be created lazily when needed
177
+
178
+ def _initialize_multi_user(self) -> None:
179
+ """Initialize multi-user mode."""
180
+ from .implementations.multi_user import MultiUserMemoryManager
181
+
182
+ # Ensure multi-user config exists
183
+ if 'agent_memory' not in self.config:
184
+ self.config['agent_memory'] = {}
185
+
186
+ if 'multi_user_config' not in self.config['agent_memory']:
187
+ self.config['agent_memory']['multi_user_config'] = self._get_default_multi_user_config()
188
+
189
+ # Create the manager with ConfigObject wrapper
190
+ original_config = self.config._data if hasattr(self.config, '_data') else self.config
191
+ config_obj = ConfigObject(original_config)
192
+ self._agent_manager = MultiUserMemoryManager(config_obj)
193
+ self._agent_manager.initialize()
194
+
195
+ # Memory instance will be created lazily when needed
196
+
197
+ def _initialize_hybrid(self) -> None:
198
+ """Initialize hybrid mode."""
199
+ from .implementations.hybrid import HybridMemoryManager
200
+
201
+ # Ensure hybrid config exists
202
+ if 'agent_memory' not in self.config:
203
+ self.config['agent_memory'] = {}
204
+
205
+ if 'hybrid_config' not in self.config['agent_memory']:
206
+ self.config['agent_memory']['hybrid_config'] = self._get_default_hybrid_config()
207
+
208
+ # Create the manager with ConfigObject wrapper
209
+ original_config = self.config._data if hasattr(self.config, '_data') else self.config
210
+ config_obj = ConfigObject(original_config)
211
+ self._agent_manager = HybridMemoryManager(config_obj)
212
+ self._agent_manager.initialize()
213
+
214
+ # Memory instance will be created lazily when needed
215
+
216
+ def _initialize_auto(self) -> None:
217
+ """Initialize auto mode with intelligent detection."""
218
+ # For now, default to multi-agent mode
219
+ # This can be enhanced with intelligent detection logic
220
+ logger.info("Auto mode detected, defaulting to multi-agent")
221
+ self._initialize_multi_agent()
222
+
223
+ def _get_default_multi_agent_config(self) -> Dict[str, Any]:
224
+ """Get default multi-agent configuration with environment variable support."""
225
+ import os
226
+
227
+ # Get environment variables with defaults
228
+ enabled = os.getenv('AGENT_ENABLED', 'true').lower() == 'true'
229
+ default_scope = os.getenv('AGENT_DEFAULT_SCOPE', 'AGENT')
230
+ default_privacy_level = os.getenv('AGENT_DEFAULT_PRIVACY_LEVEL', 'PRIVATE')
231
+ default_collaboration_level = os.getenv('AGENT_DEFAULT_COLLABORATION_LEVEL', 'READ_ONLY')
232
+ default_access_permission = os.getenv('AGENT_DEFAULT_ACCESS_PERMISSION', 'OWNER_ONLY')
233
+
234
+ return {
235
+ 'enabled': enabled,
236
+ 'default_scope': default_scope,
237
+ 'default_privacy_level': default_privacy_level,
238
+ 'default_collaboration_level': default_collaboration_level,
239
+ 'default_access_permission': default_access_permission,
240
+ 'default_permissions': {
241
+ 'owner': ['read', 'write', 'delete', 'admin'],
242
+ 'collaborator': ['read', 'write'],
243
+ 'viewer': ['read']
244
+ },
245
+ 'agent_groups': {},
246
+ 'collaboration_settings': {
247
+ 'auto_share_threshold': 0.8,
248
+ 'default_privacy_level': default_privacy_level.lower()
249
+ },
250
+ 'privacy_config': {
251
+ 'enable_encryption': False,
252
+ 'data_anonymization': True,
253
+ 'access_logging': True,
254
+ 'retention_policy': '30_days',
255
+ 'gdpr_compliance': True,
256
+ 'default_privacy_level': default_privacy_level.lower()
257
+ },
258
+ 'collaborative_memory_config': {
259
+ 'enabled': True,
260
+ 'auto_collaboration': True,
261
+ 'collaboration_threshold': 0.7,
262
+ 'max_collaborators': 5,
263
+ 'collaboration_timeout': 3600,
264
+ 'default_collaboration_level': default_collaboration_level.lower()
265
+ },
266
+ 'default_scope': default_scope.lower()
267
+ }
268
+
269
+ def _get_default_multi_user_config(self) -> Dict[str, Any]:
270
+ """Get default multi-user configuration with environment variable support."""
271
+ import os
272
+
273
+ # Get environment variables with defaults
274
+ enabled = os.getenv('AGENT_ENABLED', 'true').lower() == 'true'
275
+ default_scope = os.getenv('AGENT_DEFAULT_SCOPE', 'USER_GROUP')
276
+ default_privacy_level = os.getenv('AGENT_DEFAULT_PRIVACY_LEVEL', 'PRIVATE')
277
+ default_collaboration_level = os.getenv('AGENT_DEFAULT_COLLABORATION_LEVEL', 'READ_ONLY')
278
+ default_access_permission = os.getenv('AGENT_DEFAULT_ACCESS_PERMISSION', 'OWNER_ONLY')
279
+
280
+ return {
281
+ 'enabled': enabled,
282
+ 'default_scope': default_scope,
283
+ 'default_privacy_level': default_privacy_level,
284
+ 'default_collaboration_level': default_collaboration_level,
285
+ 'default_access_permission': default_access_permission,
286
+ 'user_isolation': True,
287
+ 'cross_user_sharing': True,
288
+ 'privacy_protection': True,
289
+ 'default_permissions': {
290
+ 'owner': ['read', 'write', 'delete', 'admin'],
291
+ 'collaborator': ['read', 'write'],
292
+ 'viewer': ['read']
293
+ },
294
+ 'user_context_config': {
295
+ 'max_user_memories': 10000,
296
+ 'context_retention_days': 30,
297
+ 'auto_cleanup': True,
298
+ 'context_sharing_enabled': True
299
+ }
300
+ }
301
+
302
+ def _get_default_hybrid_config(self) -> Dict[str, Any]:
303
+ """Get default hybrid configuration with environment variable support."""
304
+ import os
305
+
306
+ # Get environment variables with defaults
307
+ enabled = os.getenv('AGENT_ENABLED', 'true').lower() == 'true'
308
+ default_scope = os.getenv('AGENT_DEFAULT_SCOPE', 'AGENT')
309
+ default_privacy_level = os.getenv('AGENT_DEFAULT_PRIVACY_LEVEL', 'PRIVATE')
310
+ default_collaboration_level = os.getenv('AGENT_DEFAULT_COLLABORATION_LEVEL', 'READ_ONLY')
311
+ default_access_permission = os.getenv('AGENT_DEFAULT_ACCESS_PERMISSION', 'OWNER_ONLY')
312
+
313
+ return {
314
+ 'enabled': enabled,
315
+ 'default_scope': default_scope,
316
+ 'default_privacy_level': default_privacy_level,
317
+ 'default_collaboration_level': default_collaboration_level,
318
+ 'default_access_permission': default_access_permission,
319
+ 'primary_mode': 'multi_agent',
320
+ 'fallback_mode': 'multi_user',
321
+ 'auto_switch': True,
322
+ 'switch_threshold': 0.7,
323
+ 'mode_detection': {
324
+ 'agent_count_threshold': 2,
325
+ 'user_count_threshold': 3,
326
+ 'collaboration_threshold': 0.5
327
+ },
328
+ 'mode_switching_config': {
329
+ 'enabled': True,
330
+ 'switch_delay': 1.0,
331
+ 'context_window': 10,
332
+ 'confidence_threshold': 0.8,
333
+ 'fallback_enabled': True
334
+ }
335
+ }
336
+
337
+ # Unified API Methods
338
+
339
+ def add(
340
+ self,
341
+ content: str,
342
+ user_id: Optional[str] = None,
343
+ agent_id: Optional[str] = None,
344
+ metadata: Optional[Dict[str, Any]] = None,
345
+ scope: Optional[str] = None,
346
+ share_with: Optional[List[str]] = None
347
+ ) -> Dict[str, Any]:
348
+ """
349
+ Add a new memory.
350
+
351
+ Args:
352
+ content: The memory content to store
353
+ user_id: Optional user ID
354
+ agent_id: Optional agent ID
355
+ metadata: Optional metadata for the memory
356
+ scope: Optional memory scope
357
+ share_with: Optional list of IDs to share with
358
+
359
+ Returns:
360
+ Dictionary containing the added memory information
361
+ """
362
+ if not self._initialized:
363
+ raise RuntimeError("AgentMemory not initialized")
364
+
365
+ try:
366
+ # Use the underlying agent manager for processing
367
+ if hasattr(self._agent_manager, 'process_memory'):
368
+ # Multi-agent or multi-user mode
369
+ context = {
370
+ 'user_id': user_id,
371
+ 'agent_id': agent_id,
372
+ 'scope': scope,
373
+ 'share_with': share_with or []
374
+ }
375
+
376
+ result = self._agent_manager.process_memory(
377
+ content=content,
378
+ agent_id=agent_id or 'default',
379
+ context=context,
380
+ metadata=metadata
381
+ )
382
+
383
+ # Memory is stored by the agent manager, no need for additional storage
384
+
385
+ return result
386
+ else:
387
+ # Fallback to agent manager
388
+ raise RuntimeError("No agent manager available for fallback")
389
+
390
+ except Exception as e:
391
+ logger.error(f"Failed to add memory: {e}")
392
+ raise
393
+
394
+ def search(
395
+ self,
396
+ query: str,
397
+ user_id: Optional[str] = None,
398
+ agent_id: Optional[str] = None,
399
+ scope: Optional[str] = None,
400
+ limit: int = 10
401
+ ) -> List[Dict[str, Any]]:
402
+ """
403
+ Search memories.
404
+
405
+ Args:
406
+ query: Search query string
407
+ user_id: Optional user ID filter
408
+ agent_id: Optional agent ID filter
409
+ scope: Optional scope filter
410
+ limit: Maximum number of results
411
+
412
+ Returns:
413
+ List of matching memory dictionaries
414
+ """
415
+ if not self._initialized:
416
+ raise RuntimeError("AgentMemory not initialized")
417
+
418
+ try:
419
+ # Use the underlying agent manager for search
420
+ if hasattr(self._agent_manager, 'get_memories'):
421
+ filters = {}
422
+ if user_id:
423
+ filters['user_id'] = user_id
424
+ if scope:
425
+ filters['scope'] = scope
426
+
427
+ results = self._agent_manager.get_memories(
428
+ agent_id=agent_id or 'default',
429
+ query=query,
430
+ filters=filters
431
+ )
432
+
433
+ return results[:limit]
434
+ else:
435
+ # Fallback to base memory
436
+ # Use agent manager for search
437
+ if hasattr(self._agent_manager, 'get_memories'):
438
+ return self._agent_manager.get_memories(
439
+ agent_id=agent_id or 'default',
440
+ query=query,
441
+ filters={'user_id': user_id} if user_id else None
442
+ )
443
+ else:
444
+ raise RuntimeError("Search not supported by current manager")
445
+
446
+ except Exception as e:
447
+ logger.error(f"Failed to search memories: {e}")
448
+ raise
449
+
450
+ def get_all(
451
+ self,
452
+ user_id: Optional[str] = None,
453
+ agent_id: Optional[str] = None,
454
+ limit: int = 100
455
+ ) -> List[Dict[str, Any]]:
456
+ """
457
+ Get all memories with optional filtering.
458
+
459
+ Args:
460
+ user_id: Optional user ID filter
461
+ agent_id: Optional agent ID filter
462
+ limit: Maximum number of results
463
+
464
+ Returns:
465
+ List of all memory dictionaries
466
+ """
467
+ if not self._initialized:
468
+ raise RuntimeError("AgentMemory not initialized")
469
+
470
+ try:
471
+ # Use the underlying agent manager
472
+ if hasattr(self._agent_manager, 'get_memories'):
473
+ filters = {}
474
+ if user_id:
475
+ filters['user_id'] = user_id
476
+
477
+ results = self._agent_manager.get_memories(
478
+ agent_id=agent_id or 'default',
479
+ filters=filters
480
+ )
481
+
482
+ return results[:limit]
483
+ else:
484
+ # Fallback to base memory
485
+ # Use agent manager for get_all
486
+ if hasattr(self._agent_manager, 'get_memories'):
487
+ return self._agent_manager.get_memories(
488
+ agent_id=agent_id or 'default',
489
+ filters={'user_id': user_id} if user_id else None
490
+ )
491
+ else:
492
+ raise RuntimeError("Get all not supported by current manager")
493
+
494
+ except Exception as e:
495
+ logger.error(f"Failed to get all memories: {e}")
496
+ raise
497
+
498
+ def update(
499
+ self,
500
+ memory_id: str,
501
+ content: str,
502
+ user_id: Optional[str] = None,
503
+ agent_id: Optional[str] = None,
504
+ metadata: Optional[Dict[str, Any]] = None
505
+ ) -> Dict[str, Any]:
506
+ """
507
+ Update an existing memory.
508
+
509
+ Args:
510
+ memory_id: ID of the memory to update
511
+ content: New content for the memory
512
+ user_id: Optional user ID
513
+ agent_id: Optional agent ID
514
+ metadata: Optional new metadata
515
+
516
+ Returns:
517
+ Dictionary containing the updated memory information
518
+ """
519
+ if not self._initialized:
520
+ raise RuntimeError("AgentMemory not initialized")
521
+
522
+ try:
523
+ # Use the underlying agent manager
524
+ if hasattr(self._agent_manager, 'update_memory'):
525
+ updates = {'content': content}
526
+ if metadata:
527
+ updates['metadata'] = metadata
528
+
529
+ return self._agent_manager.update_memory(
530
+ memory_id=memory_id,
531
+ agent_id=agent_id or 'default',
532
+ updates=updates
533
+ )
534
+ else:
535
+ # Use agent manager for update
536
+ if hasattr(self._agent_manager, 'update_memory'):
537
+ return self._agent_manager.update_memory(
538
+ memory_id=memory_id,
539
+ agent_id=agent_id or 'default',
540
+ updates=updates
541
+ )
542
+ else:
543
+ raise RuntimeError("Update not supported by current manager")
544
+
545
+ except Exception as e:
546
+ logger.error(f"Failed to update memory {memory_id}: {e}")
547
+ raise
548
+
549
+ def delete(
550
+ self,
551
+ memory_id: str,
552
+ user_id: Optional[str] = None,
553
+ agent_id: Optional[str] = None
554
+ ) -> bool:
555
+ """
556
+ Delete a memory.
557
+
558
+ Args:
559
+ memory_id: ID of the memory to delete
560
+ user_id: Optional user ID
561
+ agent_id: Optional agent ID
562
+
563
+ Returns:
564
+ True if successful, False otherwise
565
+ """
566
+ if not self._initialized:
567
+ raise RuntimeError("AgentMemory not initialized")
568
+
569
+ try:
570
+ # Use the underlying agent manager
571
+ if hasattr(self._agent_manager, 'delete_memory'):
572
+ result = self._agent_manager.delete_memory(
573
+ memory_id=memory_id,
574
+ agent_id=agent_id or 'default'
575
+ )
576
+ return result.get('success', False)
577
+ else:
578
+ # Use agent manager for delete
579
+ if hasattr(self._agent_manager, 'delete_memory'):
580
+ result = self._agent_manager.delete_memory(
581
+ memory_id=memory_id,
582
+ agent_id=agent_id or 'default'
583
+ )
584
+ return result.get('success', False)
585
+ else:
586
+ raise RuntimeError("Delete not supported by current manager")
587
+
588
+ except Exception as e:
589
+ logger.error(f"Failed to delete memory {memory_id}: {e}")
590
+ raise
591
+
592
+ def delete_all(
593
+ self,
594
+ user_id: Optional[str] = None,
595
+ agent_id: Optional[str] = None
596
+ ) -> bool:
597
+ """
598
+ Delete all memories matching the provided identifiers.
599
+
600
+ Args:
601
+ user_id: Optional user ID filter
602
+ agent_id: Optional agent ID (defaults to 'default' if not provided)
603
+
604
+ Returns:
605
+ True if all deletions succeeded (or nothing to delete), False otherwise
606
+ """
607
+ if not self._initialized:
608
+ raise RuntimeError("AgentMemory not initialized")
609
+
610
+ try:
611
+ # Require manager capabilities for listing and deleting
612
+ if not hasattr(self._agent_manager, 'get_memories') or not hasattr(self._agent_manager, 'delete_memory'):
613
+ raise RuntimeError("Delete all not supported by current manager")
614
+
615
+ filters: Dict[str, Any] = {}
616
+ if user_id:
617
+ filters['user_id'] = user_id
618
+
619
+ # Determine the agent_id to use for deletion
620
+ # In multi_user mode, user_id should be used as agent_id for permission checks
621
+ # In multi_agent mode, agent_id should be provided explicitly
622
+ deletion_agent_id = agent_id or user_id or 'default'
623
+
624
+ # Fetch memories to delete
625
+ results = self._agent_manager.get_memories(
626
+ agent_id=deletion_agent_id,
627
+ filters=filters
628
+ )
629
+
630
+ if not results:
631
+ return True
632
+
633
+ all_ok = True
634
+ for item in results:
635
+ mem_id = item.get('id') or item.get('memory_id')
636
+ if not mem_id:
637
+ continue
638
+ resp = self._agent_manager.delete_memory(
639
+ memory_id=mem_id,
640
+ agent_id=deletion_agent_id
641
+ )
642
+ ok = bool(resp.get('success', False)) if isinstance(resp, dict) else bool(resp)
643
+ all_ok = all_ok and ok
644
+ return all_ok
645
+
646
+ except Exception as e:
647
+ logger.error(f"Failed to delete all memories: {e}")
648
+ raise
649
+
650
+ def reset(self) -> None:
651
+ """
652
+ Reset the memory store by clearing all data.
653
+
654
+ This method resets the underlying memory storage, including:
655
+ - Vector store collections
656
+ - Database tables
657
+ - Graph store (if enabled)
658
+
659
+ WARNING: This will delete ALL memories and cannot be undone.
660
+ """
661
+ if not self._initialized:
662
+ raise RuntimeError("AgentMemory not initialized")
663
+
664
+ try:
665
+ # Try to access the underlying Memory instance through the agent manager
666
+ if hasattr(self._agent_manager, '_memory_instance'):
667
+ self._agent_manager._memory_instance.reset()
668
+ logger.info("Memory store reset completed successfully")
669
+ else:
670
+ # Fallback: try to reset through agent manager if it has a reset method
671
+ if hasattr(self._agent_manager, 'reset'):
672
+ self._agent_manager.reset()
673
+ logger.info("Memory store reset completed successfully")
674
+ else:
675
+ raise RuntimeError("Reset not supported by current manager - no memory instance or reset method available")
676
+ except Exception as e:
677
+ logger.error(f"Failed to reset memory store: {e}")
678
+ raise
679
+
680
+ # Agent-specific methods (for multi-agent mode)
681
+
682
+ def create_agent(self, agent_id: str, agent_name: Optional[str] = None) -> 'AgentMemory':
683
+ """
684
+ Create a new agent (multi-agent mode only).
685
+
686
+ Args:
687
+ agent_id: Unique identifier for the agent
688
+ agent_name: Optional human-readable name for the agent
689
+
690
+ Returns:
691
+ AgentMemory instance for the agent
692
+ """
693
+ if self.mode not in ['multi_agent', 'hybrid']:
694
+ raise RuntimeError(f"create_agent() not supported in {self.mode} mode")
695
+
696
+ # Create a new AgentMemory instance for this specific agent
697
+ agent_config = self.config.copy()
698
+ agent_config['agent_id'] = agent_id
699
+
700
+ return AgentMemory(config=agent_config, mode=self.mode)
701
+
702
+ def create_group(self, group_name: str, agent_ids: List[str], permissions: Optional[Dict[str, List[str]]] = None) -> Dict[str, Any]:
703
+ """
704
+ Create an agent group (multi-agent mode only).
705
+
706
+ Args:
707
+ group_name: Name of the group
708
+ agent_ids: List of agent IDs to include in the group
709
+ permissions: Optional permissions configuration
710
+
711
+ Returns:
712
+ Dictionary containing group creation result
713
+ """
714
+ if self.mode not in ['multi_agent', 'hybrid']:
715
+ raise RuntimeError(f"create_group() not supported in {self.mode} mode")
716
+
717
+ if hasattr(self._agent_manager, 'create_group'):
718
+ return self._agent_manager.create_group(group_name, agent_ids, permissions)
719
+ else:
720
+ raise RuntimeError("Group creation not supported by current manager")
721
+
722
+ def share_memory(self, memory_id: str, from_agent: str, to_agents: List[str], permissions: Optional[List[str]] = None) -> Dict[str, Any]:
723
+ """
724
+ Share a memory between agents (multi-agent mode only).
725
+
726
+ Args:
727
+ memory_id: ID of the memory to share
728
+ from_agent: ID of the agent sharing the memory
729
+ to_agents: List of agent IDs to share with
730
+ permissions: Optional list of permissions to grant
731
+
732
+ Returns:
733
+ Dictionary containing sharing result
734
+ """
735
+ if self.mode not in ['multi_agent', 'hybrid']:
736
+ raise RuntimeError(f"share_memory() not supported in {self.mode} mode")
737
+
738
+ if hasattr(self._agent_manager, 'share_memory'):
739
+ return self._agent_manager.share_memory(memory_id, from_agent, to_agents, permissions)
740
+ else:
741
+ raise RuntimeError("Memory sharing not supported by current manager")
742
+
743
+ # Statistics and monitoring
744
+
745
+ def get_statistics(self) -> Dict[str, Any]:
746
+ """
747
+ Get statistics about the memory system.
748
+
749
+ Returns:
750
+ Dictionary containing memory statistics
751
+ """
752
+ if not self._initialized:
753
+ raise RuntimeError("AgentMemory not initialized")
754
+
755
+ try:
756
+ if hasattr(self._agent_manager, 'get_memory_statistics'):
757
+ return self._agent_manager.get_memory_statistics()
758
+ else:
759
+ # Fallback to basic statistics
760
+ all_memories = self.get_all()
761
+ return {
762
+ 'total_memories': len(all_memories),
763
+ 'mode': self.mode,
764
+ 'initialized': self._initialized
765
+ }
766
+
767
+ except Exception as e:
768
+ logger.error(f"Failed to get statistics: {e}")
769
+ raise
770
+
771
+ def get_mode(self) -> str:
772
+ """Get the current mode."""
773
+ return self.mode
774
+
775
+ def switch_mode(self, new_mode: str) -> bool:
776
+ """
777
+ Switch to a different mode (hybrid mode only).
778
+
779
+ Args:
780
+ new_mode: New mode to switch to
781
+
782
+ Returns:
783
+ True if successful, False otherwise
784
+ """
785
+ if self.mode != 'hybrid':
786
+ raise RuntimeError(f"Mode switching only supported in hybrid mode, current mode: {self.mode}")
787
+
788
+ if hasattr(self._agent_manager, 'switch_mode'):
789
+ return self._agent_manager.switch_mode(new_mode)
790
+ else:
791
+ raise RuntimeError("Mode switching not supported by current manager")