strands_session_mongodb 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.
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""MongoDB session backend for Strands Agents.
|
|
2
|
+
|
|
3
|
+
Provides a ``MongoDBSessionStorage`` (implementing the ``SessionStorage``
|
|
4
|
+
interface from ``strands-agents-session``) and a thin ``MongoDBSessionManager``
|
|
5
|
+
that wires it into ``KeyValueSessionManager``. All the session-repository logic
|
|
6
|
+
lives in the base package; this module is just the storage layer.
|
|
7
|
+
|
|
8
|
+
Records are stored in a single collection with a compound ``_id`` of the form
|
|
9
|
+
``{pk, sk}``, and a ``data`` field holding the serialized payload. A compound
|
|
10
|
+
index on ``(pk, sk)`` gives ordered range scans for ``list_messages``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Any, Dict, List, Optional
|
|
14
|
+
|
|
15
|
+
from pymongo import ASCENDING, MongoClient
|
|
16
|
+
|
|
17
|
+
from strands_agents_session import KeyValueSessionManager, SessionStorage
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MongoDBSessionStorage(SessionStorage):
|
|
21
|
+
"""MongoDB implementation of the session ``SessionStorage`` interface."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
connection_string: str = "mongodb://127.0.0.1:27017/",
|
|
27
|
+
database_name: str = "strands_sessions",
|
|
28
|
+
collection_name: str = "sessions",
|
|
29
|
+
client: Optional[MongoClient] = None,
|
|
30
|
+
ttl_seconds: Optional[int] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
self.client = client or MongoClient(connection_string)
|
|
33
|
+
self.collection = self.client[database_name][collection_name]
|
|
34
|
+
# Compound index on (pk, sk) — unique identity + ordered range scans.
|
|
35
|
+
self.collection.create_index([("pk", ASCENDING), ("sk", ASCENDING)], unique=True)
|
|
36
|
+
self.ttl_seconds = ttl_seconds
|
|
37
|
+
if ttl_seconds:
|
|
38
|
+
# MongoDB TTL index expires documents `ttl_seconds` after `created_at`.
|
|
39
|
+
self.collection.create_index("created_at", expireAfterSeconds=ttl_seconds)
|
|
40
|
+
|
|
41
|
+
# SessionStorage ----------------------------------------------------
|
|
42
|
+
|
|
43
|
+
def put(self, item: Dict[str, Any]) -> None:
|
|
44
|
+
doc = {"pk": item["pk"], "sk": item["sk"], "data": item["data"]}
|
|
45
|
+
if self.ttl_seconds:
|
|
46
|
+
import datetime
|
|
47
|
+
|
|
48
|
+
doc["created_at"] = datetime.datetime.now(datetime.timezone.utc)
|
|
49
|
+
self.collection.replace_one({"pk": item["pk"], "sk": item["sk"]}, doc, upsert=True)
|
|
50
|
+
|
|
51
|
+
def get(self, pk: str, sk: str) -> Optional[Dict[str, Any]]:
|
|
52
|
+
doc = self.collection.find_one({"pk": pk, "sk": sk})
|
|
53
|
+
if doc is None:
|
|
54
|
+
return None
|
|
55
|
+
return {"pk": doc["pk"], "sk": doc["sk"], "data": doc["data"]}
|
|
56
|
+
|
|
57
|
+
def query(
|
|
58
|
+
self, pk: str, sk_gte: Optional[str] = None, limit: Optional[int] = None
|
|
59
|
+
) -> List[Dict[str, Any]]:
|
|
60
|
+
query: Dict[str, Any] = {"pk": pk}
|
|
61
|
+
if sk_gte is not None:
|
|
62
|
+
query["sk"] = {"$gte": sk_gte}
|
|
63
|
+
cursor = self.collection.find(query).sort("sk", ASCENDING)
|
|
64
|
+
if limit is not None:
|
|
65
|
+
cursor = cursor.limit(limit)
|
|
66
|
+
return [{"pk": d["pk"], "sk": d["sk"], "data": d["data"]} for d in cursor]
|
|
67
|
+
|
|
68
|
+
def delete(self, pk: str, sk: str) -> None:
|
|
69
|
+
self.collection.delete_one({"pk": pk, "sk": sk})
|
|
70
|
+
|
|
71
|
+
def delete_partition(self, pk: str) -> None:
|
|
72
|
+
self.collection.delete_many({"pk": pk})
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class MongoDBSessionManager(KeyValueSessionManager):
|
|
76
|
+
"""MongoDB-backed session manager for Strands Agents.
|
|
77
|
+
|
|
78
|
+
agent = Agent(session_manager=MongoDBSessionManager(
|
|
79
|
+
session_id="user-123",
|
|
80
|
+
connection_string="mongodb://127.0.0.1:27017/",
|
|
81
|
+
))
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
def __init__(
|
|
85
|
+
self,
|
|
86
|
+
session_id: str,
|
|
87
|
+
*,
|
|
88
|
+
connection_string: str = "mongodb://127.0.0.1:27017/",
|
|
89
|
+
database_name: str = "strands_sessions",
|
|
90
|
+
collection_name: str = "sessions",
|
|
91
|
+
client: Optional[MongoClient] = None,
|
|
92
|
+
ttl_seconds: Optional[int] = None,
|
|
93
|
+
**kwargs: Any,
|
|
94
|
+
) -> None:
|
|
95
|
+
storage = MongoDBSessionStorage(
|
|
96
|
+
connection_string=connection_string,
|
|
97
|
+
database_name=database_name,
|
|
98
|
+
collection_name=collection_name,
|
|
99
|
+
client=client,
|
|
100
|
+
ttl_seconds=ttl_seconds,
|
|
101
|
+
)
|
|
102
|
+
super().__init__(session_id=session_id, storage=storage)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strands_session_mongodb
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MongoDB session manager (storage backend) for Strands Agents — persists sessions, agent state, and messages
|
|
5
|
+
Project-URL: Homepage, https://github.com/skamalj/strands-agents-session
|
|
6
|
+
Project-URL: Repository, https://github.com/skamalj/strands-agents-session.git
|
|
7
|
+
Author-email: Kamal <skamalj@github.com>
|
|
8
|
+
Keywords: agent-state,memory,mongodb,persistence,session,strands,strands-agents
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Requires-Dist: pymongo
|
|
15
|
+
Requires-Dist: strands-agents
|
|
16
|
+
Requires-Dist: strands-agents-session>=0.1.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# strands-session-mongodb
|
|
20
|
+
|
|
21
|
+
MongoDB **session manager** (storage backend) for [Strands Agents](https://strandsagents.com). Persists an agent's sessions, agent state, conversation-manager state, and messages to MongoDB so conversations resume across runs.
|
|
22
|
+
|
|
23
|
+
Part of the [`strands-agents-session`](https://pypi.org/project/strands-agents-session/) family — it implements the base `SessionStorage` interface, so all the Strands session-repository logic (message indexing, restore, `removed_message_count` offsetting, tool-use repair) comes from the core.
|
|
24
|
+
|
|
25
|
+
> **Storage only, by design.** Message *pruning* in Strands is a `ConversationManager` concern, decoupled from storage. This package does not prune.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install strands-session-mongodb
|
|
31
|
+
# or, via the family's extra:
|
|
32
|
+
pip install "strands-agents-session[mongodb]"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Requires Python 3.10+** and a reachable MongoDB (local, Atlas, or self-hosted).
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from strands import Agent
|
|
41
|
+
from strands_session_mongodb import MongoDBSessionManager
|
|
42
|
+
|
|
43
|
+
session_manager = MongoDBSessionManager(
|
|
44
|
+
session_id="user-123",
|
|
45
|
+
connection_string="mongodb://127.0.0.1:27017/",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
agent = Agent(session_manager=session_manager)
|
|
49
|
+
agent("Hi, I'm Kamal")
|
|
50
|
+
agent("What's my name?") # remembers within the session
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Next run, same `session_id` → the agent restores its full history and state from MongoDB.
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### `MongoDBSessionManager(session_id, *, connection_string="mongodb://127.0.0.1:27017/", database_name="strands_sessions", collection_name="sessions", client=None, ttl_seconds=None)`
|
|
58
|
+
|
|
59
|
+
| Parameter | Description |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `session_id` | Session identifier |
|
|
62
|
+
| `connection_string` | MongoDB URI (local, Atlas `mongodb+srv://…`, etc.) |
|
|
63
|
+
| `database_name` | Database (default `strands_sessions`) |
|
|
64
|
+
| `collection_name` | Collection (default `sessions`) |
|
|
65
|
+
| `client` | Optional pre-built `pymongo.MongoClient` to reuse |
|
|
66
|
+
| `ttl_seconds` | If set, adds a TTL index so documents expire automatically |
|
|
67
|
+
|
|
68
|
+
## Data model
|
|
69
|
+
|
|
70
|
+
A single collection; each document has a `pk` + `sk` (compound-indexed, unique) and a `data` field with the serialized payload:
|
|
71
|
+
|
|
72
|
+
| Item | pk | sk |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| Session | `SESSION#<session_id>` | `META` |
|
|
75
|
+
| Agent | `SESSION#<session_id>` | `AGENT#<agent_id>` |
|
|
76
|
+
| Message | `SESSION#<session_id>#AGENT#<agent_id>` | `MSG#<zero-padded id>` |
|
|
77
|
+
|
|
78
|
+
The `(pk, sk)` index gives ordered range scans, so `list_messages(offset, limit)` is a simple indexed `find(...).sort(sk).limit(...)` — matching the `removed_message_count` offset semantics Strands relies on.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
strands_session_mongodb/__init__.py,sha256=_SQxOfZ8y4v_NSSi-HmsbPcknDIz7x3WnKU5secJlO8,187
|
|
2
|
+
strands_session_mongodb/session_manager.py,sha256=3yAox5Yl4XONPS8ihFLIHWrDST2YB7OxE6-PkFv6qMg,4006
|
|
3
|
+
strands_session_mongodb-0.1.0.dist-info/METADATA,sha256=FKB7s_i1Id4O4Z8TUGyAvMmu_O318TZXQtEvSr1iyDQ,3423
|
|
4
|
+
strands_session_mongodb-0.1.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
5
|
+
strands_session_mongodb-0.1.0.dist-info/RECORD,,
|