memwal 0.1.2.dev2__tar.gz → 0.1.2.dev3__tar.gz
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-0.1.2.dev2 → memwal-0.1.2.dev3}/PKG-INFO +1 -1
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/__init__.py +4 -2
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/client.py +11 -7
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/types.py +35 -1
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/pyproject.toml +1 -1
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_client.py +33 -2
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/.gitignore +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/CHANGELOG.md +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/README.md +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/.env.example +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/.gitignore +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/async_remember_demo.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/interactive_demo.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/verify_credentials.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/compatibility.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/middleware.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/utils.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/run_tests.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/__init__.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_env_presets.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_integration.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_middleware.py +0 -0
- {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_signing.py +0 -0
|
@@ -32,7 +32,6 @@ from .client import (
|
|
|
32
32
|
MemWalSync,
|
|
33
33
|
)
|
|
34
34
|
from .middleware import with_memwal_langchain, with_memwal_openai
|
|
35
|
-
from .utils import delegate_key_to_sui_address, delegate_key_to_public_key
|
|
36
35
|
from .types import (
|
|
37
36
|
ENV_PRESETS,
|
|
38
37
|
AnalyzedFact,
|
|
@@ -61,7 +60,9 @@ from .types import (
|
|
|
61
60
|
RememberManualResult,
|
|
62
61
|
RememberResult,
|
|
63
62
|
RestoreResult,
|
|
63
|
+
ScoringWeights,
|
|
64
64
|
)
|
|
65
|
+
from .utils import delegate_key_to_public_key, delegate_key_to_sui_address
|
|
65
66
|
|
|
66
67
|
# JS-style alias for developers coming from the TypeScript SDK
|
|
67
68
|
withMemWal = with_memwal_langchain
|
|
@@ -105,6 +106,7 @@ __all__ = [
|
|
|
105
106
|
"AnalyzedFact",
|
|
106
107
|
"HealthResult",
|
|
107
108
|
"RestoreResult",
|
|
109
|
+
"ScoringWeights",
|
|
108
110
|
"RememberManualOptions",
|
|
109
111
|
"RememberManualResult",
|
|
110
112
|
"RecallManualOptions",
|
|
@@ -112,4 +114,4 @@ __all__ = [
|
|
|
112
114
|
"RecallManualResult",
|
|
113
115
|
]
|
|
114
116
|
|
|
115
|
-
__version__ = "0.1.2.
|
|
117
|
+
__version__ = "0.1.2.dev3"
|
|
@@ -58,7 +58,6 @@ from .types import (
|
|
|
58
58
|
RememberBulkResult,
|
|
59
59
|
RememberBulkStatusItem,
|
|
60
60
|
RememberBulkStatusResult,
|
|
61
|
-
RememberJobStatus,
|
|
62
61
|
RememberManualOptions,
|
|
63
62
|
RememberManualResult,
|
|
64
63
|
RememberResult,
|
|
@@ -728,14 +727,18 @@ class MemWal:
|
|
|
728
727
|
Returns:
|
|
729
728
|
:class:`RecallManualResult` with blob_id + distance pairs.
|
|
730
729
|
"""
|
|
730
|
+
body: Dict[str, Any] = {
|
|
731
|
+
"vector": opts.vector,
|
|
732
|
+
"limit": opts.limit,
|
|
733
|
+
"namespace": opts.namespace or self._namespace,
|
|
734
|
+
}
|
|
735
|
+
if opts.scoring_weights is not None:
|
|
736
|
+
body["scoring_weights"] = opts.scoring_weights.to_wire()
|
|
737
|
+
|
|
731
738
|
data = await self._signed_request(
|
|
732
739
|
"POST",
|
|
733
740
|
"/api/recall/manual",
|
|
734
|
-
|
|
735
|
-
"vector": opts.vector,
|
|
736
|
-
"limit": opts.limit,
|
|
737
|
-
"namespace": opts.namespace or self._namespace,
|
|
738
|
-
},
|
|
741
|
+
body,
|
|
739
742
|
include_seal_session=False,
|
|
740
743
|
)
|
|
741
744
|
hits = [
|
|
@@ -840,7 +843,8 @@ class MemWal:
|
|
|
840
843
|
version = obj.get("version")
|
|
841
844
|
if str(version) != "1":
|
|
842
845
|
raise MemWalError(
|
|
843
|
-
f"SEAL package {package_id} must be at version 1 to build
|
|
846
|
+
f"SEAL package {package_id} must be at version 1 to build "
|
|
847
|
+
f"x-seal-session, got {version!r}"
|
|
844
848
|
)
|
|
845
849
|
|
|
846
850
|
async def _build_seal_session_inner(self) -> str:
|
|
@@ -36,7 +36,8 @@ class MemWalConfig:
|
|
|
36
36
|
"""Configuration for creating a Walrus Memory client.
|
|
37
37
|
|
|
38
38
|
Attributes:
|
|
39
|
-
key: Ed25519 private key (hex string). This is the delegate key from the
|
|
39
|
+
key: Ed25519 private key (hex string). This is the delegate key from the
|
|
40
|
+
Walrus Memory dashboard.
|
|
40
41
|
account_id: Walrus Memory account object ID on Sui.
|
|
41
42
|
server_url: Server URL (default: http://localhost:8000). An explicit
|
|
42
43
|
non-default value always wins over ``env``.
|
|
@@ -99,6 +100,37 @@ class RecallResult:
|
|
|
99
100
|
total: int
|
|
100
101
|
|
|
101
102
|
|
|
103
|
+
@dataclass
|
|
104
|
+
class ScoringWeights:
|
|
105
|
+
"""Optional composite-scoring weights for recall ranking.
|
|
106
|
+
|
|
107
|
+
Attributes:
|
|
108
|
+
semantic: Weight applied to semantic similarity (default: 1).
|
|
109
|
+
recency: Weight applied to recency decay (default: 0).
|
|
110
|
+
recency_half_life_days: Half-life for the recency term, in days (default: 30).
|
|
111
|
+
importance: Weight applied to memory importance (default: 0).
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
semantic: Optional[float] = None
|
|
115
|
+
recency: Optional[float] = None
|
|
116
|
+
recency_half_life_days: Optional[float] = None
|
|
117
|
+
importance: Optional[float] = None
|
|
118
|
+
|
|
119
|
+
def to_wire(self) -> Dict[str, float]:
|
|
120
|
+
"""Return the snake_case payload expected by the relayer."""
|
|
121
|
+
|
|
122
|
+
payload: Dict[str, float] = {}
|
|
123
|
+
if self.semantic is not None:
|
|
124
|
+
payload["semantic"] = self.semantic
|
|
125
|
+
if self.recency is not None:
|
|
126
|
+
payload["recency"] = self.recency
|
|
127
|
+
if self.recency_half_life_days is not None:
|
|
128
|
+
payload["recency_half_life_days"] = self.recency_half_life_days
|
|
129
|
+
if self.importance is not None:
|
|
130
|
+
payload["importance"] = self.importance
|
|
131
|
+
return payload
|
|
132
|
+
|
|
133
|
+
|
|
102
134
|
@dataclass
|
|
103
135
|
class AnalyzedFact:
|
|
104
136
|
"""A single extracted fact."""
|
|
@@ -212,11 +244,13 @@ class RecallManualOptions:
|
|
|
212
244
|
vector: Pre-computed query embedding vector.
|
|
213
245
|
limit: Max number of results (default: 10).
|
|
214
246
|
namespace: Namespace (default: config namespace or "default").
|
|
247
|
+
scoring_weights: Optional composite-scoring weights applied before returning hits.
|
|
215
248
|
"""
|
|
216
249
|
|
|
217
250
|
vector: List[float]
|
|
218
251
|
limit: int = 10
|
|
219
252
|
namespace: Optional[str] = None
|
|
253
|
+
scoring_weights: Optional[ScoringWeights] = None
|
|
220
254
|
|
|
221
255
|
|
|
222
256
|
@dataclass
|
|
@@ -17,7 +17,7 @@ import pytest
|
|
|
17
17
|
import respx
|
|
18
18
|
|
|
19
19
|
from memwal.client import MemWal, MemWalCompatibilityError, MemWalError
|
|
20
|
-
from memwal.types import RecallManualOptions, RememberManualOptions
|
|
20
|
+
from memwal.types import RecallManualOptions, RememberManualOptions, ScoringWeights
|
|
21
21
|
from memwal.utils import build_signature_message, bytes_to_hex, sha256_hex
|
|
22
22
|
|
|
23
23
|
# ============================================================
|
|
@@ -327,7 +327,11 @@ class TestRecall:
|
|
|
327
327
|
)
|
|
328
328
|
)
|
|
329
329
|
|
|
330
|
-
result = await memwal_client.wait_for_remember_job(
|
|
330
|
+
result = await memwal_client.wait_for_remember_job(
|
|
331
|
+
"job-1",
|
|
332
|
+
poll_interval_ms=0,
|
|
333
|
+
timeout_ms=100,
|
|
334
|
+
)
|
|
331
335
|
|
|
332
336
|
request = route.calls[0].request
|
|
333
337
|
assert request.content == b""
|
|
@@ -583,6 +587,33 @@ class TestManualAPI:
|
|
|
583
587
|
assert len(result.results) == 1
|
|
584
588
|
assert result.results[0].blob_id == "b1"
|
|
585
589
|
|
|
590
|
+
@respx.mock
|
|
591
|
+
async def test_recall_manual_forwards_scoring_weights(self, memwal_client: MemWal) -> None:
|
|
592
|
+
_mock_version()
|
|
593
|
+
route = respx.post(f"{_TEST_SERVER}/api/recall/manual").mock(
|
|
594
|
+
return_value=httpx.Response(200, json={"results": [], "total": 0})
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
opts = RecallManualOptions(
|
|
598
|
+
vector=[0.1, 0.2, 0.3],
|
|
599
|
+
limit=5,
|
|
600
|
+
scoring_weights=ScoringWeights(
|
|
601
|
+
semantic=1.0,
|
|
602
|
+
recency=0.5,
|
|
603
|
+
recency_half_life_days=7.0,
|
|
604
|
+
importance=2.0,
|
|
605
|
+
),
|
|
606
|
+
)
|
|
607
|
+
await memwal_client.recall_manual(opts)
|
|
608
|
+
|
|
609
|
+
body = json.loads(route.calls[0].request.content)
|
|
610
|
+
assert body["scoring_weights"] == {
|
|
611
|
+
"semantic": 1.0,
|
|
612
|
+
"recency": 0.5,
|
|
613
|
+
"recency_half_life_days": 7.0,
|
|
614
|
+
"importance": 2.0,
|
|
615
|
+
}
|
|
616
|
+
|
|
586
617
|
|
|
587
618
|
class TestPublicKey:
|
|
588
619
|
async def test_get_public_key_hex(self, memwal_client: MemWal) -> None:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|