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,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
+ ]