comemo 2.0.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.
- cognitivememory/__init__.py +39 -0
- cognitivememory/client.py +412 -0
- cognitivememory/exceptions.py +27 -0
- cognitivememory/models.py +83 -0
- comemo-2.0.0.dist-info/METADATA +187 -0
- comemo-2.0.0.dist-info/RECORD +7 -0
- comemo-2.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Cognitive Memory SDK - Python client for the Cognitive Memory API."""
|
|
2
|
+
|
|
3
|
+
from .client import MemoryClient
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
CognitiveMemoryError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
ServerError,
|
|
9
|
+
ValidationError,
|
|
10
|
+
)
|
|
11
|
+
from .models import (
|
|
12
|
+
AddMemoryResult,
|
|
13
|
+
DeleteResult,
|
|
14
|
+
DetailedMemory,
|
|
15
|
+
DetailedRetrieveResult,
|
|
16
|
+
HealthResult,
|
|
17
|
+
Memory,
|
|
18
|
+
RetrieveResult,
|
|
19
|
+
RetrieveSummaryResult,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__version__ = "2.0.0"
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"MemoryClient",
|
|
26
|
+
"AddMemoryResult",
|
|
27
|
+
"DeleteResult",
|
|
28
|
+
"DetailedMemory",
|
|
29
|
+
"DetailedRetrieveResult",
|
|
30
|
+
"HealthResult",
|
|
31
|
+
"Memory",
|
|
32
|
+
"RetrieveResult",
|
|
33
|
+
"RetrieveSummaryResult",
|
|
34
|
+
"CognitiveMemoryError",
|
|
35
|
+
"AuthenticationError",
|
|
36
|
+
"NotFoundError",
|
|
37
|
+
"ServerError",
|
|
38
|
+
"ValidationError",
|
|
39
|
+
]
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"""Cognitive Memory SDK client."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from .exceptions import (
|
|
6
|
+
AuthenticationError,
|
|
7
|
+
CognitiveMemoryError,
|
|
8
|
+
NotFoundError,
|
|
9
|
+
ServerError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
)
|
|
12
|
+
from .models import (
|
|
13
|
+
AddMemoryResult,
|
|
14
|
+
DeleteResult,
|
|
15
|
+
DetailedMemory,
|
|
16
|
+
DetailedRetrieveResult,
|
|
17
|
+
HealthResult,
|
|
18
|
+
Memory,
|
|
19
|
+
RetrieveResult,
|
|
20
|
+
RetrieveSummaryResult,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MemoryClient:
|
|
25
|
+
"""Client for the Cognitive Memory API.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
api_key: LLM API key (e.g. OpenAI key).
|
|
29
|
+
model: LLM model name (e.g. "gpt-4o-mini").
|
|
30
|
+
pinecone_api_key: Pinecone API key.
|
|
31
|
+
pinecone_index_name: Pinecone index name. Defaults to "cognitivememory".
|
|
32
|
+
neo4j_uri: Neo4j connection URI.
|
|
33
|
+
neo4j_user: Neo4j username.
|
|
34
|
+
neo4j_password: Neo4j password.
|
|
35
|
+
base_url: Base URL of the API. Defaults to "https://xvert.io".
|
|
36
|
+
timeout: Request timeout in seconds. Defaults to 30.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
api_key: str,
|
|
42
|
+
model: str,
|
|
43
|
+
pinecone_api_key: str,
|
|
44
|
+
neo4j_uri: str,
|
|
45
|
+
neo4j_user: str,
|
|
46
|
+
neo4j_password: str,
|
|
47
|
+
pinecone_index_name: str = "cognitivememory",
|
|
48
|
+
base_url: str = "https://xvert.io",
|
|
49
|
+
timeout: float = 30,
|
|
50
|
+
):
|
|
51
|
+
self.base_url = base_url.rstrip("/")
|
|
52
|
+
self.api_key = api_key
|
|
53
|
+
self.model = model
|
|
54
|
+
self.pinecone_api_key = pinecone_api_key
|
|
55
|
+
self.pinecone_index_name = pinecone_index_name
|
|
56
|
+
self.neo4j_uri = neo4j_uri
|
|
57
|
+
self.neo4j_user = neo4j_user
|
|
58
|
+
self.neo4j_password = neo4j_password
|
|
59
|
+
self.timeout = timeout
|
|
60
|
+
|
|
61
|
+
self._client = httpx.Client(
|
|
62
|
+
base_url=self.base_url,
|
|
63
|
+
headers={"Content-Type": "application/json"},
|
|
64
|
+
timeout=timeout,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def _credential_fields(self) -> dict:
|
|
68
|
+
"""Return all credential fields to include in request bodies."""
|
|
69
|
+
return {
|
|
70
|
+
"api_key": self.api_key,
|
|
71
|
+
"model": self.model,
|
|
72
|
+
"pinecone_api_key": self.pinecone_api_key,
|
|
73
|
+
"pinecone_index_name": self.pinecone_index_name,
|
|
74
|
+
"neo4j_uri": self.neo4j_uri,
|
|
75
|
+
"neo4j_user": self.neo4j_user,
|
|
76
|
+
"neo4j_password": self.neo4j_password,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
def _credential_params(self) -> dict:
|
|
80
|
+
"""Return credential fields as query params (for GET/DELETE endpoints)."""
|
|
81
|
+
return {
|
|
82
|
+
"pinecone_api_key": self.pinecone_api_key,
|
|
83
|
+
"pinecone_index_name": self.pinecone_index_name,
|
|
84
|
+
"neo4j_uri": self.neo4j_uri,
|
|
85
|
+
"neo4j_user": self.neo4j_user,
|
|
86
|
+
"neo4j_password": self.neo4j_password,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def _handle_response(self, response: httpx.Response) -> dict:
|
|
90
|
+
"""Parse response and raise appropriate exceptions on errors."""
|
|
91
|
+
if response.status_code >= 400:
|
|
92
|
+
try:
|
|
93
|
+
body = response.json()
|
|
94
|
+
detail = body.get("detail", response.text)
|
|
95
|
+
except Exception:
|
|
96
|
+
detail = response.text
|
|
97
|
+
|
|
98
|
+
if response.status_code in (401, 403):
|
|
99
|
+
raise AuthenticationError(detail, response.status_code)
|
|
100
|
+
if response.status_code == 404:
|
|
101
|
+
raise NotFoundError(detail, response.status_code)
|
|
102
|
+
if response.status_code in (400, 422):
|
|
103
|
+
raise ValidationError(detail, response.status_code)
|
|
104
|
+
if response.status_code >= 500:
|
|
105
|
+
raise ServerError(detail, response.status_code)
|
|
106
|
+
raise CognitiveMemoryError(detail, response.status_code)
|
|
107
|
+
|
|
108
|
+
return response.json()
|
|
109
|
+
|
|
110
|
+
# ── Core Memory Operations ──────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
def add_memory(self, user_id: str, session_id: str, text: str) -> AddMemoryResult:
|
|
113
|
+
"""Extract facts from text and store them as memories.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
user_id: User ID for memory isolation.
|
|
117
|
+
session_id: Session ID for context grouping.
|
|
118
|
+
text: Input text to extract facts from.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
AddMemoryResult with status, action taken, memory_id, links created, and score.
|
|
122
|
+
"""
|
|
123
|
+
data = self._handle_response(
|
|
124
|
+
self._client.post("/memory", json={
|
|
125
|
+
"user_id": user_id,
|
|
126
|
+
"session_id": session_id,
|
|
127
|
+
"input": text,
|
|
128
|
+
**self._credential_fields(),
|
|
129
|
+
})
|
|
130
|
+
)
|
|
131
|
+
return AddMemoryResult(
|
|
132
|
+
status=data.get("status", ""),
|
|
133
|
+
action=data.get("action", ""),
|
|
134
|
+
memory_id=data.get("memory_id"),
|
|
135
|
+
links_created=data.get("links_created", 0),
|
|
136
|
+
score=data.get("score", 0.0),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def delete_memory(self, memory_id: str) -> dict:
|
|
140
|
+
"""Delete a single memory by ID.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
memory_id: The memory identifier to delete.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Dict with status, memory_id, and deleted flag.
|
|
147
|
+
"""
|
|
148
|
+
return self._handle_response(
|
|
149
|
+
self._client.delete(f"/memory/{memory_id}", params=self._credential_params())
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def delete_user_memories(self, user_id: str) -> DeleteResult:
|
|
153
|
+
"""Delete all memories for a user.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
user_id: The user whose memories to delete.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
DeleteResult with count of deleted memories.
|
|
160
|
+
"""
|
|
161
|
+
data = self._handle_response(
|
|
162
|
+
self._client.delete("/memory", params={"user_id": user_id, **self._credential_params()})
|
|
163
|
+
)
|
|
164
|
+
return DeleteResult(
|
|
165
|
+
status=data.get("status", ""),
|
|
166
|
+
user_id=data.get("user_id", user_id),
|
|
167
|
+
memories_deleted=data.get("memories_deleted", 0),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def delete_session_memories(self, user_id: str, session_id: str) -> DeleteResult:
|
|
171
|
+
"""Delete all memories for a specific session.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
user_id: The user ID.
|
|
175
|
+
session_id: The session whose memories to delete.
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
DeleteResult with count of deleted memories.
|
|
179
|
+
"""
|
|
180
|
+
data = self._handle_response(
|
|
181
|
+
self._client.delete(f"/memory/session/{session_id}", params={"user_id": user_id, **self._credential_params()})
|
|
182
|
+
)
|
|
183
|
+
return DeleteResult(
|
|
184
|
+
status=data.get("status", ""),
|
|
185
|
+
user_id=data.get("user_id", user_id),
|
|
186
|
+
memories_deleted=data.get("memories_deleted", 0),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# ── Retrieval ───────────────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
def retrieve(self, user_id: str, session_id: str, query: str, top_k: int = 5) -> RetrieveResult:
|
|
192
|
+
"""Retrieve top memories matching a query (simple mode).
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
user_id: User ID for namespace isolation.
|
|
196
|
+
session_id: Current session ID.
|
|
197
|
+
query: Search query text.
|
|
198
|
+
top_k: Maximum number of results (1-50). Defaults to 5.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
RetrieveResult with query, expanded query, and list of memories.
|
|
202
|
+
"""
|
|
203
|
+
data = self._handle_response(
|
|
204
|
+
self._client.post("/memories/retrieve", json={
|
|
205
|
+
"user_id": user_id,
|
|
206
|
+
"session_id": session_id,
|
|
207
|
+
"query": query,
|
|
208
|
+
"top_k": top_k,
|
|
209
|
+
**self._credential_fields(),
|
|
210
|
+
})
|
|
211
|
+
)
|
|
212
|
+
memories = [
|
|
213
|
+
Memory(memory_id=m["memory_id"], fact=m["fact"], score=m["score"])
|
|
214
|
+
for m in data.get("memories", [])
|
|
215
|
+
]
|
|
216
|
+
return RetrieveResult(
|
|
217
|
+
query=data.get("query", query),
|
|
218
|
+
expanded_query=data.get("expanded_query", ""),
|
|
219
|
+
memories=memories,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def retrieve_advanced(
|
|
223
|
+
self,
|
|
224
|
+
user_id: str,
|
|
225
|
+
session_id: str,
|
|
226
|
+
query: str,
|
|
227
|
+
top_k: int = 10,
|
|
228
|
+
expand_context: bool = True,
|
|
229
|
+
expand_graph: bool = True,
|
|
230
|
+
min_score: float = 0.1,
|
|
231
|
+
reinforce: bool = False,
|
|
232
|
+
) -> DetailedRetrieveResult:
|
|
233
|
+
"""Retrieve memories with full scoring details and advanced options.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
user_id: User ID for namespace isolation.
|
|
237
|
+
session_id: Current session ID.
|
|
238
|
+
query: Search query text.
|
|
239
|
+
top_k: Maximum number of results (1-50). Defaults to 10.
|
|
240
|
+
expand_context: Use session context for query expansion. Defaults to True.
|
|
241
|
+
expand_graph: Expand via Neo4j graph relationships. Defaults to True.
|
|
242
|
+
min_score: Minimum score threshold (0.0-1.0). Defaults to 0.1.
|
|
243
|
+
reinforce: Reinforce retrieved memories. Defaults to False.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
DetailedRetrieveResult with full scoring breakdown per memory.
|
|
247
|
+
"""
|
|
248
|
+
data = self._handle_response(
|
|
249
|
+
self._client.post("/memory/retrieve", json={
|
|
250
|
+
"user_id": user_id,
|
|
251
|
+
"session_id": session_id,
|
|
252
|
+
"query": query,
|
|
253
|
+
"top_k": top_k,
|
|
254
|
+
"expand_context": expand_context,
|
|
255
|
+
"expand_graph": expand_graph,
|
|
256
|
+
"min_score": min_score,
|
|
257
|
+
"reinforce": reinforce,
|
|
258
|
+
**self._credential_fields(),
|
|
259
|
+
})
|
|
260
|
+
)
|
|
261
|
+
memories = [
|
|
262
|
+
DetailedMemory(
|
|
263
|
+
memory_id=m["memory_id"],
|
|
264
|
+
fact=m["fact"],
|
|
265
|
+
domain=m.get("domain", ""),
|
|
266
|
+
final_score=m.get("final_score", 0.0),
|
|
267
|
+
semantic_similarity=m.get("semantic_similarity", 0.0),
|
|
268
|
+
graph_relevance=m.get("graph_relevance", 0.0),
|
|
269
|
+
memory_strength=m.get("memory_strength", 0.0),
|
|
270
|
+
recency_score=m.get("recency_score", 0.0),
|
|
271
|
+
session_boost=m.get("session_boost", 0.0),
|
|
272
|
+
source=m.get("source", ""),
|
|
273
|
+
session_id=m.get("session_id", ""),
|
|
274
|
+
)
|
|
275
|
+
for m in data.get("memories", [])
|
|
276
|
+
]
|
|
277
|
+
return DetailedRetrieveResult(
|
|
278
|
+
query=data.get("query", query),
|
|
279
|
+
expanded_query=data.get("expanded_query", ""),
|
|
280
|
+
user_id=data.get("user_id", user_id),
|
|
281
|
+
session_id=data.get("session_id", session_id),
|
|
282
|
+
memories=memories,
|
|
283
|
+
total_candidates=data.get("total_candidates", 0),
|
|
284
|
+
filtered_count=data.get("filtered_count", 0),
|
|
285
|
+
retrieval_time_ms=data.get("retrieval_time_ms", 0.0),
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
def retrieve_summary(
|
|
289
|
+
self, user_id: str, session_id: str, query: str, top_k: int = 5
|
|
290
|
+
) -> RetrieveSummaryResult:
|
|
291
|
+
"""Retrieve memories and get an LLM-generated summary.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
user_id: User ID for namespace isolation.
|
|
295
|
+
session_id: Current session ID.
|
|
296
|
+
query: Search query text.
|
|
297
|
+
top_k: Number of memories to summarize (1-20). Defaults to 5.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
RetrieveSummaryResult with summary text and supporting memories.
|
|
301
|
+
"""
|
|
302
|
+
data = self._handle_response(
|
|
303
|
+
self._client.post("/memories/retrieve-summary", json={
|
|
304
|
+
"user_id": user_id,
|
|
305
|
+
"session_id": session_id,
|
|
306
|
+
"query": query,
|
|
307
|
+
"top_k": top_k,
|
|
308
|
+
**self._credential_fields(),
|
|
309
|
+
})
|
|
310
|
+
)
|
|
311
|
+
memories = [
|
|
312
|
+
Memory(memory_id=m["memory_id"], fact=m["fact"], score=m["score"])
|
|
313
|
+
for m in data.get("supporting_memories", [])
|
|
314
|
+
]
|
|
315
|
+
return RetrieveSummaryResult(
|
|
316
|
+
query=data.get("query", query),
|
|
317
|
+
summary=data.get("summary", ""),
|
|
318
|
+
supporting_memories=memories,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
def list_memories(self, user_id: str, query: str, top_k: int = 10) -> RetrieveResult:
|
|
322
|
+
"""List user memories across all sessions.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
user_id: User ID.
|
|
326
|
+
query: Search query text.
|
|
327
|
+
top_k: Maximum number of results (1-50). Defaults to 10.
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
RetrieveResult with matching memories across all sessions.
|
|
331
|
+
"""
|
|
332
|
+
data = self._handle_response(
|
|
333
|
+
self._client.get("/memories", params={
|
|
334
|
+
"user_id": user_id,
|
|
335
|
+
"query": query,
|
|
336
|
+
"top_k": top_k,
|
|
337
|
+
**self._credential_params(),
|
|
338
|
+
})
|
|
339
|
+
)
|
|
340
|
+
memories = [
|
|
341
|
+
Memory(memory_id=m["memory_id"], fact=m["fact"], score=m["score"])
|
|
342
|
+
for m in data.get("memories", [])
|
|
343
|
+
]
|
|
344
|
+
return RetrieveResult(
|
|
345
|
+
query=data.get("query", query),
|
|
346
|
+
expanded_query=data.get("expanded_query", ""),
|
|
347
|
+
memories=memories,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
# ── Maintenance & Governance ────────────────────────────────────────
|
|
351
|
+
|
|
352
|
+
def run_maintenance(self, user_id: str = "") -> dict:
|
|
353
|
+
"""Manually trigger all maintenance tasks (decay, forgetting, summarization).
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
user_id: Optional user ID to scope maintenance. Empty string for all users.
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
Dict with job results for each maintenance task.
|
|
360
|
+
"""
|
|
361
|
+
return self._handle_response(
|
|
362
|
+
self._client.post("/memory/governance/run-all", params={"user_id": user_id})
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# ── System ──────────────────────────────────────────────────────────
|
|
366
|
+
|
|
367
|
+
def delete_all_memories(self, confirm: str = "DELETE_ALL_DATA") -> dict:
|
|
368
|
+
"""Delete ALL memories from ALL users. Destructive and irreversible.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
confirm: Must be exactly "DELETE_ALL_DATA" to confirm.
|
|
372
|
+
|
|
373
|
+
Returns:
|
|
374
|
+
Dict with status, message, and count of deleted memories.
|
|
375
|
+
"""
|
|
376
|
+
return self._handle_response(
|
|
377
|
+
self._client.delete("/memory/all", params={"confirm": confirm, **self._credential_params()})
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def scheduler_status(self) -> dict:
|
|
381
|
+
"""Get current status of the maintenance scheduler.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
Dict with registered jobs, next run times, and recent history.
|
|
385
|
+
"""
|
|
386
|
+
return self._handle_response(self._client.get("/scheduler/status"))
|
|
387
|
+
|
|
388
|
+
def health(self) -> HealthResult:
|
|
389
|
+
"""Check API health and status.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
HealthResult with status, version, architecture, and scheduler info.
|
|
393
|
+
"""
|
|
394
|
+
data = self._handle_response(self._client.get("/health"))
|
|
395
|
+
return HealthResult(
|
|
396
|
+
status=data.get("status", ""),
|
|
397
|
+
version=data.get("version", ""),
|
|
398
|
+
architecture=data.get("architecture", ""),
|
|
399
|
+
scheduler=data.get("scheduler", {}),
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
# ── Context Manager ─────────────────────────────────────────────────
|
|
403
|
+
|
|
404
|
+
def close(self):
|
|
405
|
+
"""Close the underlying HTTP client."""
|
|
406
|
+
self._client.close()
|
|
407
|
+
|
|
408
|
+
def __enter__(self):
|
|
409
|
+
return self
|
|
410
|
+
|
|
411
|
+
def __exit__(self, *args):
|
|
412
|
+
self.close()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Exceptions for the Cognitive Memory SDK."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CognitiveMemoryError(Exception):
|
|
5
|
+
"""Base exception for all SDK errors."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, message: str, status_code: int | None = None, response: dict | None = None):
|
|
8
|
+
self.message = message
|
|
9
|
+
self.status_code = status_code
|
|
10
|
+
self.response = response
|
|
11
|
+
super().__init__(self.message)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AuthenticationError(CognitiveMemoryError):
|
|
15
|
+
"""Raised when authentication fails (401/403)."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NotFoundError(CognitiveMemoryError):
|
|
19
|
+
"""Raised when a resource is not found (404)."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ValidationError(CognitiveMemoryError):
|
|
23
|
+
"""Raised when the request is invalid (400/422)."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ServerError(CognitiveMemoryError):
|
|
27
|
+
"""Raised when the server returns a 5xx error."""
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Response models for the Cognitive Memory SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class AddMemoryResult:
|
|
8
|
+
"""Result of adding a memory."""
|
|
9
|
+
status: str
|
|
10
|
+
action: str
|
|
11
|
+
memory_id: str | None
|
|
12
|
+
links_created: int
|
|
13
|
+
score: float
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Memory:
|
|
18
|
+
"""A retrieved memory."""
|
|
19
|
+
memory_id: str
|
|
20
|
+
fact: str
|
|
21
|
+
score: float
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class DetailedMemory:
|
|
26
|
+
"""A retrieved memory with detailed scoring breakdown."""
|
|
27
|
+
memory_id: str
|
|
28
|
+
fact: str
|
|
29
|
+
domain: str
|
|
30
|
+
final_score: float
|
|
31
|
+
semantic_similarity: float
|
|
32
|
+
graph_relevance: float
|
|
33
|
+
memory_strength: float
|
|
34
|
+
recency_score: float
|
|
35
|
+
session_boost: float
|
|
36
|
+
source: str
|
|
37
|
+
session_id: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class RetrieveResult:
|
|
42
|
+
"""Result of a simple retrieval."""
|
|
43
|
+
query: str
|
|
44
|
+
expanded_query: str
|
|
45
|
+
memories: list[Memory]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class DetailedRetrieveResult:
|
|
50
|
+
"""Result of an advanced retrieval with full scoring details."""
|
|
51
|
+
query: str
|
|
52
|
+
expanded_query: str
|
|
53
|
+
user_id: str
|
|
54
|
+
session_id: str
|
|
55
|
+
memories: list[DetailedMemory]
|
|
56
|
+
total_candidates: int
|
|
57
|
+
filtered_count: int
|
|
58
|
+
retrieval_time_ms: float
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class RetrieveSummaryResult:
|
|
63
|
+
"""Result of a retrieval with LLM summary."""
|
|
64
|
+
query: str
|
|
65
|
+
summary: str
|
|
66
|
+
supporting_memories: list[Memory]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass
|
|
70
|
+
class DeleteResult:
|
|
71
|
+
"""Result of a delete operation."""
|
|
72
|
+
status: str
|
|
73
|
+
user_id: str
|
|
74
|
+
memories_deleted: int
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass
|
|
78
|
+
class HealthResult:
|
|
79
|
+
"""Health check result."""
|
|
80
|
+
status: str
|
|
81
|
+
version: str
|
|
82
|
+
architecture: str
|
|
83
|
+
scheduler: dict
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: comemo
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Python SDK for Cognitive Memory
|
|
5
|
+
Project-URL: Homepage, https://github.com/hasala/cognitive-memory-sdk
|
|
6
|
+
Project-URL: Documentation, https://github.com/hasala/cognitive-memory-sdk#readme
|
|
7
|
+
Project-URL: Issues, https://github.com/hasala/cognitive-memory-sdk/issues
|
|
8
|
+
Author: Hasala
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: ai,cognitive,memory,sdk
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx>=0.24.0
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Cognitive Memory SDK
|
|
25
|
+
|
|
26
|
+
Python SDK for Cognitive Memory — a multi-module hybrid memory system powered by Pinecone and Neo4j.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install comemo
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from cognitivememory import MemoryClient
|
|
38
|
+
|
|
39
|
+
client = MemoryClient(
|
|
40
|
+
api_key="sk-your-openai-key",
|
|
41
|
+
model="gpt-4o-mini",
|
|
42
|
+
pinecone_api_key="your-pinecone-key",
|
|
43
|
+
neo4j_uri="neo4j+s://your-instance.databases.neo4j.io",
|
|
44
|
+
neo4j_user="neo4j",
|
|
45
|
+
neo4j_password="your-neo4j-password",
|
|
46
|
+
)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Core Memory
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# Add a memory
|
|
53
|
+
result = client.add_memory("john", "chat_01", "I work at Google as a software engineer")
|
|
54
|
+
print(result.status) # "success"
|
|
55
|
+
print(result.action) # "NEW"
|
|
56
|
+
print(result.memory_id) # "mem_abc123"
|
|
57
|
+
|
|
58
|
+
# Clear all user memories
|
|
59
|
+
client.delete_user_memories("john")
|
|
60
|
+
|
|
61
|
+
# Clear session memories
|
|
62
|
+
client.delete_session_memories("john", "chat_01")
|
|
63
|
+
|
|
64
|
+
# Delete a single memory
|
|
65
|
+
client.delete_memory("mem_abc123")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Retrieval
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# Retrieve memories with graph expansion
|
|
72
|
+
result = client.retrieve_advanced(
|
|
73
|
+
user_id="john",
|
|
74
|
+
session_id="chat_01",
|
|
75
|
+
query="career and hobbies",
|
|
76
|
+
top_k=10,
|
|
77
|
+
expand_context=True,
|
|
78
|
+
expand_graph=True,
|
|
79
|
+
min_score=0.3,
|
|
80
|
+
reinforce=True
|
|
81
|
+
)
|
|
82
|
+
for m in result.memories:
|
|
83
|
+
print(f"{m.fact} | semantic={m.semantic_similarity:.2f} graph={m.graph_relevance:.2f}")
|
|
84
|
+
|
|
85
|
+
# List user memories
|
|
86
|
+
result = client.list_memories("john", query="work", top_k=10)
|
|
87
|
+
for m in result.memories:
|
|
88
|
+
print(f"{m.fact} (score: {m.score:.2f})")
|
|
89
|
+
|
|
90
|
+
# Simple retrieve
|
|
91
|
+
result = client.retrieve("john", "chat_01", "Where does John work?", top_k=5)
|
|
92
|
+
for m in result.memories:
|
|
93
|
+
print(f"{m.fact} (score: {m.score:.2f})")
|
|
94
|
+
|
|
95
|
+
# Retrieve with summary
|
|
96
|
+
summary = client.retrieve_summary("john", "chat_01", "Tell me about John's career")
|
|
97
|
+
print(summary.summary)
|
|
98
|
+
for m in summary.supporting_memories:
|
|
99
|
+
print(f" - {m.fact}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Maintenance & Governance
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Run all maintenance tasks
|
|
106
|
+
result = client.run_maintenance(user_id="john")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### System
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
# Clear all memory
|
|
113
|
+
client.delete_all_memories(confirm="DELETE_ALL_DATA")
|
|
114
|
+
|
|
115
|
+
# Get scheduler status
|
|
116
|
+
status = client.scheduler_status()
|
|
117
|
+
|
|
118
|
+
# Health check
|
|
119
|
+
health = client.health()
|
|
120
|
+
print(health.status) # "healthy"
|
|
121
|
+
print(health.version) # "5.1.0"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Context Manager
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
with MemoryClient(
|
|
128
|
+
api_key="sk-your-openai-key",
|
|
129
|
+
model="gpt-4o-mini",
|
|
130
|
+
pinecone_api_key="your-pinecone-key",
|
|
131
|
+
neo4j_uri="neo4j+s://your-instance.databases.neo4j.io",
|
|
132
|
+
neo4j_user="neo4j",
|
|
133
|
+
neo4j_password="your-neo4j-password",
|
|
134
|
+
) as client:
|
|
135
|
+
client.add_memory("john", "chat_01", "My favorite color is blue")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Error Handling
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from cognitivememory import MemoryClient, ValidationError, NotFoundError
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
client.retrieve("john", "chat_01", "")
|
|
145
|
+
except ValidationError as e:
|
|
146
|
+
print(f"Bad request: {e.message}")
|
|
147
|
+
except NotFoundError as e:
|
|
148
|
+
print(f"Not found: {e.message}")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## All Methods
|
|
152
|
+
|
|
153
|
+
### Core Memory
|
|
154
|
+
|
|
155
|
+
| Method | Description |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `add_memory(user_id, session_id, text)` | Add Memory |
|
|
158
|
+
| `delete_user_memories(user_id)` | Clear User Memory |
|
|
159
|
+
| `delete_session_memories(user_id, session_id)` | Clear Session Memory |
|
|
160
|
+
| `delete_memory(memory_id)` | Delete Single Memory |
|
|
161
|
+
|
|
162
|
+
### Retrieval
|
|
163
|
+
|
|
164
|
+
| Method | Description |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `retrieve_advanced(user_id, session_id, query, ...)` | Retrieve Memories |
|
|
167
|
+
| `list_memories(user_id, query, top_k=10)` | List User Memories |
|
|
168
|
+
| `retrieve(user_id, session_id, query, top_k=5)` | Simple Retrieve Memories |
|
|
169
|
+
| `retrieve_summary(user_id, session_id, query, top_k=5)` | Retrieve With Summary |
|
|
170
|
+
|
|
171
|
+
### Maintenance & Governance
|
|
172
|
+
|
|
173
|
+
| Method | Description |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `run_maintenance(user_id="")` | Run All Maintenance |
|
|
176
|
+
|
|
177
|
+
### System
|
|
178
|
+
|
|
179
|
+
| Method | Description |
|
|
180
|
+
|---|---|
|
|
181
|
+
| `delete_all_memories(confirm)` | Clear All Memory |
|
|
182
|
+
| `scheduler_status()` | Get Scheduler Status |
|
|
183
|
+
| `health()` | Health Check |
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
cognitivememory/__init__.py,sha256=Fgh45ucvYK9FQKCa02zbbb1FKWeJ-A0Z5Jq2TqK-3SY,787
|
|
2
|
+
cognitivememory/client.py,sha256=43Sfa9e9TrR9gXnlJn0tUsqIRXKXuiKcplrO5BCDHB8,15078
|
|
3
|
+
cognitivememory/exceptions.py,sha256=FcJpqq3POiX4iSGQJlt8dbCvlDOmt0pqsPmopfV9nyI,779
|
|
4
|
+
cognitivememory/models.py,sha256=KMlXMGOauCeb42Cyt0l0PzxIlyi65SOD1xQUsx42qrQ,1581
|
|
5
|
+
comemo-2.0.0.dist-info/METADATA,sha256=62GO2OWNPiZJaWPFJwP2NDc1sbjCPoNja1tiMt4xR2Y,4849
|
|
6
|
+
comemo-2.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
7
|
+
comemo-2.0.0.dist-info/RECORD,,
|