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.
Files changed (23) hide show
  1. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/PKG-INFO +1 -1
  2. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/__init__.py +4 -2
  3. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/client.py +11 -7
  4. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/types.py +35 -1
  5. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/pyproject.toml +1 -1
  6. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_client.py +33 -2
  7. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/.gitignore +0 -0
  8. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/CHANGELOG.md +0 -0
  9. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/README.md +0 -0
  10. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/.env.example +0 -0
  11. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/.gitignore +0 -0
  12. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/async_remember_demo.py +0 -0
  13. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/interactive_demo.py +0 -0
  14. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/examples/verify_credentials.py +0 -0
  15. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/compatibility.py +0 -0
  16. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/middleware.py +0 -0
  17. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/memwal/utils.py +0 -0
  18. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/run_tests.py +0 -0
  19. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/__init__.py +0 -0
  20. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_env_presets.py +0 -0
  21. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_integration.py +0 -0
  22. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_middleware.py +0 -0
  23. {memwal-0.1.2.dev2 → memwal-0.1.2.dev3}/tests/test_signing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memwal
3
- Version: 0.1.2.dev2
3
+ Version: 0.1.2.dev3
4
4
  Summary: Python SDK for Walrus Memory — Privacy-first AI memory with Ed25519 signing
5
5
  Project-URL: Homepage, https://memwal.ai
6
6
  Project-URL: Documentation, https://docs.memwal.ai
@@ -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.dev2"
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 x-seal-session, got {version!r}"
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 Walrus Memory dashboard.
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memwal"
7
- version = "0.1.2.dev2"
7
+ version = "0.1.2.dev3"
8
8
  description = "Python SDK for Walrus Memory — Privacy-first AI memory with Ed25519 signing"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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("job-1", poll_interval_ms=0, timeout_ms=100)
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