memorisdk 2.1.0__py3-none-any.whl → 2.1.1__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.

Potentially problematic release.


This version of memorisdk might be problematic. Click here for more details.

memori/__init__.py CHANGED
@@ -5,7 +5,7 @@ Professional-grade memory layer with comprehensive error handling, configuration
5
5
  management, and modular architecture for production AI systems.
6
6
  """
7
7
 
8
- __version__ = "2.1.0"
8
+ __version__ = "2.1.1"
9
9
  __author__ = "Harshal More"
10
10
  __email__ = "harshalmore2468@gmail.com"
11
11
 
@@ -24,9 +24,9 @@ try:
24
24
  from pymongo.errors import ConnectionFailure, OperationFailure # noqa: F401
25
25
 
26
26
  PYMONGO_AVAILABLE = True
27
- MongoClient = _MongoClient
28
- Collection = _Collection
29
- Database = _Database
27
+ MongoClient = _MongoClient # type: ignore
28
+ Collection = _Collection # type: ignore
29
+ Database = _Database # type: ignore
30
30
  except ImportError:
31
31
  PYMONGO_AVAILABLE = False
32
32
  MongoClient = None # type: ignore
@@ -72,21 +72,86 @@ class MongoDBConnector(BaseDatabaseConnector):
72
72
  def _parse_connection_string(self):
73
73
  """Parse MongoDB connection string to extract components"""
74
74
  try:
75
- parsed = urlparse(self.connection_string)
76
- self.host = parsed.hostname or "localhost"
77
- self.port = parsed.port or 27017
78
- self.database_name = parsed.path.lstrip("/") or "memori"
79
- self.username = parsed.username
80
- self.password = parsed.password
81
-
82
- # Extract query parameters
83
- self.options = {}
84
- if parsed.query:
85
- params = parsed.query.split("&")
86
- for param in params:
87
- if "=" in param:
88
- key, value = param.split("=", 1)
89
- self.options[key] = value
75
+ # Handle MongoDB connection strings properly (including replica sets)
76
+ if self.connection_string.startswith(
77
+ "mongodb://"
78
+ ) or self.connection_string.startswith("mongodb+srv://"):
79
+ # For MongoDB URIs, extract database name and basic info for logging
80
+ # but let pymongo handle the full parsing
81
+ if "?" in self.connection_string:
82
+ uri_part, query_part = self.connection_string.split("?", 1)
83
+ else:
84
+ uri_part, query_part = self.connection_string, ""
85
+
86
+ # Extract database name from path
87
+ if "/" in uri_part:
88
+ path_part = uri_part.split("/")[-1]
89
+ self.database_name = path_part if path_part else "memori"
90
+ else:
91
+ self.database_name = "memori"
92
+
93
+ # Extract host info for logging
94
+ is_srv_uri = self.connection_string.startswith("mongodb+srv://")
95
+
96
+ if is_srv_uri:
97
+ # For SRV URIs, extract the service hostname
98
+ if "@" in uri_part:
99
+ srv_host = uri_part.split("@")[1].split("/")[0].split("?")[0]
100
+ else:
101
+ srv_host = (
102
+ uri_part.replace("mongodb+srv://", "")
103
+ .split("/")[0]
104
+ .split("?")[0]
105
+ )
106
+ self.host = srv_host
107
+ self.port = (
108
+ 27017 # SRV uses default port, actual ports resolved via DNS
109
+ )
110
+ else:
111
+ # Regular mongodb:// URI parsing
112
+ if "@" in uri_part:
113
+ host_part = uri_part.split("@")[1]
114
+ else:
115
+ host_part = uri_part.replace("mongodb://", "")
116
+
117
+ # Get first host for logging purposes
118
+ if "," in host_part:
119
+ first_host = host_part.split(",")[0].split("/")[0]
120
+ else:
121
+ first_host = host_part.split("/")[0]
122
+
123
+ if ":" in first_host:
124
+ self.host, port_str = first_host.split(":", 1)
125
+ try:
126
+ self.port = int(port_str)
127
+ except ValueError:
128
+ self.port = 27017
129
+ else:
130
+ self.host = first_host
131
+ self.port = 27017
132
+
133
+ # Extract auth info
134
+ parsed = urlparse(self.connection_string)
135
+ self.username = parsed.username
136
+ self.password = parsed.password
137
+
138
+ # Extract query parameters
139
+ self.options = {}
140
+ if query_part:
141
+ params = query_part.split("&")
142
+ for param in params:
143
+ if "=" in param:
144
+ key, value = param.split("=", 1)
145
+ self.options[key] = value
146
+ else:
147
+ # Fall back to urlparse for simple connection strings
148
+ parsed = urlparse(self.connection_string)
149
+ self.host = parsed.hostname or "localhost"
150
+ self.port = parsed.port or 27017
151
+ self.database_name = parsed.path.lstrip("/") or "memori"
152
+ self.username = parsed.username
153
+ self.password = parsed.password
154
+ self.options = {}
90
155
 
91
156
  except Exception as e:
92
157
  logger.warning(f"Failed to parse MongoDB connection string: {e}")
@@ -99,7 +164,7 @@ class MongoDBConnector(BaseDatabaseConnector):
99
164
  self.options = {}
100
165
 
101
166
  def get_connection(self) -> MongoClient:
102
- """Get MongoDB client connection"""
167
+ """Get MongoDB client connection with support for mongodb+srv DNS seedlist"""
103
168
  if self.client is None:
104
169
  try:
105
170
  # Create MongoDB client with appropriate options
@@ -111,14 +176,76 @@ class MongoDBConnector(BaseDatabaseConnector):
111
176
  "retryWrites": True, # Enable retryable writes
112
177
  }
113
178
 
114
- # Add any additional options from connection string
179
+ # Special handling for mongodb+srv URIs
180
+ is_srv_uri = self.connection_string.startswith("mongodb+srv://")
181
+
182
+ if is_srv_uri:
183
+ # For mongodb+srv URIs, TLS is automatically enabled
184
+ # Don't set directConnection for SRV URIs as they use DNS seedlist discovery
185
+ logger.info(
186
+ "Using MongoDB Atlas DNS seedlist discovery (mongodb+srv)"
187
+ )
188
+
189
+ # Add modern SRV-specific options for 2025
190
+ srv_options = {
191
+ "srvMaxHosts": 0, # No limit on SRV hosts (default)
192
+ "srvServiceName": "mongodb", # Default service name
193
+ }
194
+ client_options.update(srv_options)
195
+ else:
196
+ # For standard mongodb:// URIs
197
+ # Handle replica sets vs single hosts
198
+ if "replicaSet" in self.options:
199
+ logger.info("Using MongoDB replica set connection")
200
+ elif "," in self.connection_string:
201
+ logger.info("Using MongoDB multiple host connection")
202
+ else:
203
+ logger.info("Using MongoDB single host connection")
204
+
205
+ # Add any additional options from connection string (these override defaults)
115
206
  client_options.update(self.options)
116
207
 
208
+ # Never set directConnection for SRV URIs or replica sets
209
+ if is_srv_uri or "replicaSet" in self.options:
210
+ client_options.pop("directConnection", None)
211
+
212
+ logger.debug(f"MongoDB connection options: {client_options}")
117
213
  self.client = MongoClient(self.connection_string, **client_options)
118
214
 
119
- # Test connection
215
+ # Test connection with more detailed logging
120
216
  self.client.admin.command("ping")
121
- logger.info(f"Connected to MongoDB at {self.host}:{self.port}")
217
+
218
+ # Get server info for better logging
219
+ try:
220
+ server_info = self.client.server_info()
221
+ version = server_info.get("version", "unknown")
222
+ logger.info(
223
+ f"Connected to MongoDB {version} at {self.host}:{self.port}"
224
+ )
225
+
226
+ if is_srv_uri:
227
+ # Log DNS-resolved hosts for SRV connections
228
+ topology = self.client.topology_description
229
+ hosts = []
230
+ for server in topology.server_descriptions():
231
+ if hasattr(server, "address") and server.address:
232
+ if (
233
+ isinstance(server.address, tuple)
234
+ and len(server.address) >= 2
235
+ ):
236
+ hosts.append(
237
+ f"{server.address[0]}:{server.address[1]}"
238
+ )
239
+ else:
240
+ hosts.append(str(server.address))
241
+
242
+ if hosts:
243
+ logger.info(f"DNS resolved hosts: {', '.join(hosts)}")
244
+ else:
245
+ logger.info("DNS seedlist discovery completed successfully")
246
+ except Exception as e:
247
+ logger.warning(f"Could not get server info: {e}")
248
+ logger.info(f"Connected to MongoDB at {self.host}:{self.port}")
122
249
 
123
250
  except Exception as e:
124
251
  raise DatabaseError(f"Failed to connect to MongoDB: {e}")
@@ -31,9 +31,9 @@ try:
31
31
  )
32
32
 
33
33
  PYMONGO_AVAILABLE = True
34
- MongoClient = _MongoClient
35
- Collection = _Collection
36
- Database = _Database
34
+ MongoClient = _MongoClient # type: ignore
35
+ Collection = _Collection # type: ignore
36
+ Database = _Database # type: ignore
37
37
  except ImportError:
38
38
  PYMONGO_AVAILABLE = False
39
39
  MongoClient = None # type: ignore
@@ -92,20 +92,27 @@ class MongoDBDatabaseManager:
92
92
  # Handle both mongodb:// and mongodb+srv:// schemes
93
93
  parsed = urlparse(self.database_connect)
94
94
 
95
- # Extract host - ensure it's a proper hostname/IP
95
+ # Extract host - handle SRV URIs differently
96
96
  hostname = parsed.hostname
97
- if hostname and hostname != "localhost":
98
- # Check if it's a valid hostname/IP, if not fall back to localhost
99
- import socket
97
+ is_srv_uri = self.database_connect.startswith("mongodb+srv://")
100
98
 
101
- try:
102
- socket.gethostbyname(hostname)
99
+ if hostname and hostname != "localhost":
100
+ if is_srv_uri:
101
+ # For SRV URIs, don't try to resolve hostname directly
102
+ # PyMongo will handle SRV resolution internally
103
103
  self.host = hostname
104
- except socket.gaierror:
105
- logger.warning(
106
- f"Cannot resolve hostname '{hostname}', falling back to localhost"
107
- )
108
- self.host = "localhost"
104
+ else:
105
+ # For regular mongodb:// URIs, check hostname resolution
106
+ import socket
107
+
108
+ try:
109
+ socket.gethostbyname(hostname)
110
+ self.host = hostname
111
+ except socket.gaierror:
112
+ logger.warning(
113
+ f"Cannot resolve hostname '{hostname}', falling back to localhost"
114
+ )
115
+ self.host = "localhost"
109
116
  else:
110
117
  self.host = hostname or "localhost"
111
118
 
@@ -138,7 +145,7 @@ class MongoDBDatabaseManager:
138
145
  self.options = {}
139
146
 
140
147
  def _get_client(self) -> MongoClient:
141
- """Get MongoDB client connection with caching and fallbacks"""
148
+ """Get MongoDB client connection with support for mongodb+srv DNS seedlist"""
142
149
  if self.client is None:
143
150
  try:
144
151
  # Create MongoDB client with appropriate options
@@ -148,33 +155,108 @@ class MongoDBDatabaseManager:
148
155
  "socketTimeoutMS": 10000, # 10 second socket timeout
149
156
  "maxPoolSize": 50, # Connection pool size
150
157
  "retryWrites": True, # Enable retryable writes
151
- "directConnection": True, # Direct connection to avoid replica set issues
152
158
  }
153
159
 
154
- # Add any additional options from connection string
155
- client_options.update(self.options)
160
+ # Check if this is a mongodb+srv URI for DNS seedlist discovery
161
+ is_srv_uri = self.database_connect.startswith("mongodb+srv://")
156
162
 
157
- # Try original connection string first
158
- try:
163
+ if is_srv_uri:
164
+ logger.info(
165
+ "Using MongoDB Atlas DNS seedlist discovery (mongodb+srv)"
166
+ )
167
+
168
+ # Add modern SRV-specific options for 2025
169
+ srv_options = {
170
+ "srvMaxHosts": 0, # No limit on SRV hosts (default)
171
+ "srvServiceName": "mongodb", # Default service name
172
+ }
173
+ client_options.update(srv_options)
174
+
175
+ # For SRV URIs, don't use fallback - they handle discovery automatically
176
+ # Add any additional options from connection string (these override defaults)
177
+ client_options.update(self.options)
178
+
179
+ # Never set directConnection for SRV URIs
180
+ client_options.pop("directConnection", None)
181
+
182
+ logger.debug(f"MongoDB+SRV connection options: {client_options}")
159
183
  self.client = MongoClient(self.database_connect, **client_options)
184
+
160
185
  # Test connection
161
186
  self.client.admin.command("ping")
162
- logger.info("Connected to MongoDB using original connection string")
163
- except Exception as original_error:
164
- logger.warning(f"Original connection failed: {original_error}")
165
187
 
166
- # Try fallback with explicit host:port
167
- fallback_uri = (
168
- f"mongodb://{self.host}:{self.port}/{self.database_name}"
169
- )
170
- logger.info(f"Trying fallback connection: {fallback_uri}")
188
+ # Get server info and DNS-resolved hosts for better logging
189
+ try:
190
+ server_info = self.client.server_info()
191
+ version = server_info.get("version", "unknown")
192
+ logger.info(f"Connected to MongoDB Atlas {version}")
193
+
194
+ # Log DNS-resolved hosts for SRV connections
195
+ try:
196
+ topology = self.client.topology_description
197
+ hosts = []
198
+ for server in topology.server_descriptions():
199
+ try:
200
+ if hasattr(server, "address") and server.address:
201
+ if (
202
+ isinstance(server.address, tuple)
203
+ and len(server.address) >= 2
204
+ ):
205
+ hosts.append(
206
+ f"{server.address[0]}:{server.address[1]}"
207
+ )
208
+ else:
209
+ hosts.append(str(server.address))
210
+ except AttributeError:
211
+ # Some server descriptions might not have address attribute
212
+ continue
213
+
214
+ if hosts:
215
+ logger.info(
216
+ f"DNS resolved MongoDB Atlas hosts: {', '.join(hosts)}"
217
+ )
218
+ else:
219
+ logger.info(
220
+ "MongoDB Atlas DNS seedlist discovery completed successfully"
221
+ )
222
+ except Exception as e:
223
+ logger.debug(
224
+ f"Could not get Atlas server topology info: {e}"
225
+ )
226
+ except Exception as e:
227
+ logger.warning(f"Could not get Atlas server info: {e}")
228
+ logger.info("Connected to MongoDB Atlas successfully")
171
229
 
172
- self.client = MongoClient(fallback_uri, **client_options)
173
- # Test connection
174
- self.client.admin.command("ping")
175
- logger.info(
176
- f"Connected to MongoDB at {self.host}:{self.port}/{self.database_name}"
177
- )
230
+ else:
231
+ # Legacy mongodb:// URI handling with fallbacks
232
+ # Add any additional options from connection string
233
+ client_options.update(self.options)
234
+
235
+ # Try original connection string first
236
+ try:
237
+ self.client = MongoClient(
238
+ self.database_connect, **client_options
239
+ )
240
+ # Test connection
241
+ self.client.admin.command("ping")
242
+ logger.info(
243
+ "Connected to MongoDB using original connection string"
244
+ )
245
+ except Exception as original_error:
246
+ logger.warning(f"Original connection failed: {original_error}")
247
+
248
+ # Try fallback with explicit host:port (only for non-SRV URIs)
249
+ fallback_uri = (
250
+ f"mongodb://{self.host}:{self.port}/{self.database_name}"
251
+ )
252
+ logger.info(f"Trying fallback connection: {fallback_uri}")
253
+
254
+ self.client = MongoClient(fallback_uri, **client_options)
255
+ # Test connection
256
+ self.client.admin.command("ping")
257
+ logger.info(
258
+ f"Connected to MongoDB at {self.host}:{self.port}/{self.database_name}"
259
+ )
178
260
 
179
261
  except Exception as e:
180
262
  error_msg = f"Failed to connect to MongoDB: {e}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memorisdk
3
- Version: 2.1.0
3
+ Version: 2.1.1
4
4
  Summary: The Open-Source Memory Layer for AI Agents & Multi-Agent Systems
5
5
  Author-email: GibsonAI Team <noc@gibsonai.com>
6
6
  License: Apache-2.0
@@ -53,11 +53,11 @@ Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgres"
53
53
  Provides-Extra: mysql
54
54
  Requires-Dist: PyMySQL>=1.0.0; extra == "mysql"
55
55
  Provides-Extra: mongodb
56
- Requires-Dist: pymongo>=4.0.0; extra == "mongodb"
56
+ Requires-Dist: pymongo[srv]>=4.0.0; extra == "mongodb"
57
57
  Provides-Extra: databases
58
58
  Requires-Dist: psycopg2-binary>=2.9.0; extra == "databases"
59
59
  Requires-Dist: PyMySQL>=1.0.0; extra == "databases"
60
- Requires-Dist: pymongo>=4.0.0; extra == "databases"
60
+ Requires-Dist: pymongo[srv]>=4.0.0; extra == "databases"
61
61
  Provides-Extra: anthropic
62
62
  Requires-Dist: anthropic>=0.3.0; extra == "anthropic"
63
63
  Provides-Extra: litellm
@@ -87,6 +87,7 @@ Requires-Dist: mkdocs-minify-plugin>=0.7.0; extra == "all"
87
87
  Requires-Dist: mkdocs-redirects>=1.2.0; extra == "all"
88
88
  Requires-Dist: psycopg2-binary>=2.9.0; extra == "all"
89
89
  Requires-Dist: PyMySQL>=1.0.0; extra == "all"
90
+ Requires-Dist: pymongo[srv]>=4.0.0; extra == "all"
90
91
  Requires-Dist: litellm>=1.0.0; extra == "all"
91
92
  Requires-Dist: anthropic>=0.3.0; extra == "all"
92
93
  Requires-Dist: streamlit>=1.28.0; extra == "all"
@@ -1,4 +1,4 @@
1
- memori/__init__.py,sha256=cwAJcWkWX1bbulI3oQK512OSd7mv_0wEAhzwE3OWUYo,3670
1
+ memori/__init__.py,sha256=u5Y2fGofYR3hZwRLN0lwu24iVztgmDLk0JGZfwhSjW8,3670
2
2
  memori/agents/__init__.py,sha256=9M3IG5R10FfVgT8tUzBZ2pZ0SypSpYkFfhtyvMyeTpE,261
3
3
  memori/agents/conscious_agent.py,sha256=x3MFps2BSIt9CubjwFUZ_2g4EXESO66aT2lyHx_LiDQ,22225
4
4
  memori/agents/memory_agent.py,sha256=khCbbBaMfHm7uYxZvIw4JO4kXzM848R_Cual0uSVZ2A,23957
@@ -16,7 +16,7 @@ memori/database/__init__.py,sha256=yungdfis0lyDE2eZFs86miYCAMG4klhS-TLhKq-1K3w,4
16
16
  memori/database/auto_creator.py,sha256=oMUKuJlLqwG4OxbhkMMjq0e5DDan3KcvAfEM2a56jOQ,12662
17
17
  memori/database/connection_utils.py,sha256=QQ50IQlrNUd0CWiFQeH76yIi1evbgMv8dDV29QkSAsc,6796
18
18
  memori/database/models.py,sha256=jPsD_ALGHMgv6_nxgizSQ2BTbNTupCMPOuS5EBaUiFU,14826
19
- memori/database/mongodb_manager.py,sha256=9i65D5mX2v0nM-3mR6-YxouybvHtnnLMB5i58uPBs7Y,55049
19
+ memori/database/mongodb_manager.py,sha256=aB4vEnL2Jrb0ny4wbhsQGouTwkKfcVGNwsc-D8k7WYA,59270
20
20
  memori/database/query_translator.py,sha256=ruwzfIVxhcO5ouNamRVlxIUMkesU7xE8N5LzgaPW9Qc,6988
21
21
  memori/database/search_service.py,sha256=QH0CQaDONR3aSd7Su2C6Ysz4pikbYk3NDFRkP4EcFws,26856
22
22
  memori/database/sqlalchemy_manager.py,sha256=qSVSUp76CFiAy7CUvwdq3xGeXPGimhZxac0OtnV6XKQ,34926
@@ -27,7 +27,7 @@ memori/database/adapters/postgresql_adapter.py,sha256=QQEQtWVozlLDa4Cz2yWk1xC1Of
27
27
  memori/database/adapters/sqlite_adapter.py,sha256=Mu6Vjy2dCirAZcO591omLZXnbO0zMkD-WO23KGfV4Ck,9142
28
28
  memori/database/connectors/__init__.py,sha256=vQvrAVrN93Sd-kRpFllKLsFJPOCu35E1NHyCLIfG6cw,519
29
29
  memori/database/connectors/base_connector.py,sha256=y-XZVGWf01VmxVpvh9EiG73io6zmVLXXWfhgYlT1U7k,9603
30
- memori/database/connectors/mongodb_connector.py,sha256=_bYXgPzmP8Bq-WcqCfPOSnGKya0150ywXbAeNeWyNPs,21416
30
+ memori/database/connectors/mongodb_connector.py,sha256=hRWPD2JvV3CxsYe7E63FHIKUVenCe7uGbalqd5eaFcI,27646
31
31
  memori/database/connectors/mysql_connector.py,sha256=RviFF2GRjug90NA60PcvLZ5aJSjAvXkGa42uXSjIIx0,13319
32
32
  memori/database/connectors/postgres_connector.py,sha256=AvLZ6XwWPYhIPrT2zlH1bfB5heEPibisO86r68R3FMg,16635
33
33
  memori/database/connectors/sqlite_connector.py,sha256=7UUFA-6U-N2K8JXxSzF7j2nKYwDV1awWNAJTzMiWH7A,11680
@@ -64,8 +64,8 @@ memori/utils/security_audit.py,sha256=SZyqdHyIUzrrnMxO__dAcnB-3x0vSuHW7eW0apOGT2
64
64
  memori/utils/security_integration.py,sha256=xiyYQ1sEo0yk_0NhWeXzzjTJ60pNbI0SEyAz766iilA,13050
65
65
  memori/utils/transaction_manager.py,sha256=kyxI_gRJUY8b1lq0ZUDN65rNmUC5qIGOyL8obFIysBQ,18735
66
66
  memori/utils/validators.py,sha256=u5emqDrSkN9JlJxdo5yxcCqs510UDOiLf16F6p-Oyps,11267
67
- memorisdk-2.1.0.dist-info/licenses/LICENSE,sha256=gyrDaYsSODngoYE1l68l_UfjppS-oYDrf1MvY1JGhgE,10430
68
- memorisdk-2.1.0.dist-info/METADATA,sha256=nMjmuDVkehI1B5nxNiwaONaP5y0_zuQD89BAwwZo85Q,19846
69
- memorisdk-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
70
- memorisdk-2.1.0.dist-info/top_level.txt,sha256=Nm3ad0isbJYBzTEce-O_gmkAEiTbAbyilgAhRt8IoGA,7
71
- memorisdk-2.1.0.dist-info/RECORD,,
67
+ memorisdk-2.1.1.dist-info/licenses/LICENSE,sha256=gyrDaYsSODngoYE1l68l_UfjppS-oYDrf1MvY1JGhgE,10430
68
+ memorisdk-2.1.1.dist-info/METADATA,sha256=6KWbuv3JjXWmNrCjwqZ-MisJQVK5CqgS9H-0W-AyY0c,19907
69
+ memorisdk-2.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
70
+ memorisdk-2.1.1.dist-info/top_level.txt,sha256=Nm3ad0isbJYBzTEce-O_gmkAEiTbAbyilgAhRt8IoGA,7
71
+ memorisdk-2.1.1.dist-info/RECORD,,