sls-memory 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.
- sls_memory/__init__.py +47 -0
- sls_memory/client.py +1138 -0
- sls_memory/exceptions.py +22 -0
- sls_memory-0.1.0.dist-info/METADATA +67 -0
- sls_memory-0.1.0.dist-info/RECORD +8 -0
- sls_memory-0.1.0.dist-info/WHEEL +5 -0
- sls_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
- sls_memory-0.1.0.dist-info/top_level.txt +1 -0
sls_memory/__init__.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
SLS Memory SDK - A mem0-compatible memory SDK powered by Alibaba Cloud SLS.
|
|
4
|
+
|
|
5
|
+
This SDK provides an interface compatible with mem0 SDK, allowing users to
|
|
6
|
+
seamlessly migrate from mem0 to SLS Memory service.
|
|
7
|
+
|
|
8
|
+
Note:
|
|
9
|
+
Some mem0 parameters are not yet supported by SLS API. See COMPATIBILITY.md
|
|
10
|
+
for detailed differences between SLS Memory SDK and mem0 SDK.
|
|
11
|
+
|
|
12
|
+
Example:
|
|
13
|
+
>>> from sls_memory import SLSMemoryClient, Config
|
|
14
|
+
>>>
|
|
15
|
+
>>> # Initialize with AK/SK
|
|
16
|
+
>>> config = Config(
|
|
17
|
+
... access_key_id="your_access_key_id",
|
|
18
|
+
... access_key_secret="your_access_key_secret",
|
|
19
|
+
... endpoint="cn-hangzhou.log.aliyuncs.com"
|
|
20
|
+
... )
|
|
21
|
+
>>> client = SLSMemoryClient(config, project="my-project", memory_store="my-store")
|
|
22
|
+
>>>
|
|
23
|
+
>>> # Add a memory
|
|
24
|
+
>>> client.add("I love playing tennis", user_id="user123")
|
|
25
|
+
>>>
|
|
26
|
+
>>> # Search memories
|
|
27
|
+
>>> results = client.search("tennis", user_id="user123")
|
|
28
|
+
>>> print(results)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from sls_memory.client import SLSMemoryClient, AsyncSLSMemoryClient
|
|
32
|
+
from sls_memory.exceptions import ValidationError
|
|
33
|
+
|
|
34
|
+
# Re-export Config from alibabacloud_tea_openapi for convenience
|
|
35
|
+
from alibabacloud_tea_openapi.utils_models import Config
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# Clients
|
|
39
|
+
"SLSMemoryClient",
|
|
40
|
+
"AsyncSLSMemoryClient",
|
|
41
|
+
# Config
|
|
42
|
+
"Config",
|
|
43
|
+
# Exceptions (only for SDK internal validation)
|
|
44
|
+
"ValidationError",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
__version__ = "0.1.0"
|
sls_memory/client.py
ADDED
|
@@ -0,0 +1,1138 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
SLS Memory Client - A mem0-compatible memory client powered by Alibaba Cloud SLS.
|
|
4
|
+
|
|
5
|
+
This module provides synchronous and asynchronous clients that wrap the SLS SDK
|
|
6
|
+
to provide an interface compatible with mem0 SDK.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, List, Optional, Union
|
|
11
|
+
|
|
12
|
+
from alibabacloud_sls20201230.client import Client as SLSClient
|
|
13
|
+
from alibabacloud_sls20201230 import models as sls_models
|
|
14
|
+
from alibabacloud_tea_openapi import utils_models as openapi_models
|
|
15
|
+
|
|
16
|
+
from sls_memory.exceptions import ValidationError
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SLSMemoryClient:
|
|
20
|
+
"""Synchronous client for interacting with SLS Memory service.
|
|
21
|
+
|
|
22
|
+
This class provides methods compatible with mem0 SDK to create, retrieve,
|
|
23
|
+
search, and delete memories using the SLS Memory service.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> from sls_memory import SLSMemoryClient
|
|
27
|
+
>>> from alibabacloud_tea_openapi.utils_models import Config
|
|
28
|
+
>>>
|
|
29
|
+
>>> config = Config(
|
|
30
|
+
... access_key_id="your_access_key_id",
|
|
31
|
+
... access_key_secret="your_access_key_secret",
|
|
32
|
+
... endpoint="cn-hangzhou.log.aliyuncs.com"
|
|
33
|
+
... )
|
|
34
|
+
>>> client = SLSMemoryClient(config, project="my-project", memory_store="my-store")
|
|
35
|
+
>>>
|
|
36
|
+
>>> # Add a memory
|
|
37
|
+
>>> client.add("I love playing tennis", user_id="user123")
|
|
38
|
+
>>>
|
|
39
|
+
>>> # Search memories
|
|
40
|
+
>>> results = client.search("tennis", user_id="user123")
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
config: openapi_models.Config,
|
|
46
|
+
project: str,
|
|
47
|
+
memory_store: str,
|
|
48
|
+
):
|
|
49
|
+
"""Initialize the SLSMemoryClient.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
config: The SLS SDK configuration object. Supports multiple authentication
|
|
53
|
+
methods including AK/SK, STS Token, Bearer Token, and Credential.
|
|
54
|
+
project: The SLS project name.
|
|
55
|
+
memory_store: The Memory Store name within the project.
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
ValidationError: If required parameters are missing.
|
|
59
|
+
"""
|
|
60
|
+
if not project:
|
|
61
|
+
raise ValidationError("project is required")
|
|
62
|
+
if not memory_store:
|
|
63
|
+
raise ValidationError("memory_store is required")
|
|
64
|
+
|
|
65
|
+
self._client = SLSClient(config)
|
|
66
|
+
self._project = project
|
|
67
|
+
self._memory_store = memory_store
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def project(self) -> str:
|
|
71
|
+
"""Get the SLS project name."""
|
|
72
|
+
return self._project
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def memory_store(self) -> str:
|
|
76
|
+
"""Get the Memory Store name."""
|
|
77
|
+
return self._memory_store
|
|
78
|
+
|
|
79
|
+
def _prepare_messages(
|
|
80
|
+
self, messages: Union[str, Dict[str, str], List[Dict[str, str]]]
|
|
81
|
+
) -> List[sls_models.AddMemoriesRequestMessages]:
|
|
82
|
+
"""Convert messages to SLS request format.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
messages: A string, single message dict, or list of message dicts.
|
|
86
|
+
If a string is provided, it will be converted to a user message.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
A list of AddMemoriesRequestMessages objects.
|
|
90
|
+
"""
|
|
91
|
+
if isinstance(messages, str):
|
|
92
|
+
messages = [{"role": "user", "content": messages}]
|
|
93
|
+
elif isinstance(messages, dict):
|
|
94
|
+
messages = [messages]
|
|
95
|
+
elif not isinstance(messages, list):
|
|
96
|
+
raise ValidationError(
|
|
97
|
+
f"messages must be str, dict, or list[dict], got {type(messages).__name__}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
result = []
|
|
101
|
+
for msg in messages:
|
|
102
|
+
result.append(sls_models.AddMemoriesRequestMessages(
|
|
103
|
+
role=msg.get("role", "user"),
|
|
104
|
+
content=msg.get("content", ""),
|
|
105
|
+
))
|
|
106
|
+
return result
|
|
107
|
+
|
|
108
|
+
def _convert_memory_result(self, result: Any) -> Dict[str, Any]:
|
|
109
|
+
"""Convert SLS memory result to dict format."""
|
|
110
|
+
if hasattr(result, 'to_map'):
|
|
111
|
+
return result.to_map()
|
|
112
|
+
return dict(result) if result else {}
|
|
113
|
+
|
|
114
|
+
def _convert_results_list(self, results: List[Any]) -> List[Dict[str, Any]]:
|
|
115
|
+
"""Convert a list of SLS results to dict format."""
|
|
116
|
+
return [self._convert_memory_result(r) for r in results] if results else []
|
|
117
|
+
|
|
118
|
+
def add(
|
|
119
|
+
self,
|
|
120
|
+
messages: Union[str, Dict[str, str], List[Dict[str, str]]],
|
|
121
|
+
user_id: Optional[str] = None,
|
|
122
|
+
agent_id: Optional[str] = None,
|
|
123
|
+
app_id: Optional[str] = None,
|
|
124
|
+
run_id: Optional[str] = None,
|
|
125
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
126
|
+
infer: bool = True,
|
|
127
|
+
async_mode: bool = True,
|
|
128
|
+
) -> Dict[str, Any]:
|
|
129
|
+
"""Add a new memory.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
messages: A list of message dictionaries, a single message dictionary,
|
|
133
|
+
or a string. If a string is provided, it will be converted to
|
|
134
|
+
a user message.
|
|
135
|
+
user_id: The user ID to associate with the memory.
|
|
136
|
+
agent_id: The agent ID to associate with the memory.
|
|
137
|
+
app_id: The application ID to associate with the memory.
|
|
138
|
+
run_id: The run ID to associate with the memory.
|
|
139
|
+
metadata: Optional metadata to attach to the memory (any key-value pairs).
|
|
140
|
+
infer: Whether to enable inference mode. Defaults to True.
|
|
141
|
+
async_mode: Whether to process asynchronously. Defaults to True.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
A dictionary containing the API response in format:
|
|
145
|
+
{"results": [{"message": "...", "status": "PENDING", "event_id": "..."}]}
|
|
146
|
+
|
|
147
|
+
Example:
|
|
148
|
+
>>> client.add("I love playing tennis", user_id="user123")
|
|
149
|
+
>>> client.add(
|
|
150
|
+
... messages=[{"role": "user", "content": "I love tennis"}],
|
|
151
|
+
... user_id="user123",
|
|
152
|
+
... agent_id="agent_001",
|
|
153
|
+
... metadata={"source": "chat", "importance": "high"}
|
|
154
|
+
... )
|
|
155
|
+
"""
|
|
156
|
+
sls_messages = self._prepare_messages(messages)
|
|
157
|
+
|
|
158
|
+
request = sls_models.AddMemoriesRequest(
|
|
159
|
+
messages=sls_messages,
|
|
160
|
+
user_id=user_id,
|
|
161
|
+
agent_id=agent_id,
|
|
162
|
+
app_id=app_id,
|
|
163
|
+
run_id=run_id,
|
|
164
|
+
metadata=metadata,
|
|
165
|
+
infer=infer,
|
|
166
|
+
async_mode=async_mode,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
response = self._client.add_memories(
|
|
170
|
+
self._project,
|
|
171
|
+
self._memory_store,
|
|
172
|
+
request,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Return the response body (async mode format)
|
|
176
|
+
if response.body:
|
|
177
|
+
return self._convert_memory_result(response.body)
|
|
178
|
+
return {"results": []}
|
|
179
|
+
|
|
180
|
+
def get(self, memory_id: str) -> Dict[str, Any]:
|
|
181
|
+
"""Retrieve a specific memory by ID.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
memory_id: The ID of the memory to retrieve.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
A dictionary containing the memory data.
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
>>> memory = client.get("mem_123")
|
|
191
|
+
>>> print(memory["memory"])
|
|
192
|
+
"""
|
|
193
|
+
if not memory_id:
|
|
194
|
+
raise ValidationError("memory_id is required")
|
|
195
|
+
|
|
196
|
+
response = self._client.get_memory(
|
|
197
|
+
self._project,
|
|
198
|
+
self._memory_store,
|
|
199
|
+
memory_id,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if response.body:
|
|
203
|
+
return self._convert_memory_result(response.body)
|
|
204
|
+
return {}
|
|
205
|
+
|
|
206
|
+
def get_all(
|
|
207
|
+
self,
|
|
208
|
+
user_id: Optional[str] = None,
|
|
209
|
+
agent_id: Optional[str] = None,
|
|
210
|
+
app_id: Optional[str] = None,
|
|
211
|
+
run_id: Optional[str] = None,
|
|
212
|
+
limit: Optional[int] = None,
|
|
213
|
+
) -> Dict[str, Any]:
|
|
214
|
+
"""Retrieve all memories, with optional filtering.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
user_id: Optional user ID to filter memories.
|
|
218
|
+
agent_id: Optional agent ID to filter memories.
|
|
219
|
+
app_id: Optional application ID to filter memories.
|
|
220
|
+
run_id: Optional run ID to filter memories.
|
|
221
|
+
limit: Maximum number of memories to retrieve.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
A dictionary containing memories in format: {"results": [...]}
|
|
225
|
+
|
|
226
|
+
Example:
|
|
227
|
+
>>> memories = client.get_all(user_id="user123", limit=10)
|
|
228
|
+
>>> for mem in memories["results"]:
|
|
229
|
+
... print(mem["memory"])
|
|
230
|
+
"""
|
|
231
|
+
request = sls_models.GetMemoriesRequest(
|
|
232
|
+
user_id=user_id,
|
|
233
|
+
agent_id=agent_id,
|
|
234
|
+
app_id=app_id,
|
|
235
|
+
run_id=run_id,
|
|
236
|
+
limit=limit,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
response = self._client.get_memories(
|
|
240
|
+
self._project,
|
|
241
|
+
self._memory_store,
|
|
242
|
+
request,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
result = {"results": []}
|
|
246
|
+
if response.body and response.body.results:
|
|
247
|
+
result["results"] = self._convert_results_list(response.body.results)
|
|
248
|
+
|
|
249
|
+
return result
|
|
250
|
+
|
|
251
|
+
def search(
|
|
252
|
+
self,
|
|
253
|
+
query: str,
|
|
254
|
+
user_id: Optional[str] = None,
|
|
255
|
+
agent_id: Optional[str] = None,
|
|
256
|
+
app_id: Optional[str] = None,
|
|
257
|
+
run_id: Optional[str] = None,
|
|
258
|
+
top_k: Optional[int] = None,
|
|
259
|
+
rerank: bool = False,
|
|
260
|
+
) -> Dict[str, Any]:
|
|
261
|
+
"""Search memories based on a query.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
query: The search query string.
|
|
265
|
+
user_id: Optional user ID to filter results.
|
|
266
|
+
agent_id: Optional agent ID to filter results.
|
|
267
|
+
app_id: Optional application ID to filter results.
|
|
268
|
+
run_id: Optional run ID to filter results.
|
|
269
|
+
top_k: Maximum number of top results to return.
|
|
270
|
+
rerank: Whether to enable reranking. Defaults to False.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
A dictionary containing search results in format: {"results": [...]}
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
>>> results = client.search("tennis", user_id="user123", top_k=5)
|
|
277
|
+
>>> results = client.search(
|
|
278
|
+
... query="preferences",
|
|
279
|
+
... agent_id="agent_001",
|
|
280
|
+
... rerank=True,
|
|
281
|
+
... )
|
|
282
|
+
>>> for mem in results["results"]:
|
|
283
|
+
... print(f"{mem['memory']} (score: {mem.get('score', 'N/A')})")
|
|
284
|
+
"""
|
|
285
|
+
if not query:
|
|
286
|
+
raise ValidationError("query is required")
|
|
287
|
+
|
|
288
|
+
request = sls_models.SearchMemoriesRequest(
|
|
289
|
+
query=query,
|
|
290
|
+
user_id=user_id,
|
|
291
|
+
agent_id=agent_id,
|
|
292
|
+
app_id=app_id,
|
|
293
|
+
run_id=run_id,
|
|
294
|
+
top_k=top_k,
|
|
295
|
+
rerank=rerank,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
response = self._client.search_memories(
|
|
299
|
+
self._project,
|
|
300
|
+
self._memory_store,
|
|
301
|
+
request,
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
result = {"results": []}
|
|
305
|
+
if response.body and response.body.results:
|
|
306
|
+
result["results"] = self._convert_results_list(response.body.results)
|
|
307
|
+
|
|
308
|
+
return result
|
|
309
|
+
|
|
310
|
+
def update(
|
|
311
|
+
self,
|
|
312
|
+
memory_id: str,
|
|
313
|
+
text: Optional[str] = None,
|
|
314
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
315
|
+
) -> Dict[str, Any]:
|
|
316
|
+
"""Update a memory by ID.
|
|
317
|
+
|
|
318
|
+
Args:
|
|
319
|
+
memory_id: The ID of the memory to update.
|
|
320
|
+
text: New content to update the memory with.
|
|
321
|
+
metadata: Metadata to update in the memory (any key-value pairs).
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
A dictionary containing the API response.
|
|
325
|
+
|
|
326
|
+
Example:
|
|
327
|
+
>>> client.update("mem_123", text="I love playing tennis on weekends")
|
|
328
|
+
>>> client.update(
|
|
329
|
+
... memory_id="mem_123",
|
|
330
|
+
... metadata={"updated_by": "user", "importance": "high"}
|
|
331
|
+
... )
|
|
332
|
+
"""
|
|
333
|
+
if not memory_id:
|
|
334
|
+
raise ValidationError("memory_id is required")
|
|
335
|
+
if text is None and metadata is None:
|
|
336
|
+
raise ValidationError("Either text or metadata must be provided for update.")
|
|
337
|
+
|
|
338
|
+
request = sls_models.UpdateMemoryRequest(
|
|
339
|
+
text=text,
|
|
340
|
+
metadata=metadata,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
response = self._client.update_memory(
|
|
344
|
+
self._project,
|
|
345
|
+
self._memory_store,
|
|
346
|
+
memory_id,
|
|
347
|
+
request,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
"status_code": response.status_code,
|
|
352
|
+
"headers": response.headers,
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
def delete(self, memory_id: str) -> Dict[str, Any]:
|
|
356
|
+
"""Delete a specific memory by ID.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
memory_id: The ID of the memory to delete.
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
A dictionary containing the API response.
|
|
363
|
+
|
|
364
|
+
Example:
|
|
365
|
+
>>> client.delete("mem_123")
|
|
366
|
+
"""
|
|
367
|
+
if not memory_id:
|
|
368
|
+
raise ValidationError("memory_id is required")
|
|
369
|
+
|
|
370
|
+
response = self._client.delete_memory(
|
|
371
|
+
self._project,
|
|
372
|
+
self._memory_store,
|
|
373
|
+
memory_id,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
"status_code": response.status_code,
|
|
378
|
+
"headers": response.headers,
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
def delete_all(
|
|
382
|
+
self,
|
|
383
|
+
user_id: Optional[str] = None,
|
|
384
|
+
agent_id: Optional[str] = None,
|
|
385
|
+
app_id: Optional[str] = None,
|
|
386
|
+
run_id: Optional[str] = None
|
|
387
|
+
) -> Dict[str, Any]:
|
|
388
|
+
"""Delete all memories with optional filtering.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
user_id: Optional user ID to filter which memories to delete.
|
|
392
|
+
agent_id: Optional agent ID to filter which memories to delete.
|
|
393
|
+
app_id: Optional application ID to filter which memories to delete.
|
|
394
|
+
run_id: Optional run ID to filter which memories to delete.
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
A dictionary containing the API response.
|
|
398
|
+
|
|
399
|
+
Warning:
|
|
400
|
+
If no filters are provided, this will delete ALL memories in the memory store!
|
|
401
|
+
|
|
402
|
+
Example:
|
|
403
|
+
>>> client.delete_all(user_id="user123") # Delete only user123's memories
|
|
404
|
+
"""
|
|
405
|
+
request = sls_models.DeleteMemoriesRequest(
|
|
406
|
+
user_id=user_id,
|
|
407
|
+
agent_id=agent_id,
|
|
408
|
+
app_id=app_id,
|
|
409
|
+
run_id=run_id,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
response = self._client.delete_memories(
|
|
413
|
+
self._project,
|
|
414
|
+
self._memory_store,
|
|
415
|
+
request,
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
"status_code": response.status_code,
|
|
420
|
+
"headers": response.headers,
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
def history(self, memory_id: str) -> List[Dict[str, Any]]:
|
|
424
|
+
"""Retrieve the history of a specific memory.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
memory_id: The ID of the memory to retrieve history for.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
A list of dictionaries containing the memory history.
|
|
431
|
+
|
|
432
|
+
Example:
|
|
433
|
+
>>> history = client.history("mem_123")
|
|
434
|
+
>>> for entry in history:
|
|
435
|
+
... print(f"{entry['event']}: {entry.get('new_memory', 'N/A')}")
|
|
436
|
+
"""
|
|
437
|
+
if not memory_id:
|
|
438
|
+
raise ValidationError("memory_id is required")
|
|
439
|
+
|
|
440
|
+
response = self._client.get_memory_history(
|
|
441
|
+
self._project,
|
|
442
|
+
self._memory_store,
|
|
443
|
+
memory_id,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
if response.body:
|
|
447
|
+
return self._convert_results_list(response.body)
|
|
448
|
+
return []
|
|
449
|
+
|
|
450
|
+
# Memory Store Management Methods
|
|
451
|
+
|
|
452
|
+
def create_memory_store(
|
|
453
|
+
self,
|
|
454
|
+
description: Optional[str] = None,
|
|
455
|
+
custom_instructions: Optional[str] = None,
|
|
456
|
+
enable_graph: bool = False,
|
|
457
|
+
strategy: str = "default",
|
|
458
|
+
short_term_ttl: int = 7,
|
|
459
|
+
) -> Dict[str, Any]:
|
|
460
|
+
"""Create the Memory Store bound to this client.
|
|
461
|
+
|
|
462
|
+
Creates the memory store specified during client initialization.
|
|
463
|
+
If the project does not exist, creates the project first then retries.
|
|
464
|
+
|
|
465
|
+
Args:
|
|
466
|
+
description: Description of the memory store.
|
|
467
|
+
custom_instructions: Custom instructions for the memory store.
|
|
468
|
+
enable_graph: Whether to enable knowledge graph. Defaults to False.
|
|
469
|
+
strategy: Memory processing strategy. Defaults to "default".
|
|
470
|
+
short_term_ttl: TTL for short-term memories in days. Defaults to 7.
|
|
471
|
+
|
|
472
|
+
Returns:
|
|
473
|
+
A dictionary containing the API response.
|
|
474
|
+
|
|
475
|
+
Example:
|
|
476
|
+
>>> client.create_memory_store(
|
|
477
|
+
... description="Store for user memories",
|
|
478
|
+
... enable_graph=True
|
|
479
|
+
... )
|
|
480
|
+
"""
|
|
481
|
+
store_name = self._memory_store
|
|
482
|
+
|
|
483
|
+
request = sls_models.CreateMemoryStoreRequest(
|
|
484
|
+
name=store_name,
|
|
485
|
+
description=description,
|
|
486
|
+
custom_instructions=custom_instructions,
|
|
487
|
+
enable_graph=enable_graph,
|
|
488
|
+
strategy=strategy,
|
|
489
|
+
short_term_ttl=short_term_ttl,
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
response = self._client.create_memory_store(
|
|
494
|
+
self._project,
|
|
495
|
+
request,
|
|
496
|
+
)
|
|
497
|
+
except Exception as e:
|
|
498
|
+
if "ProjectNotExist" not in str(e):
|
|
499
|
+
raise
|
|
500
|
+
self._client.create_project(
|
|
501
|
+
sls_models.CreateProjectRequest(
|
|
502
|
+
project_name=self._project,
|
|
503
|
+
description="Auto-created by SLS Memory SDK",
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
response = self._client.create_memory_store(
|
|
507
|
+
self._project,
|
|
508
|
+
request,
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
return {
|
|
512
|
+
"status_code": response.status_code,
|
|
513
|
+
"headers": response.headers,
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
def describe_memory_store(self) -> Dict[str, Any]:
|
|
517
|
+
"""Get detailed information about the current Memory Store.
|
|
518
|
+
|
|
519
|
+
Returns:
|
|
520
|
+
A dictionary containing memory store details including:
|
|
521
|
+
- name: Memory Store name
|
|
522
|
+
- description: Description
|
|
523
|
+
- custom_instructions: Custom instructions
|
|
524
|
+
- enable_graph: Whether graph is enabled
|
|
525
|
+
- strategy: Processing strategy
|
|
526
|
+
- short_term_ttl: Short-term memory TTL
|
|
527
|
+
- create_time: Creation timestamp
|
|
528
|
+
- update_time: Last update timestamp
|
|
529
|
+
|
|
530
|
+
Example:
|
|
531
|
+
>>> info = client.describe_memory_store()
|
|
532
|
+
>>> print(f"Store: {info['name']}, Created: {info['create_time']}")
|
|
533
|
+
"""
|
|
534
|
+
response = self._client.get_memory_store(
|
|
535
|
+
self._project,
|
|
536
|
+
self._memory_store,
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
if response.body:
|
|
540
|
+
return self._convert_memory_result(response.body)
|
|
541
|
+
return {}
|
|
542
|
+
|
|
543
|
+
def update_memory_store(
|
|
544
|
+
self,
|
|
545
|
+
description: Optional[str] = None,
|
|
546
|
+
custom_instructions: Optional[str] = None,
|
|
547
|
+
enable_graph: Optional[bool] = None,
|
|
548
|
+
strategy: Optional[str] = None,
|
|
549
|
+
short_term_ttl: Optional[int] = None,
|
|
550
|
+
) -> Dict[str, Any]:
|
|
551
|
+
"""Update the configuration of the current Memory Store.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
description: New description.
|
|
555
|
+
custom_instructions: New custom instructions.
|
|
556
|
+
enable_graph: Whether to enable knowledge graph.
|
|
557
|
+
strategy: New memory processing strategy.
|
|
558
|
+
short_term_ttl: New TTL for short-term memories in seconds.
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
A dictionary containing the API response.
|
|
562
|
+
|
|
563
|
+
Example:
|
|
564
|
+
>>> client.update_memory_store(
|
|
565
|
+
... description="Updated description",
|
|
566
|
+
... enable_graph=True,
|
|
567
|
+
... short_term_ttl=3600
|
|
568
|
+
... )
|
|
569
|
+
"""
|
|
570
|
+
request = sls_models.UpdateMemoryStoreRequest(
|
|
571
|
+
description=description,
|
|
572
|
+
custom_instructions=custom_instructions,
|
|
573
|
+
enable_graph=enable_graph,
|
|
574
|
+
strategy=strategy,
|
|
575
|
+
short_term_ttl=short_term_ttl,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
response = self._client.update_memory_store(
|
|
579
|
+
self._project,
|
|
580
|
+
self._memory_store,
|
|
581
|
+
request,
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
return {
|
|
585
|
+
"status_code": response.status_code,
|
|
586
|
+
"headers": response.headers,
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
def delete_memory_store(self) -> Dict[str, Any]:
|
|
590
|
+
"""Delete the current Memory Store.
|
|
591
|
+
|
|
592
|
+
Warning:
|
|
593
|
+
This will permanently delete the memory store and all its memories!
|
|
594
|
+
|
|
595
|
+
Returns:
|
|
596
|
+
A dictionary containing the API response.
|
|
597
|
+
|
|
598
|
+
Example:
|
|
599
|
+
>>> client.delete_memory_store()
|
|
600
|
+
"""
|
|
601
|
+
response = self._client.delete_memory_store(
|
|
602
|
+
self._project,
|
|
603
|
+
self._memory_store,
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
return {
|
|
607
|
+
"status_code": response.status_code,
|
|
608
|
+
"headers": response.headers,
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
class AsyncSLSMemoryClient:
|
|
613
|
+
"""Asynchronous client for interacting with SLS Memory service.
|
|
614
|
+
|
|
615
|
+
This class provides async versions of all SLSMemoryClient methods.
|
|
616
|
+
It uses the SLS SDK's async methods for non-blocking API requests.
|
|
617
|
+
|
|
618
|
+
Example:
|
|
619
|
+
>>> import asyncio
|
|
620
|
+
>>> from sls_memory import AsyncSLSMemoryClient
|
|
621
|
+
>>> from alibabacloud_tea_openapi.utils_models import Config
|
|
622
|
+
>>>
|
|
623
|
+
>>> async def main():
|
|
624
|
+
... config = Config(
|
|
625
|
+
... access_key_id="your_access_key_id",
|
|
626
|
+
... access_key_secret="your_access_key_secret",
|
|
627
|
+
... endpoint="cn-hangzhou.log.aliyuncs.com"
|
|
628
|
+
... )
|
|
629
|
+
... async with AsyncSLSMemoryClient(config, "my-project", "my-store") as client:
|
|
630
|
+
... await client.add("I love tennis", user_id="user123")
|
|
631
|
+
... results = await client.search("tennis", user_id="user123")
|
|
632
|
+
... print(results)
|
|
633
|
+
>>>
|
|
634
|
+
>>> asyncio.run(main())
|
|
635
|
+
"""
|
|
636
|
+
|
|
637
|
+
def __init__(
|
|
638
|
+
self,
|
|
639
|
+
config: openapi_models.Config,
|
|
640
|
+
project: str,
|
|
641
|
+
memory_store: str,
|
|
642
|
+
):
|
|
643
|
+
"""Initialize the AsyncSLSMemoryClient.
|
|
644
|
+
|
|
645
|
+
Args:
|
|
646
|
+
config: The SLS SDK configuration object. Supports multiple authentication
|
|
647
|
+
methods including AK/SK, STS Token, Bearer Token, and Credential.
|
|
648
|
+
project: The SLS project name.
|
|
649
|
+
memory_store: The Memory Store name within the project.
|
|
650
|
+
|
|
651
|
+
Raises:
|
|
652
|
+
ValidationError: If required parameters are missing.
|
|
653
|
+
"""
|
|
654
|
+
if not project:
|
|
655
|
+
raise ValidationError("project is required")
|
|
656
|
+
if not memory_store:
|
|
657
|
+
raise ValidationError("memory_store is required")
|
|
658
|
+
|
|
659
|
+
self._client = SLSClient(config)
|
|
660
|
+
self._project = project
|
|
661
|
+
self._memory_store = memory_store
|
|
662
|
+
|
|
663
|
+
async def __aenter__(self):
|
|
664
|
+
return self
|
|
665
|
+
|
|
666
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
667
|
+
pass
|
|
668
|
+
|
|
669
|
+
@property
|
|
670
|
+
def project(self) -> str:
|
|
671
|
+
"""Get the SLS project name."""
|
|
672
|
+
return self._project
|
|
673
|
+
|
|
674
|
+
@property
|
|
675
|
+
def memory_store(self) -> str:
|
|
676
|
+
"""Get the Memory Store name."""
|
|
677
|
+
return self._memory_store
|
|
678
|
+
|
|
679
|
+
def _prepare_messages(
|
|
680
|
+
self, messages: Union[str, Dict[str, str], List[Dict[str, str]]]
|
|
681
|
+
) -> List[sls_models.AddMemoriesRequestMessages]:
|
|
682
|
+
"""Convert messages to SLS request format."""
|
|
683
|
+
if isinstance(messages, str):
|
|
684
|
+
messages = [{"role": "user", "content": messages}]
|
|
685
|
+
elif isinstance(messages, dict):
|
|
686
|
+
messages = [messages]
|
|
687
|
+
elif not isinstance(messages, list):
|
|
688
|
+
raise ValidationError(
|
|
689
|
+
f"messages must be str, dict, or list[dict], got {type(messages).__name__}"
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
result = []
|
|
693
|
+
for msg in messages:
|
|
694
|
+
result.append(sls_models.AddMemoriesRequestMessages(
|
|
695
|
+
role=msg.get("role", "user"),
|
|
696
|
+
content=msg.get("content", ""),
|
|
697
|
+
))
|
|
698
|
+
return result
|
|
699
|
+
|
|
700
|
+
def _convert_memory_result(self, result: Any) -> Dict[str, Any]:
|
|
701
|
+
"""Convert SLS memory result to dict format."""
|
|
702
|
+
if hasattr(result, 'to_map'):
|
|
703
|
+
return result.to_map()
|
|
704
|
+
return dict(result) if result else {}
|
|
705
|
+
|
|
706
|
+
def _convert_results_list(self, results: List[Any]) -> List[Dict[str, Any]]:
|
|
707
|
+
"""Convert a list of SLS results to dict format."""
|
|
708
|
+
return [self._convert_memory_result(r) for r in results] if results else []
|
|
709
|
+
|
|
710
|
+
async def add(
|
|
711
|
+
self,
|
|
712
|
+
messages: Union[str, Dict[str, str], List[Dict[str, str]]],
|
|
713
|
+
user_id: Optional[str] = None,
|
|
714
|
+
agent_id: Optional[str] = None,
|
|
715
|
+
app_id: Optional[str] = None,
|
|
716
|
+
run_id: Optional[str] = None,
|
|
717
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
718
|
+
infer: bool = True,
|
|
719
|
+
custom_instructions: Optional[str] = None,
|
|
720
|
+
async_mode: bool = True,
|
|
721
|
+
) -> Dict[str, Any]:
|
|
722
|
+
"""Add a new memory (async version).
|
|
723
|
+
|
|
724
|
+
Args:
|
|
725
|
+
messages: A list of message dictionaries, a single message dictionary,
|
|
726
|
+
or a string. If a string is provided, it will be converted to
|
|
727
|
+
a user message.
|
|
728
|
+
user_id: The user ID to associate with the memory.
|
|
729
|
+
agent_id: The agent ID to associate with the memory.
|
|
730
|
+
app_id: The application ID to associate with the memory.
|
|
731
|
+
run_id: The run ID to associate with the memory.
|
|
732
|
+
metadata: Optional metadata to attach to the memory (any key-value pairs).
|
|
733
|
+
infer: Whether to enable inference mode. Defaults to True.
|
|
734
|
+
custom_instructions: Custom instructions for memory processing.
|
|
735
|
+
async_mode: Whether to process asynchronously. Defaults to True.
|
|
736
|
+
|
|
737
|
+
Returns:
|
|
738
|
+
A dictionary containing the API response in format:
|
|
739
|
+
{"results": [{"message": "...", "status": "PENDING", "event_id": "..."}]}
|
|
740
|
+
"""
|
|
741
|
+
sls_messages = self._prepare_messages(messages)
|
|
742
|
+
|
|
743
|
+
request = sls_models.AddMemoriesRequest(
|
|
744
|
+
messages=sls_messages,
|
|
745
|
+
user_id=user_id,
|
|
746
|
+
agent_id=agent_id,
|
|
747
|
+
app_id=app_id,
|
|
748
|
+
run_id=run_id,
|
|
749
|
+
metadata=metadata,
|
|
750
|
+
infer=infer,
|
|
751
|
+
custom_instructions=custom_instructions,
|
|
752
|
+
asyn_mode=async_mode,
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
response = await self._client.add_memories_async(
|
|
756
|
+
self._project,
|
|
757
|
+
self._memory_store,
|
|
758
|
+
request,
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
# Return the response body (async mode format)
|
|
762
|
+
if response.body:
|
|
763
|
+
return self._convert_memory_result(response.body)
|
|
764
|
+
return {"results": []}
|
|
765
|
+
|
|
766
|
+
async def get(self, memory_id: str) -> Dict[str, Any]:
|
|
767
|
+
"""Retrieve a specific memory by ID (async version).
|
|
768
|
+
|
|
769
|
+
Args:
|
|
770
|
+
memory_id: The ID of the memory to retrieve.
|
|
771
|
+
|
|
772
|
+
Returns:
|
|
773
|
+
A dictionary containing the memory data.
|
|
774
|
+
"""
|
|
775
|
+
if not memory_id:
|
|
776
|
+
raise ValidationError("memory_id is required")
|
|
777
|
+
|
|
778
|
+
response = await self._client.get_memory_async(
|
|
779
|
+
self._project,
|
|
780
|
+
self._memory_store,
|
|
781
|
+
memory_id,
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
if response.body:
|
|
785
|
+
return self._convert_memory_result(response.body)
|
|
786
|
+
return {}
|
|
787
|
+
|
|
788
|
+
async def get_all(
|
|
789
|
+
self,
|
|
790
|
+
user_id: Optional[str] = None,
|
|
791
|
+
agent_id: Optional[str] = None,
|
|
792
|
+
app_id: Optional[str] = None,
|
|
793
|
+
run_id: Optional[str] = None,
|
|
794
|
+
limit: Optional[int] = None,
|
|
795
|
+
) -> Dict[str, Any]:
|
|
796
|
+
"""Retrieve all memories, with optional filtering (async version).
|
|
797
|
+
|
|
798
|
+
Args:
|
|
799
|
+
user_id: Optional user ID to filter memories.
|
|
800
|
+
agent_id: Optional agent ID to filter memories.
|
|
801
|
+
app_id: Optional application ID to filter memories.
|
|
802
|
+
run_id: Optional run ID to filter memories.
|
|
803
|
+
limit: Maximum number of memories to retrieve.
|
|
804
|
+
|
|
805
|
+
Returns:
|
|
806
|
+
A dictionary containing memories in format: {"results": [...]}
|
|
807
|
+
"""
|
|
808
|
+
request = sls_models.GetMemoriesRequest(
|
|
809
|
+
user_id=user_id,
|
|
810
|
+
agent_id=agent_id,
|
|
811
|
+
app_id=app_id,
|
|
812
|
+
run_id=run_id,
|
|
813
|
+
limit=limit,
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
response = await self._client.get_memories_async(
|
|
817
|
+
self._project,
|
|
818
|
+
self._memory_store,
|
|
819
|
+
request,
|
|
820
|
+
)
|
|
821
|
+
|
|
822
|
+
result = {"results": []}
|
|
823
|
+
if response.body and response.body.results:
|
|
824
|
+
result["results"] = self._convert_results_list(response.body.results)
|
|
825
|
+
|
|
826
|
+
return result
|
|
827
|
+
|
|
828
|
+
async def search(
|
|
829
|
+
self,
|
|
830
|
+
query: str,
|
|
831
|
+
user_id: Optional[str] = None,
|
|
832
|
+
agent_id: Optional[str] = None,
|
|
833
|
+
app_id: Optional[str] = None,
|
|
834
|
+
run_id: Optional[str] = None,
|
|
835
|
+
top_k: Optional[int] = None,
|
|
836
|
+
rerank: bool = False,
|
|
837
|
+
) -> Dict[str, Any]:
|
|
838
|
+
"""Search memories based on a query (async version).
|
|
839
|
+
|
|
840
|
+
Args:
|
|
841
|
+
query: The search query string.
|
|
842
|
+
user_id: Optional user ID to filter results.
|
|
843
|
+
agent_id: Optional agent ID to filter results.
|
|
844
|
+
app_id: Optional application ID to filter results.
|
|
845
|
+
run_id: Optional run ID to filter results.
|
|
846
|
+
top_k: Maximum number of top results to return.
|
|
847
|
+
rerank: Whether to enable reranking. Defaults to False.
|
|
848
|
+
|
|
849
|
+
Returns:
|
|
850
|
+
A dictionary containing search results in format: {"results": [...]}
|
|
851
|
+
"""
|
|
852
|
+
if not query:
|
|
853
|
+
raise ValidationError("query is required")
|
|
854
|
+
|
|
855
|
+
request = sls_models.SearchMemoriesRequest(
|
|
856
|
+
query=query,
|
|
857
|
+
user_id=user_id,
|
|
858
|
+
agent_id=agent_id,
|
|
859
|
+
app_id=app_id,
|
|
860
|
+
run_id=run_id,
|
|
861
|
+
top_k=top_k,
|
|
862
|
+
rerank=rerank,
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
response = await self._client.search_memories_async(
|
|
866
|
+
self._project,
|
|
867
|
+
self._memory_store,
|
|
868
|
+
request,
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
result = {"results": []}
|
|
872
|
+
if response.body and response.body.results:
|
|
873
|
+
result["results"] = self._convert_results_list(response.body.results)
|
|
874
|
+
|
|
875
|
+
return result
|
|
876
|
+
|
|
877
|
+
async def update(
|
|
878
|
+
self,
|
|
879
|
+
memory_id: str,
|
|
880
|
+
text: Optional[str] = None,
|
|
881
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
882
|
+
) -> Dict[str, Any]:
|
|
883
|
+
"""Update a memory by ID (async version).
|
|
884
|
+
|
|
885
|
+
Args:
|
|
886
|
+
memory_id: The ID of the memory to update.
|
|
887
|
+
text: New content to update the memory with.
|
|
888
|
+
metadata: Metadata to update in the memory (any key-value pairs).
|
|
889
|
+
|
|
890
|
+
Returns:
|
|
891
|
+
A dictionary containing the API response.
|
|
892
|
+
"""
|
|
893
|
+
if not memory_id:
|
|
894
|
+
raise ValidationError("memory_id is required")
|
|
895
|
+
if text is None and metadata is None:
|
|
896
|
+
raise ValidationError("Either text or metadata must be provided for update.")
|
|
897
|
+
|
|
898
|
+
request = sls_models.UpdateMemoryRequest(
|
|
899
|
+
text=text,
|
|
900
|
+
metadata=metadata,
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
response = await self._client.update_memory_async(
|
|
904
|
+
self._project,
|
|
905
|
+
self._memory_store,
|
|
906
|
+
memory_id,
|
|
907
|
+
request,
|
|
908
|
+
)
|
|
909
|
+
|
|
910
|
+
return {
|
|
911
|
+
"status_code": response.status_code,
|
|
912
|
+
"headers": response.headers,
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
async def delete(self, memory_id: str) -> Dict[str, Any]:
|
|
916
|
+
"""Delete a specific memory by ID (async version).
|
|
917
|
+
|
|
918
|
+
Args:
|
|
919
|
+
memory_id: The ID of the memory to delete.
|
|
920
|
+
|
|
921
|
+
Returns:
|
|
922
|
+
A dictionary containing the API response.
|
|
923
|
+
"""
|
|
924
|
+
if not memory_id:
|
|
925
|
+
raise ValidationError("memory_id is required")
|
|
926
|
+
|
|
927
|
+
response = await self._client.delete_memory_async(
|
|
928
|
+
self._project,
|
|
929
|
+
self._memory_store,
|
|
930
|
+
memory_id,
|
|
931
|
+
)
|
|
932
|
+
|
|
933
|
+
return {
|
|
934
|
+
"status_code": response.status_code,
|
|
935
|
+
"headers": response.headers,
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
async def delete_all(
|
|
939
|
+
self,
|
|
940
|
+
user_id: Optional[str] = None,
|
|
941
|
+
agent_id: Optional[str] = None,
|
|
942
|
+
app_id: Optional[str] = None,
|
|
943
|
+
run_id: Optional[str] = None,
|
|
944
|
+
) -> Dict[str, Any]:
|
|
945
|
+
"""Delete all memories with optional filtering (async version).
|
|
946
|
+
|
|
947
|
+
Args:
|
|
948
|
+
user_id: Optional user ID to filter which memories to delete.
|
|
949
|
+
agent_id: Optional agent ID to filter which memories to delete.
|
|
950
|
+
app_id: Optional application ID to filter which memories to delete.
|
|
951
|
+
run_id: Optional run ID to filter which memories to delete.
|
|
952
|
+
|
|
953
|
+
Returns:
|
|
954
|
+
A dictionary containing the API response.
|
|
955
|
+
|
|
956
|
+
Warning:
|
|
957
|
+
If no filters are provided, this will delete ALL memories in the memory store!
|
|
958
|
+
"""
|
|
959
|
+
request = sls_models.DeleteMemoriesRequest(
|
|
960
|
+
user_id=user_id,
|
|
961
|
+
agent_id=agent_id,
|
|
962
|
+
app_id=app_id,
|
|
963
|
+
run_id=run_id,
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
response = await self._client.delete_memories_async(
|
|
967
|
+
self._project,
|
|
968
|
+
self._memory_store,
|
|
969
|
+
request,
|
|
970
|
+
)
|
|
971
|
+
|
|
972
|
+
return {
|
|
973
|
+
"status_code": response.status_code,
|
|
974
|
+
"headers": response.headers,
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
async def history(self, memory_id: str) -> List[Dict[str, Any]]:
|
|
978
|
+
"""Retrieve the history of a specific memory (async version).
|
|
979
|
+
|
|
980
|
+
Args:
|
|
981
|
+
memory_id: The ID of the memory to retrieve history for.
|
|
982
|
+
|
|
983
|
+
Returns:
|
|
984
|
+
A list of dictionaries containing the memory history.
|
|
985
|
+
"""
|
|
986
|
+
if not memory_id:
|
|
987
|
+
raise ValidationError("memory_id is required")
|
|
988
|
+
|
|
989
|
+
response = await self._client.get_memory_history_async(
|
|
990
|
+
self._project,
|
|
991
|
+
self._memory_store,
|
|
992
|
+
memory_id,
|
|
993
|
+
)
|
|
994
|
+
|
|
995
|
+
if response.body:
|
|
996
|
+
return self._convert_results_list(response.body)
|
|
997
|
+
return []
|
|
998
|
+
|
|
999
|
+
# Memory Store Management Methods (Async)
|
|
1000
|
+
|
|
1001
|
+
async def create_memory_store(
|
|
1002
|
+
self,
|
|
1003
|
+
description: Optional[str] = None,
|
|
1004
|
+
custom_instructions: Optional[str] = None,
|
|
1005
|
+
enable_graph: bool = False,
|
|
1006
|
+
strategy: str = "default",
|
|
1007
|
+
short_term_ttl: int = 7,
|
|
1008
|
+
) -> Dict[str, Any]:
|
|
1009
|
+
"""Create the Memory Store bound to this client (async version).
|
|
1010
|
+
|
|
1011
|
+
Creates the memory store specified during client initialization.
|
|
1012
|
+
If the project does not exist, creates the project first then retries.
|
|
1013
|
+
|
|
1014
|
+
Args:
|
|
1015
|
+
description: Description of the memory store.
|
|
1016
|
+
custom_instructions: Custom instructions for the memory store.
|
|
1017
|
+
enable_graph: Whether to enable knowledge graph. Defaults to False.
|
|
1018
|
+
strategy: Memory processing strategy. Defaults to "default".
|
|
1019
|
+
short_term_ttl: TTL for short-term memories in days. Defaults to 7.
|
|
1020
|
+
|
|
1021
|
+
Returns:
|
|
1022
|
+
A dictionary containing the API response.
|
|
1023
|
+
"""
|
|
1024
|
+
store_name = self._memory_store
|
|
1025
|
+
|
|
1026
|
+
request = sls_models.CreateMemoryStoreRequest(
|
|
1027
|
+
name=store_name,
|
|
1028
|
+
description=description,
|
|
1029
|
+
custom_instructions=custom_instructions,
|
|
1030
|
+
enable_graph=enable_graph,
|
|
1031
|
+
strategy=strategy,
|
|
1032
|
+
short_term_ttl=short_term_ttl,
|
|
1033
|
+
)
|
|
1034
|
+
|
|
1035
|
+
try:
|
|
1036
|
+
response = await self._client.create_memory_store_async(
|
|
1037
|
+
self._project,
|
|
1038
|
+
request,
|
|
1039
|
+
)
|
|
1040
|
+
except Exception as e:
|
|
1041
|
+
if "ProjectNotExist" not in str(e):
|
|
1042
|
+
raise
|
|
1043
|
+
await self._client.create_project_async(
|
|
1044
|
+
sls_models.CreateProjectRequest(
|
|
1045
|
+
project_name=self._project,
|
|
1046
|
+
description="Auto-created by SLS Memory SDK",
|
|
1047
|
+
)
|
|
1048
|
+
)
|
|
1049
|
+
response = await self._client.create_memory_store_async(
|
|
1050
|
+
self._project,
|
|
1051
|
+
request,
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1054
|
+
return {
|
|
1055
|
+
"status_code": response.status_code,
|
|
1056
|
+
"headers": response.headers,
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async def describe_memory_store(self) -> Dict[str, Any]:
|
|
1060
|
+
"""Get detailed information about the current Memory Store (async version).
|
|
1061
|
+
|
|
1062
|
+
Returns:
|
|
1063
|
+
A dictionary containing memory store details including:
|
|
1064
|
+
- name: Memory Store name
|
|
1065
|
+
- description: Description
|
|
1066
|
+
- custom_instructions: Custom instructions
|
|
1067
|
+
- enable_graph: Whether graph is enabled
|
|
1068
|
+
- strategy: Processing strategy
|
|
1069
|
+
- short_term_ttl: Short-term memory TTL
|
|
1070
|
+
- create_time: Creation timestamp
|
|
1071
|
+
- update_time: Last update timestamp
|
|
1072
|
+
"""
|
|
1073
|
+
response = await self._client.get_memory_store_async(
|
|
1074
|
+
self._project,
|
|
1075
|
+
self._memory_store,
|
|
1076
|
+
)
|
|
1077
|
+
|
|
1078
|
+
if response.body:
|
|
1079
|
+
return self._convert_memory_result(response.body)
|
|
1080
|
+
return {}
|
|
1081
|
+
|
|
1082
|
+
async def update_memory_store(
|
|
1083
|
+
self,
|
|
1084
|
+
description: Optional[str] = None,
|
|
1085
|
+
custom_instructions: Optional[str] = None,
|
|
1086
|
+
enable_graph: Optional[bool] = None,
|
|
1087
|
+
strategy: Optional[str] = None,
|
|
1088
|
+
short_term_ttl: Optional[int] = None,
|
|
1089
|
+
) -> Dict[str, Any]:
|
|
1090
|
+
"""Update the configuration of the current Memory Store (async version).
|
|
1091
|
+
|
|
1092
|
+
Args:
|
|
1093
|
+
description: New description.
|
|
1094
|
+
custom_instructions: New custom instructions.
|
|
1095
|
+
enable_graph: Whether to enable knowledge graph.
|
|
1096
|
+
strategy: New memory processing strategy.
|
|
1097
|
+
short_term_ttl: New TTL for short-term memories in seconds.
|
|
1098
|
+
|
|
1099
|
+
Returns:
|
|
1100
|
+
A dictionary containing the API response.
|
|
1101
|
+
"""
|
|
1102
|
+
request = sls_models.UpdateMemoryStoreRequest(
|
|
1103
|
+
description=description,
|
|
1104
|
+
custom_instructions=custom_instructions,
|
|
1105
|
+
enable_graph=enable_graph,
|
|
1106
|
+
strategy=strategy,
|
|
1107
|
+
short_term_ttl=short_term_ttl,
|
|
1108
|
+
)
|
|
1109
|
+
|
|
1110
|
+
response = await self._client.update_memory_store_async(
|
|
1111
|
+
self._project,
|
|
1112
|
+
self._memory_store,
|
|
1113
|
+
request,
|
|
1114
|
+
)
|
|
1115
|
+
|
|
1116
|
+
return {
|
|
1117
|
+
"status_code": response.status_code,
|
|
1118
|
+
"headers": response.headers,
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
async def delete_memory_store(self) -> Dict[str, Any]:
|
|
1122
|
+
"""Delete the current Memory Store (async version).
|
|
1123
|
+
|
|
1124
|
+
Warning:
|
|
1125
|
+
This will permanently delete the memory store and all its memories!
|
|
1126
|
+
|
|
1127
|
+
Returns:
|
|
1128
|
+
A dictionary containing the API response.
|
|
1129
|
+
"""
|
|
1130
|
+
response = await self._client.delete_memory_store_async(
|
|
1131
|
+
self._project,
|
|
1132
|
+
self._memory_store,
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1135
|
+
return {
|
|
1136
|
+
"status_code": response.status_code,
|
|
1137
|
+
"headers": response.headers,
|
|
1138
|
+
}
|
sls_memory/exceptions.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Custom exceptions for SLS Memory SDK.
|
|
4
|
+
|
|
5
|
+
Note: SLS SDK exceptions are passed through directly to preserve full error details.
|
|
6
|
+
This module only contains exceptions for SDK internal validation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ValidationError(ValueError):
|
|
11
|
+
"""Raised when input validation fails in the SDK layer.
|
|
12
|
+
|
|
13
|
+
This exception is raised for parameter validation before calling SLS APIs,
|
|
14
|
+
such as missing required parameters (memory_id, query, etc.).
|
|
15
|
+
|
|
16
|
+
For SLS service errors (authentication, not found, rate limit, etc.),
|
|
17
|
+
the original SLS SDK exceptions are passed through directly.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, message: str):
|
|
21
|
+
super().__init__(message)
|
|
22
|
+
self.message = message
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sls-memory
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A mem0-compatible memory SDK powered by Alibaba Cloud SLS
|
|
5
|
+
Author: Zhengqianyi
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aliyun/aliyun-log-memory-sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/aliyun/aliyun-log-memory-sdk
|
|
9
|
+
Project-URL: Documentation, https://github.com/aliyun/aliyun-log-memory-sdk/blob/master/usage.md
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: alibabacloud-sls20201230>=5.12.0
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# SLS Memory SDK
|
|
22
|
+
|
|
23
|
+
阿里云 SLS Memory 客户端 SDK。
|
|
24
|
+
|
|
25
|
+
## 安装
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install sls-memory
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 快速开始
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from sls_memory import Config, SLSMemoryClient
|
|
35
|
+
|
|
36
|
+
# 初始化客户端
|
|
37
|
+
config = Config(
|
|
38
|
+
access_key_id="your_access_key_id",
|
|
39
|
+
access_key_secret="your_access_key_secret",
|
|
40
|
+
endpoint="cn-hangzhou.log.aliyuncs.com"
|
|
41
|
+
)
|
|
42
|
+
client = SLSMemoryClient(
|
|
43
|
+
config,
|
|
44
|
+
project="my-project",
|
|
45
|
+
memory_store="my-store"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# 添加记忆
|
|
49
|
+
client.add("我喜欢打网球", user_id="user123")
|
|
50
|
+
|
|
51
|
+
# 搜索记忆
|
|
52
|
+
results = client.search("网球", user_id="user123")
|
|
53
|
+
print(results)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 主要功能
|
|
57
|
+
|
|
58
|
+
- ✅ 兼容 mem0 SDK 接口
|
|
59
|
+
- ✅ 支持同步和异步客户端
|
|
60
|
+
- ✅ 支持记忆的增删改查
|
|
61
|
+
- ✅ 支持语义搜索和过滤
|
|
62
|
+
- ✅ 支持 Memory Store 管理
|
|
63
|
+
|
|
64
|
+
## 文档
|
|
65
|
+
|
|
66
|
+
详细使用文档请查看 [usage.md](https://github.com/aliyun/aliyun-log-memory-sdk/blob/master/usage.md)
|
|
67
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
sls_memory/__init__.py,sha256=ODLXhZQDaSvIs4xuIzLEQwIGmfUbu0MVx6GlZbrjq1k,1435
|
|
2
|
+
sls_memory/client.py,sha256=4mMdRKz0ReJkrLYkOOmGsk8w0fG7hRpEeCZbvb8ffIU,37671
|
|
3
|
+
sls_memory/exceptions.py,sha256=ZQA0FTkfoj81rb1gRrEEZJw_JiwqjLBNcvoIpEYzOaY,725
|
|
4
|
+
sls_memory-0.1.0.dist-info/licenses/LICENSE,sha256=wtKGMqopVcxY-8CjUPC4NU4VxzbaEDR2TAcBWC3oLsI,1069
|
|
5
|
+
sls_memory-0.1.0.dist-info/METADATA,sha256=idbLvkA3W3VSRnlyEtEESBOEJLCMfO9wCtSaK3ixmzU,1711
|
|
6
|
+
sls_memory-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
7
|
+
sls_memory-0.1.0.dist-info/top_level.txt,sha256=Odcc3pLcYnCY6jHxSSPN4tu_KzzdFk3YsveatEI26nc,11
|
|
8
|
+
sls_memory-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alibaba Cloud
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sls_memory
|