memwal 0.1.5.dev1__tar.gz → 0.1.5.dev2__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 (24) hide show
  1. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/PKG-INFO +1 -1
  2. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/__init__.py +1 -1
  3. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/client.py +17 -5
  4. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/types.py +11 -0
  5. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/pyproject.toml +1 -1
  6. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/test_client.py +52 -0
  7. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/.gitignore +0 -0
  8. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/CHANGELOG.md +0 -0
  9. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/README.md +0 -0
  10. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/examples/.env.example +0 -0
  11. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/examples/.gitignore +0 -0
  12. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/examples/async_remember_demo.py +0 -0
  13. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/examples/interactive_demo.py +0 -0
  14. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/examples/verify_credentials.py +0 -0
  15. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/compatibility.py +0 -0
  16. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/middleware.py +0 -0
  17. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/memwal/utils.py +0 -0
  18. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/notebooks/walrus_memory_python_sdk.ipynb +0 -0
  19. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/run_tests.py +0 -0
  20. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/__init__.py +0 -0
  21. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/test_env_presets.py +0 -0
  22. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/test_integration.py +0 -0
  23. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/test_middleware.py +0 -0
  24. {memwal-0.1.5.dev1 → memwal-0.1.5.dev2}/tests/test_signing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memwal
3
- Version: 0.1.5.dev1
3
+ Version: 0.1.5.dev2
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
@@ -116,4 +116,4 @@ __all__ = [
116
116
  "RecallManualResult",
117
117
  ]
118
118
 
119
- __version__ = "0.1.5.dev1"
119
+ __version__ = "0.1.5.dev2"
@@ -784,22 +784,30 @@ class MemWal:
784
784
  do **not** count as either restored or skipped.
785
785
  * ``total`` — count of on-chain blobs the relayer saw for
786
786
  ``(owner, namespace)`` before the limit was applied.
787
+ * ``truncated`` — True when this restore is known-incomplete (limit
788
+ truncation or an upstream on-chain candidate-fetch cap; see
789
+ :class:`~memwal.types.RestoreResult`). Defaults to ``False`` when
790
+ talking to a relayer older than WALM-319 that omits the field.
787
791
 
788
792
  Args:
789
793
  namespace: Namespace to restore. Exact match — no prefix or
790
794
  hierarchy semantics (see SKILL.md "Namespace Semantics").
791
795
  limit: Max blobs the relayer will *inspect* this call (default:
792
796
  10, matches the server-side default and the TypeScript SDK).
793
- The relayer fetches blobs newest-first and caps the work at
794
- this number; it does **not** cap ``restored`` separately.
797
+ The relayer selects up to this many missing blobs from the
798
+ candidates it sees, in unspecified order; it does **not** cap
799
+ ``restored`` separately.
795
800
 
796
801
  Returns:
797
802
  :class:`RestoreResult`.
798
803
 
799
804
  Notes:
800
- * **No pagination cursor** — restore is single-shot. To rebuild a
801
- large namespace, call repeatedly with a growing ``limit`` or
802
- prune the local index first.
805
+ * **No pagination cursor** — restore is single-shot. A larger
806
+ ``limit`` may help when ``truncated`` is caused by the request
807
+ limit, but candidate discovery also has a per-owner source cap
808
+ shared across namespaces. Hitting that cap requires cursor/
809
+ pagination support for guaranteed full recovery; increasing
810
+ ``limit`` or retrying cannot guarantee it.
803
811
  * **Performance** scales linearly in ``limit``: up to 10 Walrus
804
812
  downloads in parallel, then 3 SEAL decrypts in parallel, then
805
813
  embeddings. Expect seconds-per-blob on cold caches.
@@ -814,6 +822,10 @@ class MemWal:
814
822
  total=data["total"],
815
823
  namespace=data["namespace"],
816
824
  owner=data["owner"],
825
+ # Relayers older than WALM-319 omit `truncated` entirely --
826
+ # treat "not present" as "not known to be truncated" rather
827
+ # than require every relayer version to send it.
828
+ truncated=data.get("truncated", False),
817
829
  )
818
830
 
819
831
  async def health(self) -> HealthResult:
@@ -201,6 +201,17 @@ class RestoreResult:
201
201
  total: int
202
202
  namespace: str
203
203
  owner: str
204
+ #: True when this restore is known-incomplete: either more on-chain
205
+ #: blobs were missing locally than ``limit`` allowed this call to
206
+ #: restore, or the sidecar's raw on-chain candidate fetch hit its own
207
+ #: cap before this namespace's blobs were even filtered out of that
208
+ #: set (WALM-319) -- this can be ``True`` even when ``total == 0``,
209
+ #: since a cap hit elsewhere can starve this namespace's fetch
210
+ #: entirely. Raising ``limit`` only helps with the first case.
211
+ #:
212
+ #: Relayers older than WALM-319 don't send this field at all; the SDK
213
+ #: defaults it to ``False`` in that case rather than requiring it.
214
+ truncated: bool = False
204
215
 
205
216
 
206
217
  @dataclass
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "memwal"
7
- version = "0.1.5.dev1"
7
+ version = "0.1.5.dev2"
8
8
  description = "Python SDK for Walrus Memory — Privacy-first AI memory with Ed25519 signing"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -630,6 +630,7 @@ class TestRestore:
630
630
  "total": 7,
631
631
  "namespace": "my-app",
632
632
  "owner": "0xowner",
633
+ "truncated": False,
633
634
  },
634
635
  )
635
636
  )
@@ -641,6 +642,57 @@ class TestRestore:
641
642
  assert body["limit"] == 100
642
643
  assert result.restored == 5
643
644
  assert result.skipped == 2
645
+ assert result.truncated is False
646
+
647
+ @respx.mock
648
+ async def test_restore_preserves_truncated_true(
649
+ self, memwal_client: MemWal
650
+ ) -> None:
651
+ """truncated=True from the relayer must survive into RestoreResult
652
+ instead of being dropped when the dataclass is reconstructed."""
653
+ mock_seal_session_prereqs()
654
+ respx.post(f"{_TEST_SERVER}/api/restore").mock(
655
+ return_value=httpx.Response(
656
+ 200,
657
+ json={
658
+ "restored": 5,
659
+ "skipped": 2,
660
+ "total": 7,
661
+ "namespace": "my-app",
662
+ "owner": "0xowner",
663
+ "truncated": True,
664
+ },
665
+ )
666
+ )
667
+
668
+ result = await memwal_client.restore("my-app", limit=100)
669
+
670
+ assert result.truncated is True
671
+
672
+ @respx.mock
673
+ async def test_restore_truncated_defaults_false_when_omitted(
674
+ self, memwal_client: MemWal
675
+ ) -> None:
676
+ """Relayers older than WALM-319 omit `truncated` entirely — the
677
+ SDK must default it to False rather than requiring the field."""
678
+ mock_seal_session_prereqs()
679
+ respx.post(f"{_TEST_SERVER}/api/restore").mock(
680
+ return_value=httpx.Response(
681
+ 200,
682
+ json={
683
+ "restored": 5,
684
+ "skipped": 2,
685
+ "total": 7,
686
+ "namespace": "my-app",
687
+ "owner": "0xowner",
688
+ # no "truncated" key — simulates an older relayer
689
+ },
690
+ )
691
+ )
692
+
693
+ result = await memwal_client.restore("my-app", limit=100)
694
+
695
+ assert result.truncated is False
644
696
 
645
697
 
646
698
  class TestHealth:
File without changes
File without changes
File without changes
File without changes
File without changes