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.
- powermem/__init__.py +103 -0
- powermem/agent/__init__.py +35 -0
- powermem/agent/abstract/__init__.py +22 -0
- powermem/agent/abstract/collaboration.py +259 -0
- powermem/agent/abstract/context.py +187 -0
- powermem/agent/abstract/manager.py +232 -0
- powermem/agent/abstract/permission.py +217 -0
- powermem/agent/abstract/privacy.py +267 -0
- powermem/agent/abstract/scope.py +199 -0
- powermem/agent/agent.py +791 -0
- powermem/agent/components/__init__.py +18 -0
- powermem/agent/components/collaboration_coordinator.py +645 -0
- powermem/agent/components/permission_controller.py +586 -0
- powermem/agent/components/privacy_protector.py +767 -0
- powermem/agent/components/scope_controller.py +685 -0
- powermem/agent/factories/__init__.py +16 -0
- powermem/agent/factories/agent_factory.py +266 -0
- powermem/agent/factories/config_factory.py +308 -0
- powermem/agent/factories/memory_factory.py +229 -0
- powermem/agent/implementations/__init__.py +16 -0
- powermem/agent/implementations/hybrid.py +728 -0
- powermem/agent/implementations/multi_agent.py +1040 -0
- powermem/agent/implementations/multi_user.py +1020 -0
- powermem/agent/types.py +53 -0
- powermem/agent/wrappers/__init__.py +14 -0
- powermem/agent/wrappers/agent_memory_wrapper.py +427 -0
- powermem/agent/wrappers/compatibility_wrapper.py +520 -0
- powermem/config_loader.py +318 -0
- powermem/configs.py +249 -0
- powermem/core/__init__.py +19 -0
- powermem/core/async_memory.py +1493 -0
- powermem/core/audit.py +258 -0
- powermem/core/base.py +165 -0
- powermem/core/memory.py +1567 -0
- powermem/core/setup.py +162 -0
- powermem/core/telemetry.py +215 -0
- powermem/integrations/__init__.py +17 -0
- powermem/integrations/embeddings/__init__.py +13 -0
- powermem/integrations/embeddings/aws_bedrock.py +100 -0
- powermem/integrations/embeddings/azure_openai.py +55 -0
- powermem/integrations/embeddings/base.py +31 -0
- powermem/integrations/embeddings/config/base.py +132 -0
- powermem/integrations/embeddings/configs.py +31 -0
- powermem/integrations/embeddings/factory.py +48 -0
- powermem/integrations/embeddings/gemini.py +39 -0
- powermem/integrations/embeddings/huggingface.py +41 -0
- powermem/integrations/embeddings/langchain.py +35 -0
- powermem/integrations/embeddings/lmstudio.py +29 -0
- powermem/integrations/embeddings/mock.py +11 -0
- powermem/integrations/embeddings/ollama.py +53 -0
- powermem/integrations/embeddings/openai.py +49 -0
- powermem/integrations/embeddings/qwen.py +102 -0
- powermem/integrations/embeddings/together.py +31 -0
- powermem/integrations/embeddings/vertexai.py +54 -0
- powermem/integrations/llm/__init__.py +18 -0
- powermem/integrations/llm/anthropic.py +87 -0
- powermem/integrations/llm/base.py +132 -0
- powermem/integrations/llm/config/anthropic.py +56 -0
- powermem/integrations/llm/config/azure.py +56 -0
- powermem/integrations/llm/config/base.py +62 -0
- powermem/integrations/llm/config/deepseek.py +56 -0
- powermem/integrations/llm/config/ollama.py +56 -0
- powermem/integrations/llm/config/openai.py +79 -0
- powermem/integrations/llm/config/qwen.py +68 -0
- powermem/integrations/llm/config/qwen_asr.py +46 -0
- powermem/integrations/llm/config/vllm.py +56 -0
- powermem/integrations/llm/configs.py +26 -0
- powermem/integrations/llm/deepseek.py +106 -0
- powermem/integrations/llm/factory.py +118 -0
- powermem/integrations/llm/gemini.py +201 -0
- powermem/integrations/llm/langchain.py +65 -0
- powermem/integrations/llm/ollama.py +106 -0
- powermem/integrations/llm/openai.py +166 -0
- powermem/integrations/llm/openai_structured.py +80 -0
- powermem/integrations/llm/qwen.py +207 -0
- powermem/integrations/llm/qwen_asr.py +171 -0
- powermem/integrations/llm/vllm.py +106 -0
- powermem/integrations/rerank/__init__.py +20 -0
- powermem/integrations/rerank/base.py +43 -0
- powermem/integrations/rerank/config/__init__.py +7 -0
- powermem/integrations/rerank/config/base.py +27 -0
- powermem/integrations/rerank/configs.py +23 -0
- powermem/integrations/rerank/factory.py +68 -0
- powermem/integrations/rerank/qwen.py +159 -0
- powermem/intelligence/__init__.py +17 -0
- powermem/intelligence/ebbinghaus_algorithm.py +354 -0
- powermem/intelligence/importance_evaluator.py +361 -0
- powermem/intelligence/intelligent_memory_manager.py +284 -0
- powermem/intelligence/manager.py +148 -0
- powermem/intelligence/plugin.py +229 -0
- powermem/prompts/__init__.py +29 -0
- powermem/prompts/graph/graph_prompts.py +217 -0
- powermem/prompts/graph/graph_tools_prompts.py +469 -0
- powermem/prompts/importance_evaluation.py +246 -0
- powermem/prompts/intelligent_memory_prompts.py +163 -0
- powermem/prompts/templates.py +193 -0
- powermem/storage/__init__.py +14 -0
- powermem/storage/adapter.py +896 -0
- powermem/storage/base.py +109 -0
- powermem/storage/config/base.py +13 -0
- powermem/storage/config/oceanbase.py +58 -0
- powermem/storage/config/pgvector.py +52 -0
- powermem/storage/config/sqlite.py +27 -0
- powermem/storage/configs.py +159 -0
- powermem/storage/factory.py +59 -0
- powermem/storage/migration_manager.py +438 -0
- powermem/storage/oceanbase/__init__.py +8 -0
- powermem/storage/oceanbase/constants.py +162 -0
- powermem/storage/oceanbase/oceanbase.py +1384 -0
- powermem/storage/oceanbase/oceanbase_graph.py +1441 -0
- powermem/storage/pgvector/__init__.py +7 -0
- powermem/storage/pgvector/pgvector.py +420 -0
- powermem/storage/sqlite/__init__.py +0 -0
- powermem/storage/sqlite/sqlite.py +218 -0
- powermem/storage/sqlite/sqlite_vector_store.py +311 -0
- powermem/utils/__init__.py +35 -0
- powermem/utils/utils.py +605 -0
- powermem/version.py +23 -0
- powermem-0.1.0.dist-info/METADATA +187 -0
- powermem-0.1.0.dist-info/RECORD +123 -0
- powermem-0.1.0.dist-info/WHEEL +5 -0
- powermem-0.1.0.dist-info/licenses/LICENSE +206 -0
- powermem-0.1.0.dist-info/top_level.txt +1 -0
powermem/agent/agent.py
ADDED
|
@@ -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")
|