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,5 @@
1
+ """MongoDB session backend for Strands Agents."""
2
+
3
+ from .session_manager import MongoDBSessionManager, MongoDBSessionStorage
4
+
5
+ __all__ = ["MongoDBSessionManager", "MongoDBSessionStorage"]
@@ -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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any