memwal 0.2.2.dev1__py3-none-any.whl → 0.2.2.dev3__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.
- memwal/__init__.py +1 -1
- memwal/client.py +17 -0
- memwal/mock.py +2 -0
- memwal/types.py +1 -1
- memwal/utils.py +22 -1
- {memwal-0.2.2.dev1.dist-info → memwal-0.2.2.dev3.dist-info}/METADATA +2 -2
- memwal-0.2.2.dev3.dist-info/RECORD +10 -0
- memwal-0.2.2.dev1.dist-info/RECORD +0 -10
- {memwal-0.2.2.dev1.dist-info → memwal-0.2.2.dev3.dist-info}/WHEEL +0 -0
memwal/__init__.py
CHANGED
memwal/client.py
CHANGED
|
@@ -86,6 +86,7 @@ from .utils import (
|
|
|
86
86
|
sha256_hex,
|
|
87
87
|
sign_message,
|
|
88
88
|
sign_sui_personal_message,
|
|
89
|
+
validate_max_distance,
|
|
89
90
|
)
|
|
90
91
|
|
|
91
92
|
T = TypeVar("T")
|
|
@@ -160,6 +161,18 @@ def _require(data: object, field: str, endpoint: str) -> Any:
|
|
|
160
161
|
return data[field]
|
|
161
162
|
|
|
162
163
|
|
|
164
|
+
def _require_positive_int(value: object, name: str) -> None:
|
|
165
|
+
"""Reject anything but a positive ``int`` before it is signed (#1249).
|
|
166
|
+
|
|
167
|
+
``json.dumps`` writes ``float("nan")`` as a bare ``NaN`` token, which is
|
|
168
|
+
not valid JSON, and negative or fractional values were forwarded as-is.
|
|
169
|
+
``bool`` is an ``int`` subclass and is rejected explicitly.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
if isinstance(value, bool) or not isinstance(value, int) or value <= 0:
|
|
173
|
+
raise ValueError(f"{name} must be a positive integer, got {value!r}")
|
|
174
|
+
|
|
175
|
+
|
|
163
176
|
IDEMPOTENCY_BUCKET_MS = 30 * 60 * 1000
|
|
164
177
|
|
|
165
178
|
|
|
@@ -1194,7 +1207,9 @@ class MemWal:
|
|
|
1194
1207
|
sort = params.sort
|
|
1195
1208
|
else:
|
|
1196
1209
|
query_text = query
|
|
1210
|
+
_reject_blank_text(query_text, "query cannot be empty")
|
|
1197
1211
|
_check_limit(limit)
|
|
1212
|
+
validate_max_distance(max_distance)
|
|
1198
1213
|
body = {
|
|
1199
1214
|
"query": query_text,
|
|
1200
1215
|
"limit": limit,
|
|
@@ -1371,6 +1386,8 @@ class MemWal:
|
|
|
1371
1386
|
Returns:
|
|
1372
1387
|
:class:`AskResult` with answer, memories_used count, and memories list.
|
|
1373
1388
|
"""
|
|
1389
|
+
_reject_blank_text(question, "question cannot be empty")
|
|
1390
|
+
_require_positive_int(limit, "limit")
|
|
1374
1391
|
data = await self._signed_request("POST", "/api/ask", {
|
|
1375
1392
|
"question": question,
|
|
1376
1393
|
"limit": limit,
|
memwal/mock.py
CHANGED
|
@@ -38,6 +38,7 @@ from .types import (
|
|
|
38
38
|
RememberResult,
|
|
39
39
|
RestoreResult,
|
|
40
40
|
)
|
|
41
|
+
from .utils import validate_max_distance
|
|
41
42
|
|
|
42
43
|
_MOCK_NAMESPACE_EPOCH = datetime(2026, 1, 1, tzinfo=timezone.utc)
|
|
43
44
|
|
|
@@ -285,6 +286,7 @@ class MemWalMock:
|
|
|
285
286
|
query_text = query
|
|
286
287
|
_validate_text(query_text, "query")
|
|
287
288
|
_check_limit(limit)
|
|
289
|
+
validate_max_distance(max_distance)
|
|
288
290
|
if sort not in (None, "relevance", "recent"):
|
|
289
291
|
raise ValueError("sort must be 'relevance' or 'recent'")
|
|
290
292
|
resolved_namespace = self._namespace if namespace is None else namespace
|
memwal/types.py
CHANGED
|
@@ -24,7 +24,7 @@ DEFAULT_SERVER_URL = "https://relayer.memory.walrus.xyz"
|
|
|
24
24
|
ENV_PRESETS = {
|
|
25
25
|
"prod": "https://relayer.memory.walrus.xyz",
|
|
26
26
|
"dev": "https://relayer.dev.memwal.ai",
|
|
27
|
-
"staging": "https://relayer
|
|
27
|
+
"staging": "https://relayer.dev.memwal.ai",
|
|
28
28
|
"local": "http://127.0.0.1:8000",
|
|
29
29
|
}
|
|
30
30
|
|
memwal/utils.py
CHANGED
|
@@ -9,8 +9,9 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import base64
|
|
11
11
|
import hashlib
|
|
12
|
+
import math
|
|
12
13
|
from datetime import datetime, timezone
|
|
13
|
-
from typing import Tuple, Union
|
|
14
|
+
from typing import Optional, Tuple, Union
|
|
14
15
|
|
|
15
16
|
import nacl.signing
|
|
16
17
|
|
|
@@ -373,3 +374,23 @@ def sign_sui_personal_message(
|
|
|
373
374
|
public_key_bytes = bytes(signing_key.verify_key)
|
|
374
375
|
serialized = bytes([_SUI_ED25519_SCHEME_FLAG]) + signature_bytes + public_key_bytes
|
|
375
376
|
return base64.b64encode(serialized).decode("ascii")
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def validate_max_distance(max_distance: Optional[float]) -> None:
|
|
380
|
+
"""Reject a ``max_distance`` that would silently drop every hit (#1248).
|
|
381
|
+
|
|
382
|
+
The recall filter keeps ``distance < max_distance``. Every comparison with
|
|
383
|
+
NaN is False and real distances are never negative, so NaN or a negative
|
|
384
|
+
threshold returns an empty page that looks like an empty namespace.
|
|
385
|
+
Mirrors the TypeScript ``maxDistance`` guard (#1227).
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
if max_distance is None:
|
|
389
|
+
return
|
|
390
|
+
if (
|
|
391
|
+
isinstance(max_distance, bool)
|
|
392
|
+
or not isinstance(max_distance, (int, float))
|
|
393
|
+
or not math.isfinite(max_distance)
|
|
394
|
+
or max_distance < 0
|
|
395
|
+
):
|
|
396
|
+
raise ValueError("max_distance must be a non-negative finite number")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: memwal
|
|
3
|
-
Version: 0.2.2.
|
|
3
|
+
Version: 0.2.2.dev3
|
|
4
4
|
Summary: Python SDK for Walrus Memory — Privacy-first AI memory with Ed25519 signing
|
|
5
5
|
Project-URL: Homepage, https://memory.walrus.xyz
|
|
6
6
|
Project-URL: Documentation, https://memory.walrus.xyz
|
|
@@ -181,7 +181,7 @@ memwal = MemWal.create(
|
|
|
181
181
|
|-------|-------------|
|
|
182
182
|
| `prod` | `https://relayer.memory.walrus.xyz` |
|
|
183
183
|
| `dev` | `https://relayer.dev.memwal.ai` |
|
|
184
|
-
| `staging` | `https://relayer
|
|
184
|
+
| `staging` | `https://relayer.dev.memwal.ai` |
|
|
185
185
|
|
|
186
186
|
Precedence: any explicit **`server_url` wins over `env`**, including the hosted
|
|
187
187
|
default. `env` applies only when `server_url` is omitted (`None`). An unknown
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
memwal/__init__.py,sha256=9xGvu4OTUpHjju77Hlwd8qb6oDjc6qvfQKM5nFQ1aU0,3142
|
|
2
|
+
memwal/client.py,sha256=3FBM1AP-YYoYPOzZFAeUA_nAYZtHWnTEuJWIdYThVas,97328
|
|
3
|
+
memwal/compatibility.py,sha256=FsKApCcHOFZeIeNOph3YydWVnZtMJdT0KCt0e6jylho,2799
|
|
4
|
+
memwal/middleware.py,sha256=z2xdbvaobBg4byJXnrX7amWdVYE4jfeO4t31DoDBv_o,38413
|
|
5
|
+
memwal/mock.py,sha256=JrYAkvEk_vkDDHd5RMWdyAqdE72GEgqFPlPbAFzZvkA,24347
|
|
6
|
+
memwal/types.py,sha256=yPNAEIGPY3O1GiFln0zW8stTPuV5sZYXAyQqeIkdbhw,13990
|
|
7
|
+
memwal/utils.py,sha256=RYlELBpKUHN9RuvWQu0cSGMoyXpAdTWlNKawfDpDbQ0,13361
|
|
8
|
+
memwal-0.2.2.dev3.dist-info/METADATA,sha256=WjL3FwG7QR-MjLPYJcPUHFGPIVVGjngRp3hnltvuNek,11911
|
|
9
|
+
memwal-0.2.2.dev3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
10
|
+
memwal-0.2.2.dev3.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
memwal/__init__.py,sha256=MGoDtX1cNKJndeJGln3gaFCfk3ueuHt0Mfs-CF2JyyE,3142
|
|
2
|
-
memwal/client.py,sha256=6YExSuMZ9RGeIShakk8UxSXgVY8pKwDexExPgnqhH4I,96563
|
|
3
|
-
memwal/compatibility.py,sha256=FsKApCcHOFZeIeNOph3YydWVnZtMJdT0KCt0e6jylho,2799
|
|
4
|
-
memwal/middleware.py,sha256=z2xdbvaobBg4byJXnrX7amWdVYE4jfeO4t31DoDBv_o,38413
|
|
5
|
-
memwal/mock.py,sha256=cB-mu2yqycvMCVMmgqTTsIj_pGSkHufCyLNbfkPdHEE,24262
|
|
6
|
-
memwal/types.py,sha256=fPvxU4k14qmj577sMtGZyVaGhwXxORtyXL-TxD0P6LI,14002
|
|
7
|
-
memwal/utils.py,sha256=YyLuxPjKB0RksL1ZGPORpW7QrSID0vQQABq3L_64zKw,12596
|
|
8
|
-
memwal-0.2.2.dev1.dist-info/METADATA,sha256=XLsl3x9kG7nJN5MyuQ_hg7te9FZbu59qLwlbUyyQQEM,11923
|
|
9
|
-
memwal-0.2.2.dev1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
10
|
-
memwal-0.2.2.dev1.dist-info/RECORD,,
|
|
File without changes
|