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 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
+ }
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -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