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
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SQLite vector store implementation
|
|
3
|
+
|
|
4
|
+
This module provides a simple SQLite-based vector store for development and testing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import sqlite3
|
|
11
|
+
import threading
|
|
12
|
+
from typing import Any, Dict, List, Optional
|
|
13
|
+
|
|
14
|
+
from powermem.storage.base import VectorStoreBase, OutputData
|
|
15
|
+
from powermem.utils.utils import generate_snowflake_id
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SQLiteVectorStore(VectorStoreBase):
|
|
21
|
+
"""Simple SQLite-based vector store implementation."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, database_path: str = ":memory:", collection_name: str = "memories", **kwargs):
|
|
24
|
+
"""
|
|
25
|
+
Initialize SQLite vector store.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
database_path: Path to SQLite database file
|
|
29
|
+
collection_name: Name of the collection/table
|
|
30
|
+
"""
|
|
31
|
+
self.db_path = database_path
|
|
32
|
+
self.collection_name = collection_name
|
|
33
|
+
self.connection = None
|
|
34
|
+
self._lock = threading.Lock()
|
|
35
|
+
|
|
36
|
+
# Create directory if database path is not in-memory and directory doesn't exist
|
|
37
|
+
if database_path != ":memory:":
|
|
38
|
+
db_dir = os.path.dirname(os.path.abspath(database_path))
|
|
39
|
+
if db_dir and not os.path.exists(db_dir):
|
|
40
|
+
try:
|
|
41
|
+
os.makedirs(db_dir, exist_ok=True)
|
|
42
|
+
logger.info(f"Created database directory: {db_dir}")
|
|
43
|
+
except OSError as e:
|
|
44
|
+
logger.error(f"Failed to create database directory {db_dir}: {e}")
|
|
45
|
+
raise
|
|
46
|
+
|
|
47
|
+
# Connect to database
|
|
48
|
+
try:
|
|
49
|
+
self.connection = sqlite3.connect(database_path, check_same_thread=False)
|
|
50
|
+
except Exception as e:
|
|
51
|
+
logger.error(f"Failed to connect to SQLite database at {database_path}: {e}")
|
|
52
|
+
raise
|
|
53
|
+
|
|
54
|
+
# Create the table
|
|
55
|
+
self.create_col()
|
|
56
|
+
|
|
57
|
+
logger.info(f"SQLiteVectorStore initialized with db_path: {database_path}")
|
|
58
|
+
|
|
59
|
+
def create_col(self, name=None, vector_size=None, distance=None) -> None:
|
|
60
|
+
"""Create a new collection (table in SQLite)."""
|
|
61
|
+
table_name = name or self.collection_name
|
|
62
|
+
|
|
63
|
+
with self._lock:
|
|
64
|
+
self.connection.execute(f"""
|
|
65
|
+
CREATE TABLE IF NOT EXISTS {table_name} (
|
|
66
|
+
id INTEGER PRIMARY KEY,
|
|
67
|
+
vector TEXT, -- Store as JSON string
|
|
68
|
+
payload TEXT, -- Store as JSON string
|
|
69
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
70
|
+
)
|
|
71
|
+
""")
|
|
72
|
+
self.connection.commit()
|
|
73
|
+
|
|
74
|
+
def insert(self, vectors: List[List[float]], payloads=None, ids=None) -> List[int]:
|
|
75
|
+
"""
|
|
76
|
+
Insert vectors into the collection.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
vectors: List of vectors to insert
|
|
80
|
+
payloads: List of payload dictionaries
|
|
81
|
+
ids: Deprecated parameter (ignored), IDs are now generated using Snowflake algorithm
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
List[int]: List of generated Snowflake IDs
|
|
85
|
+
"""
|
|
86
|
+
if not vectors:
|
|
87
|
+
return []
|
|
88
|
+
|
|
89
|
+
if payloads is None:
|
|
90
|
+
payloads = [{} for _ in vectors]
|
|
91
|
+
|
|
92
|
+
# Generate Snowflake IDs for each vector
|
|
93
|
+
generated_ids = [generate_snowflake_id() for _ in range(len(vectors))]
|
|
94
|
+
|
|
95
|
+
with self._lock:
|
|
96
|
+
for vector, payload, vector_id in zip(vectors, payloads, generated_ids):
|
|
97
|
+
self.connection.execute(f"""
|
|
98
|
+
INSERT INTO {self.collection_name}
|
|
99
|
+
(id, vector, payload) VALUES (?, ?, ?)
|
|
100
|
+
""", (vector_id, json.dumps(vector), json.dumps(payload)))
|
|
101
|
+
|
|
102
|
+
self.connection.commit()
|
|
103
|
+
|
|
104
|
+
return generated_ids
|
|
105
|
+
|
|
106
|
+
def search(self, query: str, vectors: List[List[float]] = None, limit: int = 5, filters=None) -> List[OutputData]:
|
|
107
|
+
"""Search for similar vectors using simple cosine similarity."""
|
|
108
|
+
results = []
|
|
109
|
+
|
|
110
|
+
# Extract query vector from vectors parameter (OceanBase format)
|
|
111
|
+
if vectors and len(vectors) > 0:
|
|
112
|
+
query_vector = vectors[0]
|
|
113
|
+
else:
|
|
114
|
+
# Fallback for backward compatibility
|
|
115
|
+
query_vector = query if isinstance(query, list) else [0.1] * 10
|
|
116
|
+
|
|
117
|
+
# Build query with filters
|
|
118
|
+
query_sql = f"SELECT id, vector, payload FROM {self.collection_name}"
|
|
119
|
+
query_params = []
|
|
120
|
+
|
|
121
|
+
# Apply filters if provided
|
|
122
|
+
if filters:
|
|
123
|
+
conditions = []
|
|
124
|
+
for key, value in filters.items():
|
|
125
|
+
# Filter by JSON field in payload
|
|
126
|
+
conditions.append(f"json_extract(payload, '$.{key}') = ?")
|
|
127
|
+
query_params.append(value)
|
|
128
|
+
|
|
129
|
+
if conditions:
|
|
130
|
+
query_sql += " WHERE " + " AND ".join(conditions)
|
|
131
|
+
logger.info(f"SQLite search with filters: {query_sql}, params: {query_params}")
|
|
132
|
+
else:
|
|
133
|
+
logger.debug("SQLite search: filters provided but empty after processing")
|
|
134
|
+
else:
|
|
135
|
+
logger.debug("SQLite search: no filters provided")
|
|
136
|
+
|
|
137
|
+
with self._lock:
|
|
138
|
+
if query_params:
|
|
139
|
+
cursor = self.connection.execute(query_sql, query_params)
|
|
140
|
+
else:
|
|
141
|
+
cursor = self.connection.execute(query_sql)
|
|
142
|
+
|
|
143
|
+
row_count = 0
|
|
144
|
+
for row in cursor.fetchall():
|
|
145
|
+
row_count += 1
|
|
146
|
+
vector_id, vector_str, payload_str = row
|
|
147
|
+
vector = json.loads(vector_str)
|
|
148
|
+
payload = json.loads(payload_str)
|
|
149
|
+
|
|
150
|
+
# Calculate cosine similarity
|
|
151
|
+
similarity = self._cosine_similarity(query_vector, vector)
|
|
152
|
+
|
|
153
|
+
results.append(OutputData(
|
|
154
|
+
id=vector_id,
|
|
155
|
+
score=similarity,
|
|
156
|
+
payload=payload
|
|
157
|
+
))
|
|
158
|
+
|
|
159
|
+
# Sort by similarity (descending) and return top results
|
|
160
|
+
results.sort(key=lambda x: x.score, reverse=True)
|
|
161
|
+
return results[:limit]
|
|
162
|
+
|
|
163
|
+
def delete(self, vector_id: int) -> None:
|
|
164
|
+
"""Delete a vector by ID."""
|
|
165
|
+
with self._lock:
|
|
166
|
+
self.connection.execute(f"""
|
|
167
|
+
DELETE FROM {self.collection_name} WHERE id = ?
|
|
168
|
+
""", (vector_id,))
|
|
169
|
+
self.connection.commit()
|
|
170
|
+
|
|
171
|
+
def update(self, vector_id: int, vector=None, payload=None) -> None:
|
|
172
|
+
"""Update a vector and its payload."""
|
|
173
|
+
updates = []
|
|
174
|
+
values = []
|
|
175
|
+
|
|
176
|
+
if vector is not None:
|
|
177
|
+
updates.append("vector = ?")
|
|
178
|
+
values.append(json.dumps(vector))
|
|
179
|
+
|
|
180
|
+
if payload is not None:
|
|
181
|
+
updates.append("payload = ?")
|
|
182
|
+
values.append(json.dumps(payload))
|
|
183
|
+
|
|
184
|
+
if updates:
|
|
185
|
+
values.append(vector_id)
|
|
186
|
+
with self._lock:
|
|
187
|
+
self.connection.execute(f"""
|
|
188
|
+
UPDATE {self.collection_name}
|
|
189
|
+
SET {', '.join(updates)}
|
|
190
|
+
WHERE id = ?
|
|
191
|
+
""", values)
|
|
192
|
+
self.connection.commit()
|
|
193
|
+
|
|
194
|
+
def get(self, vector_id: int) -> Optional[OutputData]:
|
|
195
|
+
"""Retrieve a vector by ID."""
|
|
196
|
+
with self._lock:
|
|
197
|
+
cursor = self.connection.execute(f"""
|
|
198
|
+
SELECT id, vector, payload FROM {self.collection_name} WHERE id = ?
|
|
199
|
+
""", (vector_id,))
|
|
200
|
+
|
|
201
|
+
row = cursor.fetchone()
|
|
202
|
+
if row:
|
|
203
|
+
vector_id, vector_str, payload_str = row
|
|
204
|
+
vector = json.loads(vector_str)
|
|
205
|
+
payload = json.loads(payload_str)
|
|
206
|
+
|
|
207
|
+
return OutputData(
|
|
208
|
+
id=vector_id,
|
|
209
|
+
score=1.0, # Exact match
|
|
210
|
+
payload=payload
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
def list_cols(self) -> List[str]:
|
|
216
|
+
"""List all collections (tables)."""
|
|
217
|
+
with self._lock:
|
|
218
|
+
cursor = self.connection.execute("""
|
|
219
|
+
SELECT name FROM sqlite_master WHERE type='table'
|
|
220
|
+
""")
|
|
221
|
+
return [row[0] for row in cursor.fetchall()]
|
|
222
|
+
|
|
223
|
+
def delete_col(self) -> None:
|
|
224
|
+
"""Delete the collection (table)."""
|
|
225
|
+
with self._lock:
|
|
226
|
+
self.connection.execute(f"DROP TABLE IF EXISTS {self.collection_name}")
|
|
227
|
+
self.connection.commit()
|
|
228
|
+
|
|
229
|
+
def col_info(self) -> Dict[str, Any]:
|
|
230
|
+
"""Get information about the collection."""
|
|
231
|
+
with self._lock:
|
|
232
|
+
cursor = self.connection.execute(f"""
|
|
233
|
+
SELECT COUNT(*) FROM {self.collection_name}
|
|
234
|
+
""")
|
|
235
|
+
count = cursor.fetchone()[0]
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
"name": self.collection_name,
|
|
239
|
+
"count": count,
|
|
240
|
+
"db_path": self.db_path
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
def list(self, filters=None, limit=None) -> List[OutputData]:
|
|
244
|
+
"""List all memories with optional filtering."""
|
|
245
|
+
query = f"SELECT id, vector, payload FROM {self.collection_name}"
|
|
246
|
+
query_params = []
|
|
247
|
+
|
|
248
|
+
# Apply filters if provided
|
|
249
|
+
if filters:
|
|
250
|
+
conditions = []
|
|
251
|
+
for key, value in filters.items():
|
|
252
|
+
# Filter by JSON field in payload
|
|
253
|
+
conditions.append(f"json_extract(payload, '$.{key}') = ?")
|
|
254
|
+
query_params.append(value)
|
|
255
|
+
|
|
256
|
+
if conditions:
|
|
257
|
+
query += " WHERE " + " AND ".join(conditions)
|
|
258
|
+
|
|
259
|
+
if limit:
|
|
260
|
+
query += f" LIMIT {limit}"
|
|
261
|
+
|
|
262
|
+
results = []
|
|
263
|
+
with self._lock:
|
|
264
|
+
if query_params:
|
|
265
|
+
cursor = self.connection.execute(query, query_params)
|
|
266
|
+
else:
|
|
267
|
+
cursor = self.connection.execute(query)
|
|
268
|
+
|
|
269
|
+
for row in cursor.fetchall():
|
|
270
|
+
vector_id, vector_str, payload_str = row
|
|
271
|
+
vector = json.loads(vector_str)
|
|
272
|
+
payload = json.loads(payload_str)
|
|
273
|
+
|
|
274
|
+
results.append(OutputData(
|
|
275
|
+
id=vector_id,
|
|
276
|
+
score=1.0,
|
|
277
|
+
payload=payload
|
|
278
|
+
))
|
|
279
|
+
|
|
280
|
+
return results
|
|
281
|
+
|
|
282
|
+
def reset(self) -> None:
|
|
283
|
+
"""Reset by deleting and recreating the collection."""
|
|
284
|
+
self.delete_col()
|
|
285
|
+
self.create_col()
|
|
286
|
+
|
|
287
|
+
def _cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
|
|
288
|
+
"""Calculate cosine similarity between two vectors."""
|
|
289
|
+
if len(vec1) != len(vec2):
|
|
290
|
+
return 0.0
|
|
291
|
+
|
|
292
|
+
dot_product = sum(a * b for a, b in zip(vec1, vec2))
|
|
293
|
+
magnitude1 = sum(a * a for a in vec1) ** 0.5
|
|
294
|
+
magnitude2 = sum(b * b for b in vec2) ** 0.5
|
|
295
|
+
|
|
296
|
+
if magnitude1 == 0 or magnitude2 == 0:
|
|
297
|
+
return 0.0
|
|
298
|
+
|
|
299
|
+
return dot_product / (magnitude1 * magnitude2)
|
|
300
|
+
|
|
301
|
+
def close(self) -> None:
|
|
302
|
+
"""Close the database connection."""
|
|
303
|
+
if hasattr(self, 'connection') and self.connection:
|
|
304
|
+
self.connection.close()
|
|
305
|
+
self.connection = None
|
|
306
|
+
|
|
307
|
+
def __del__(self):
|
|
308
|
+
try:
|
|
309
|
+
self.close()
|
|
310
|
+
except Exception:
|
|
311
|
+
pass # Ignore errors during cleanup
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions and classes
|
|
3
|
+
|
|
4
|
+
This module provides utility functions and helper classes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .utils import (
|
|
8
|
+
generate_memory_id,
|
|
9
|
+
validate_memory_data,
|
|
10
|
+
sanitize_content,
|
|
11
|
+
format_memory_for_display,
|
|
12
|
+
merge_memories,
|
|
13
|
+
calculate_similarity,
|
|
14
|
+
extract_keywords,
|
|
15
|
+
format_timestamp,
|
|
16
|
+
parse_timestamp,
|
|
17
|
+
extract_json,
|
|
18
|
+
load_config_from_env,
|
|
19
|
+
convert_config_object_to_dict,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"generate_memory_id",
|
|
24
|
+
"validate_memory_data",
|
|
25
|
+
"sanitize_content",
|
|
26
|
+
"format_memory_for_display",
|
|
27
|
+
"merge_memories",
|
|
28
|
+
"calculate_similarity",
|
|
29
|
+
"extract_keywords",
|
|
30
|
+
"format_timestamp",
|
|
31
|
+
"parse_timestamp",
|
|
32
|
+
"extract_json",
|
|
33
|
+
"load_config_from_env",
|
|
34
|
+
"convert_config_object_to_dict",
|
|
35
|
+
]
|