memwal 0.1.8.dev1__tar.gz → 0.1.8.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.
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/PKG-INFO +1 -1
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/__init__.py +1 -1
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/client.py +58 -5
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/pyproject.toml +1 -1
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_client.py +6 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_middleware.py +6 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/.gitignore +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/CHANGELOG.md +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/README.md +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/examples/.env.example +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/examples/.gitignore +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/examples/async_remember_demo.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/examples/interactive_demo.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/examples/verify_credentials.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/compatibility.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/middleware.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/mock.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/types.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/memwal/utils.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/notebooks/walrus_memory_python_sdk.ipynb +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/run_tests.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/__init__.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_auth_rejected_message.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_env_presets.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_integration.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_mock.py +0 -0
- {memwal-0.1.8.dev1 → memwal-0.1.8.dev2}/tests/test_signing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: memwal
|
|
3
|
-
Version: 0.1.8.
|
|
3
|
+
Version: 0.1.8.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
|
|
@@ -83,6 +83,13 @@ from .utils import (
|
|
|
83
83
|
|
|
84
84
|
T = TypeVar("T")
|
|
85
85
|
SEAL_SESSION_TTL_MIN = 5
|
|
86
|
+
|
|
87
|
+
# Networks with a public Sui GraphQL read endpoint (https://graphql.<network>.sui.io).
|
|
88
|
+
PUBLIC_SUI_GRAPHQL_NETWORKS = ("mainnet", "testnet", "devnet")
|
|
89
|
+
|
|
90
|
+
# Fail the package-version preflight fast instead of hanging client init when a
|
|
91
|
+
# Sui read endpoint is unresponsive.
|
|
92
|
+
PACKAGE_VERSION_CHECK_TIMEOUT_S = 10.0
|
|
86
93
|
SEAL_SESSION_SAFETY_MARGIN_MS = 30_000
|
|
87
94
|
AUTH_REJECTED_MESSAGE = (
|
|
88
95
|
"401 from relayer: typically wrong private key, key not registered on this "
|
|
@@ -1039,17 +1046,46 @@ class MemWal:
|
|
|
1039
1046
|
package_id = data.get("packageId")
|
|
1040
1047
|
network = data.get("network")
|
|
1041
1048
|
sui_rpc_url = data.get("suiRpcUrl")
|
|
1042
|
-
if not package_id or not network
|
|
1043
|
-
raise MemWalError("GET /config response missing packageId / network
|
|
1049
|
+
if not package_id or not network:
|
|
1050
|
+
raise MemWalError("GET /config response missing packageId / network")
|
|
1044
1051
|
|
|
1045
1052
|
self._server_config = {
|
|
1046
1053
|
"packageId": package_id,
|
|
1047
1054
|
"network": network,
|
|
1048
|
-
"suiRpcUrl": sui_rpc_url,
|
|
1055
|
+
"suiRpcUrl": sui_rpc_url or "",
|
|
1049
1056
|
}
|
|
1050
1057
|
return self._server_config
|
|
1051
1058
|
|
|
1052
|
-
async def
|
|
1059
|
+
async def _fetch_package_version_graphql(self, network: str, package_id: str):
|
|
1060
|
+
"""Read the package object version via Sui GraphQL RPC.
|
|
1061
|
+
|
|
1062
|
+
JSON-RPC on public fullnodes is sunset (see
|
|
1063
|
+
https://docs.sui.io/develop/accessing-data/json-rpc-migration), and the
|
|
1064
|
+
third-party JSON-RPC mirror the relayer used to advertise has gone
|
|
1065
|
+
unresponsive, hanging every client init. GraphQL is the plain-HTTPS
|
|
1066
|
+
read layer that survives the sunset without pulling gRPC deps into
|
|
1067
|
+
this SDK.
|
|
1068
|
+
"""
|
|
1069
|
+
graphql_url = f"https://graphql.{network}.sui.io/graphql"
|
|
1070
|
+
response = await self._http.post(
|
|
1071
|
+
graphql_url,
|
|
1072
|
+
json={
|
|
1073
|
+
"query": "query($a:SuiAddress!){object(address:$a){version}}",
|
|
1074
|
+
"variables": {"a": package_id},
|
|
1075
|
+
},
|
|
1076
|
+
timeout=PACKAGE_VERSION_CHECK_TIMEOUT_S,
|
|
1077
|
+
)
|
|
1078
|
+
if response.status_code != 200:
|
|
1079
|
+
raise MemWalError(f"Sui GraphQL returned {response.status_code}")
|
|
1080
|
+
body = response.json()
|
|
1081
|
+
obj = (body.get("data") or {}).get("object")
|
|
1082
|
+
if not isinstance(obj, dict) or obj.get("version") is None:
|
|
1083
|
+
raise MemWalError(f"Sui GraphQL could not resolve package {package_id}")
|
|
1084
|
+
return obj["version"]
|
|
1085
|
+
|
|
1086
|
+
async def _fetch_package_version_jsonrpc(self, sui_rpc_url: str, package_id: str):
|
|
1087
|
+
"""Legacy JSON-RPC fallback for custom / local networks that have no
|
|
1088
|
+
public GraphQL endpoint and still serve `sui_getObject`."""
|
|
1053
1089
|
response = await self._http.post(
|
|
1054
1090
|
sui_rpc_url,
|
|
1055
1091
|
json={
|
|
@@ -1058,6 +1094,7 @@ class MemWal:
|
|
|
1058
1094
|
"method": "sui_getObject",
|
|
1059
1095
|
"params": [package_id, {"showBcs": False, "showContent": False, "showType": False}],
|
|
1060
1096
|
},
|
|
1097
|
+
timeout=PACKAGE_VERSION_CHECK_TIMEOUT_S,
|
|
1061
1098
|
)
|
|
1062
1099
|
if response.status_code != 200:
|
|
1063
1100
|
raise MemWalError(f"sui_getObject returned {response.status_code}")
|
|
@@ -1073,6 +1110,20 @@ class MemWal:
|
|
|
1073
1110
|
obj = result.get("object")
|
|
1074
1111
|
if isinstance(obj, dict):
|
|
1075
1112
|
version = obj.get("version")
|
|
1113
|
+
return version
|
|
1114
|
+
|
|
1115
|
+
async def _assert_first_package_version(
|
|
1116
|
+
self, network: str, sui_rpc_url: str, package_id: str
|
|
1117
|
+
) -> None:
|
|
1118
|
+
if network in PUBLIC_SUI_GRAPHQL_NETWORKS:
|
|
1119
|
+
version = await self._fetch_package_version_graphql(network, package_id)
|
|
1120
|
+
elif sui_rpc_url:
|
|
1121
|
+
version = await self._fetch_package_version_jsonrpc(sui_rpc_url, package_id)
|
|
1122
|
+
else:
|
|
1123
|
+
raise MemWalError(
|
|
1124
|
+
f"No Sui read endpoint available for network {network!r}: "
|
|
1125
|
+
"no public GraphQL endpoint and GET /config carried no suiRpcUrl"
|
|
1126
|
+
)
|
|
1076
1127
|
if str(version) != "1":
|
|
1077
1128
|
raise MemWalError(
|
|
1078
1129
|
f"SEAL package {package_id} must be at version 1 to build "
|
|
@@ -1081,7 +1132,9 @@ class MemWal:
|
|
|
1081
1132
|
|
|
1082
1133
|
async def _build_seal_session_inner(self) -> str:
|
|
1083
1134
|
cfg = await self._fetch_server_config()
|
|
1084
|
-
await self._assert_first_package_version(
|
|
1135
|
+
await self._assert_first_package_version(
|
|
1136
|
+
cfg["network"], cfg["suiRpcUrl"], cfg["packageId"]
|
|
1137
|
+
)
|
|
1085
1138
|
|
|
1086
1139
|
session_signing_key = nacl.signing.SigningKey.generate()
|
|
1087
1140
|
session_public_key = bytes(session_signing_key.verify_key)
|
|
@@ -86,6 +86,12 @@ def mock_seal_session_prereqs() -> None:
|
|
|
86
86
|
},
|
|
87
87
|
)
|
|
88
88
|
)
|
|
89
|
+
respx.post("https://graphql.testnet.sui.io/graphql").mock(
|
|
90
|
+
return_value=httpx.Response(
|
|
91
|
+
200,
|
|
92
|
+
json={"data": {"object": {"version": 1}}},
|
|
93
|
+
)
|
|
94
|
+
)
|
|
89
95
|
respx.post(_TEST_SUI_RPC).mock(
|
|
90
96
|
return_value=httpx.Response(
|
|
91
97
|
200,
|
|
@@ -99,6 +99,12 @@ def _mock_seal_session_prereqs() -> None:
|
|
|
99
99
|
},
|
|
100
100
|
)
|
|
101
101
|
)
|
|
102
|
+
respx.post("https://graphql.testnet.sui.io/graphql").mock(
|
|
103
|
+
return_value=httpx.Response(
|
|
104
|
+
200,
|
|
105
|
+
json={"data": {"object": {"version": 1}}},
|
|
106
|
+
)
|
|
107
|
+
)
|
|
102
108
|
respx.post(_SUI_RPC_URL).mock(
|
|
103
109
|
return_value=httpx.Response(
|
|
104
110
|
200,
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|