@agentlayer.tech/wallet 0.1.10 → 0.1.11
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.
- package/CHANGELOG.md +5 -0
- package/README.md +23 -8
- package/agent-wallet/README.md +18 -0
- package/agent-wallet/agent_wallet/config.py +11 -1
- package/agent-wallet/agent_wallet/openclaw_adapter.py +74 -9
- package/agent-wallet/agent_wallet/providers/jupiter.py +171 -2
- package/agent-wallet/pyproject.toml +2 -1
- package/agent-wallet/scripts/install_agent_wallet.py +1 -0
- package/bin/openclaw-agent-wallet.mjs +229 -5
- package/hermes/plugins/agent_wallet/README.md +54 -0
- package/hermes/plugins/agent_wallet/__init__.py +29 -0
- package/hermes/plugins/agent_wallet/plugin.yaml +7 -0
- package/hermes/plugins/agent_wallet/schemas.py +134 -0
- package/hermes/plugins/agent_wallet/tools.py +433 -0
- package/package.json +4 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""Hermes Agent handlers that forward to the existing wallet CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import base64
|
|
8
|
+
import hashlib
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
import time
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
SECRET_CONFIG_KEYS = {"privateKey", "masterKey", "approvalSecret"}
|
|
17
|
+
BACKENDS = ("solana_local", "wdk_btc_local", "wdk_evm_local")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _json(data: dict[str, Any]) -> str:
|
|
21
|
+
return json.dumps(data, sort_keys=True)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _canonical_json_text(payload: dict[str, Any]) -> str:
|
|
25
|
+
return json.dumps(payload, sort_keys=True, separators=(",", ":"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _preview_digest(preview: dict[str, Any]) -> str:
|
|
29
|
+
return hashlib.sha256(_canonical_json_text(preview).encode("utf-8")).hexdigest()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _hermes_home() -> Path:
|
|
33
|
+
return Path(os.getenv("HERMES_HOME", "~/.hermes")).expanduser()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _preview_cache_path() -> Path:
|
|
37
|
+
return _hermes_home() / "agent_wallet_preview_cache.json"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _read_preview_cache() -> dict[str, Any]:
|
|
41
|
+
path = _preview_cache_path()
|
|
42
|
+
try:
|
|
43
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
44
|
+
except (OSError, json.JSONDecodeError):
|
|
45
|
+
return {"previews": {}}
|
|
46
|
+
if not isinstance(payload, dict):
|
|
47
|
+
return {"previews": {}}
|
|
48
|
+
previews = payload.get("previews")
|
|
49
|
+
if not isinstance(previews, dict):
|
|
50
|
+
payload["previews"] = {}
|
|
51
|
+
return payload
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _write_preview_cache(cache: dict[str, Any]) -> None:
|
|
55
|
+
path = _preview_cache_path()
|
|
56
|
+
try:
|
|
57
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
path.write_text(json.dumps(cache, sort_keys=True), encoding="utf-8")
|
|
59
|
+
path.chmod(0o600)
|
|
60
|
+
except OSError:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _prune_preview_cache(cache: dict[str, Any]) -> dict[str, Any]:
|
|
65
|
+
now = time.time()
|
|
66
|
+
previews = cache.get("previews")
|
|
67
|
+
if not isinstance(previews, dict):
|
|
68
|
+
previews = {}
|
|
69
|
+
cache["previews"] = {
|
|
70
|
+
key: value
|
|
71
|
+
for key, value in previews.items()
|
|
72
|
+
if isinstance(value, dict) and float(value.get("expires_at") or 0) > now
|
|
73
|
+
}
|
|
74
|
+
return cache
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _cache_swap_preview(tool_name: str, result: dict[str, Any], ttl_seconds: int = 900) -> None:
|
|
78
|
+
if tool_name != "swap_solana_tokens" or result.get("ok") is not True:
|
|
79
|
+
return
|
|
80
|
+
preview = result.get("data")
|
|
81
|
+
if not isinstance(preview, dict):
|
|
82
|
+
return
|
|
83
|
+
if preview.get("mode") != "preview" or preview.get("asset_type") != "swap":
|
|
84
|
+
return
|
|
85
|
+
summary = preview.get("confirmation_summary")
|
|
86
|
+
if not isinstance(summary, dict):
|
|
87
|
+
return
|
|
88
|
+
digest = _preview_digest(preview)
|
|
89
|
+
cache = _prune_preview_cache(_read_preview_cache())
|
|
90
|
+
cache["previews"][digest] = {
|
|
91
|
+
"expires_at": time.time() + ttl_seconds,
|
|
92
|
+
"preview": preview,
|
|
93
|
+
"confirmation_summary": summary,
|
|
94
|
+
}
|
|
95
|
+
_write_preview_cache(cache)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _lookup_preview_for_summary(summary: dict[str, Any]) -> tuple[str, dict[str, Any]] | tuple[None, None]:
|
|
99
|
+
cache = _prune_preview_cache(_read_preview_cache())
|
|
100
|
+
for digest, entry in cache.get("previews", {}).items():
|
|
101
|
+
if not isinstance(entry, dict):
|
|
102
|
+
continue
|
|
103
|
+
if entry.get("confirmation_summary") == summary and isinstance(entry.get("preview"), dict):
|
|
104
|
+
_write_preview_cache(cache)
|
|
105
|
+
return str(digest), entry["preview"]
|
|
106
|
+
_write_preview_cache(cache)
|
|
107
|
+
return None, None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _approval_token_preview_digest(token: str) -> str:
|
|
111
|
+
if not isinstance(token, str) or "." not in token:
|
|
112
|
+
return ""
|
|
113
|
+
encoded_payload = token.split(".", 1)[0]
|
|
114
|
+
try:
|
|
115
|
+
padding = "=" * (-len(encoded_payload) % 4)
|
|
116
|
+
payload = json.loads(base64.urlsafe_b64decode(encoded_payload + padding).decode("utf-8"))
|
|
117
|
+
except Exception:
|
|
118
|
+
return ""
|
|
119
|
+
summary = payload.get("binding", {}).get("summary") if isinstance(payload, dict) else None
|
|
120
|
+
if not isinstance(summary, dict):
|
|
121
|
+
return ""
|
|
122
|
+
digest = summary.get("_preview_digest")
|
|
123
|
+
return str(digest).strip() if isinstance(digest, str) else ""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _lookup_preview_for_token(token: str) -> dict[str, Any] | None:
|
|
127
|
+
digest = _approval_token_preview_digest(token)
|
|
128
|
+
if not digest:
|
|
129
|
+
return None
|
|
130
|
+
cache = _prune_preview_cache(_read_preview_cache())
|
|
131
|
+
entry = cache.get("previews", {}).get(digest)
|
|
132
|
+
_write_preview_cache(cache)
|
|
133
|
+
if isinstance(entry, dict) and isinstance(entry.get("preview"), dict):
|
|
134
|
+
return entry["preview"]
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _repo_relative_package_root() -> Path:
|
|
139
|
+
return Path(__file__).resolve().parents[3] / "agent-wallet"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _resolve_package_root() -> Path:
|
|
143
|
+
candidates = [
|
|
144
|
+
os.getenv("AGENT_WALLET_PACKAGE_ROOT"),
|
|
145
|
+
os.getenv("OPENCLAW_AGENT_WALLET_PACKAGE_ROOT"),
|
|
146
|
+
str(_repo_relative_package_root()),
|
|
147
|
+
str(Path.cwd() / "agent-wallet"),
|
|
148
|
+
]
|
|
149
|
+
for candidate in candidates:
|
|
150
|
+
if not candidate:
|
|
151
|
+
continue
|
|
152
|
+
root = Path(candidate).expanduser().resolve()
|
|
153
|
+
if (root / "agent_wallet" / "__init__.py").exists():
|
|
154
|
+
return root
|
|
155
|
+
raise RuntimeError(
|
|
156
|
+
"Could not resolve agent-wallet package root. Set AGENT_WALLET_PACKAGE_ROOT."
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _python_bin(package_root: Path) -> str:
|
|
161
|
+
for candidate in (
|
|
162
|
+
os.getenv("AGENT_WALLET_PYTHON"),
|
|
163
|
+
os.getenv("OPENCLAW_AGENT_WALLET_PYTHON"),
|
|
164
|
+
str(package_root / ".venv" / "bin" / "python"),
|
|
165
|
+
str(package_root / ".runtime-venv" / "bin" / "python"),
|
|
166
|
+
"python3",
|
|
167
|
+
):
|
|
168
|
+
if not candidate:
|
|
169
|
+
continue
|
|
170
|
+
resolved = Path(candidate).expanduser()
|
|
171
|
+
if resolved.is_absolute() and not resolved.exists():
|
|
172
|
+
continue
|
|
173
|
+
return str(resolved)
|
|
174
|
+
return "python3"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _user_id(args: dict[str, Any]) -> str:
|
|
178
|
+
value = (
|
|
179
|
+
args.get("user_id")
|
|
180
|
+
or os.getenv("AGENT_WALLET_USER_ID")
|
|
181
|
+
or os.getenv("OPENCLAW_AGENT_WALLET_USER_ID")
|
|
182
|
+
or os.getenv("USER")
|
|
183
|
+
or "hermes-local-user"
|
|
184
|
+
)
|
|
185
|
+
return str(value).strip() or "hermes-local-user"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _reject_secret_config(config: dict[str, Any]) -> None:
|
|
189
|
+
present = sorted(key for key in SECRET_CONFIG_KEYS if str(config.get(key) or "").strip())
|
|
190
|
+
if present:
|
|
191
|
+
raise RuntimeError(
|
|
192
|
+
"Sensitive keys are not allowed in Hermes wallet bridge config: "
|
|
193
|
+
+ ", ".join(present)
|
|
194
|
+
+ ". Use sealed_keys.json and protected environment injection."
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _base_config(args: dict[str, Any]) -> dict[str, Any]:
|
|
199
|
+
raw = args.get("config") or {}
|
|
200
|
+
if not isinstance(raw, dict):
|
|
201
|
+
raise RuntimeError("config must be a JSON object when provided.")
|
|
202
|
+
config = dict(raw)
|
|
203
|
+
backend = args.get("backend") or os.getenv("AGENT_WALLET_BACKEND")
|
|
204
|
+
network = args.get("network") or os.getenv("AGENT_WALLET_NETWORK")
|
|
205
|
+
if backend:
|
|
206
|
+
config["backend"] = str(backend).strip()
|
|
207
|
+
if network:
|
|
208
|
+
config["network"] = str(network).strip()
|
|
209
|
+
_reject_secret_config(config)
|
|
210
|
+
return config
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _cli_env(package_root: Path) -> dict[str, str]:
|
|
214
|
+
env = dict(os.environ)
|
|
215
|
+
prior = env.get("PYTHONPATH", "")
|
|
216
|
+
env["PYTHONPATH"] = str(package_root) if not prior else f"{package_root}{os.pathsep}{prior}"
|
|
217
|
+
if not env.get("AGENT_WALLET_BOOT_KEY"):
|
|
218
|
+
key_file = env.get("AGENT_WALLET_BOOT_KEY_FILE", "").strip()
|
|
219
|
+
if key_file:
|
|
220
|
+
try:
|
|
221
|
+
boot_key = Path(key_file).expanduser().read_text(encoding="utf-8").strip()
|
|
222
|
+
except OSError:
|
|
223
|
+
boot_key = ""
|
|
224
|
+
if boot_key:
|
|
225
|
+
env["AGENT_WALLET_BOOT_KEY"] = boot_key
|
|
226
|
+
return env
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _call_wallet_cli(args: dict[str, Any]) -> dict[str, Any]:
|
|
230
|
+
package_root = _resolve_package_root()
|
|
231
|
+
config = _base_config(args)
|
|
232
|
+
tool_name = str(args.get("tool_name") or "").strip()
|
|
233
|
+
if not tool_name:
|
|
234
|
+
raise RuntimeError("tool_name is required.")
|
|
235
|
+
|
|
236
|
+
tool_args = args.get("arguments") or {}
|
|
237
|
+
if not isinstance(tool_args, dict):
|
|
238
|
+
raise RuntimeError("arguments must be a JSON object when provided.")
|
|
239
|
+
if tool_name == "swap_solana_tokens" and str(tool_args.get("mode") or "") == "execute":
|
|
240
|
+
approval_token = str(tool_args.get("approval_token") or "").strip()
|
|
241
|
+
cached_preview = _lookup_preview_for_token(approval_token)
|
|
242
|
+
if cached_preview is not None and "_approved_preview" not in tool_args:
|
|
243
|
+
tool_args = dict(tool_args)
|
|
244
|
+
tool_args["_approved_preview"] = cached_preview
|
|
245
|
+
|
|
246
|
+
command = [
|
|
247
|
+
_python_bin(package_root),
|
|
248
|
+
"-m",
|
|
249
|
+
"agent_wallet.openclaw_cli",
|
|
250
|
+
"invoke",
|
|
251
|
+
"--user-id",
|
|
252
|
+
_user_id(args),
|
|
253
|
+
"--tool",
|
|
254
|
+
tool_name,
|
|
255
|
+
"--arguments-json",
|
|
256
|
+
json.dumps(tool_args),
|
|
257
|
+
"--config-json",
|
|
258
|
+
json.dumps(config),
|
|
259
|
+
]
|
|
260
|
+
completed = subprocess.run(
|
|
261
|
+
command,
|
|
262
|
+
cwd=str(package_root),
|
|
263
|
+
env=_cli_env(package_root),
|
|
264
|
+
text=True,
|
|
265
|
+
capture_output=True,
|
|
266
|
+
timeout=float(os.getenv("AGENT_WALLET_HERMES_TIMEOUT", "120")),
|
|
267
|
+
check=False,
|
|
268
|
+
)
|
|
269
|
+
if completed.returncode != 0:
|
|
270
|
+
detail = completed.stderr.strip() or completed.stdout.strip()
|
|
271
|
+
return {"ok": False, "error": detail or f"wallet CLI exited {completed.returncode}"}
|
|
272
|
+
try:
|
|
273
|
+
result = json.loads(completed.stdout.strip() or "{}")
|
|
274
|
+
_cache_swap_preview(tool_name, result)
|
|
275
|
+
return result
|
|
276
|
+
except json.JSONDecodeError as exc:
|
|
277
|
+
return {"ok": False, "error": f"wallet CLI returned invalid JSON: {exc}"}
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _call_issue_approval(args: dict[str, Any]) -> dict[str, Any]:
|
|
281
|
+
if args.get("user_confirmed") is not True:
|
|
282
|
+
raise RuntimeError(
|
|
283
|
+
"user_confirmed=true is required after explicit user approval of the exact confirmation_summary."
|
|
284
|
+
)
|
|
285
|
+
package_root = _resolve_package_root()
|
|
286
|
+
config = _base_config(args)
|
|
287
|
+
tool_name = str(args.get("tool_name") or "").strip()
|
|
288
|
+
if not tool_name:
|
|
289
|
+
raise RuntimeError("tool_name is required.")
|
|
290
|
+
|
|
291
|
+
summary = args.get("confirmation_summary")
|
|
292
|
+
if not isinstance(summary, dict) or not summary:
|
|
293
|
+
raise RuntimeError("confirmation_summary must be the non-empty object returned by preview/prepare.")
|
|
294
|
+
summary_for_token = dict(summary)
|
|
295
|
+
preview_digest, _preview = _lookup_preview_for_summary(summary)
|
|
296
|
+
if preview_digest:
|
|
297
|
+
summary_for_token["_preview_digest"] = preview_digest
|
|
298
|
+
|
|
299
|
+
command = [
|
|
300
|
+
_python_bin(package_root),
|
|
301
|
+
"-m",
|
|
302
|
+
"agent_wallet.openclaw_cli",
|
|
303
|
+
"issue-approval",
|
|
304
|
+
"--user-id",
|
|
305
|
+
_user_id(args),
|
|
306
|
+
"--tool",
|
|
307
|
+
tool_name,
|
|
308
|
+
"--summary-json",
|
|
309
|
+
json.dumps(summary_for_token),
|
|
310
|
+
"--config-json",
|
|
311
|
+
json.dumps(config),
|
|
312
|
+
]
|
|
313
|
+
if args.get("mainnet_confirmed") is True:
|
|
314
|
+
command.append("--mainnet-confirmed")
|
|
315
|
+
ttl_seconds = args.get("ttl_seconds")
|
|
316
|
+
if ttl_seconds is not None:
|
|
317
|
+
ttl = int(ttl_seconds)
|
|
318
|
+
if ttl <= 0 or ttl > 3600:
|
|
319
|
+
raise RuntimeError("ttl_seconds must be between 1 and 3600.")
|
|
320
|
+
command.extend(["--ttl-seconds", str(ttl)])
|
|
321
|
+
|
|
322
|
+
completed = subprocess.run(
|
|
323
|
+
command,
|
|
324
|
+
cwd=str(package_root),
|
|
325
|
+
env=_cli_env(package_root),
|
|
326
|
+
text=True,
|
|
327
|
+
capture_output=True,
|
|
328
|
+
timeout=float(os.getenv("AGENT_WALLET_HERMES_TIMEOUT", "120")),
|
|
329
|
+
check=False,
|
|
330
|
+
)
|
|
331
|
+
if completed.returncode != 0:
|
|
332
|
+
detail = completed.stderr.strip() or completed.stdout.strip()
|
|
333
|
+
return {"ok": False, "error": detail or f"wallet CLI exited {completed.returncode}"}
|
|
334
|
+
try:
|
|
335
|
+
return json.loads(completed.stdout.strip() or "{}")
|
|
336
|
+
except json.JSONDecodeError as exc:
|
|
337
|
+
return {"ok": False, "error": f"wallet CLI returned invalid JSON: {exc}"}
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class _SchemaOnlyBackend:
|
|
341
|
+
def __init__(self, *, name: str, chain: str, network: str):
|
|
342
|
+
self.name = name
|
|
343
|
+
self.chain = chain
|
|
344
|
+
self.network = network
|
|
345
|
+
self.sign_only = True
|
|
346
|
+
|
|
347
|
+
def get_capabilities(self):
|
|
348
|
+
from agent_wallet.wallet_layer.base import WalletCapabilities
|
|
349
|
+
|
|
350
|
+
return WalletCapabilities(
|
|
351
|
+
backend=self.name,
|
|
352
|
+
chain=self.chain,
|
|
353
|
+
custody_model="local",
|
|
354
|
+
sign_only=True,
|
|
355
|
+
has_signer=False,
|
|
356
|
+
can_get_address=True,
|
|
357
|
+
can_get_balance=True,
|
|
358
|
+
external_dependencies=[],
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
async def get_address(self):
|
|
362
|
+
return None
|
|
363
|
+
|
|
364
|
+
async def get_balance(self, address=None):
|
|
365
|
+
return {}
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def _schema_backend(name: str) -> _SchemaOnlyBackend:
|
|
369
|
+
if name == "wdk_btc_local":
|
|
370
|
+
return _SchemaOnlyBackend(name=name, chain="bitcoin", network="bitcoin")
|
|
371
|
+
if name == "wdk_evm_local":
|
|
372
|
+
return _SchemaOnlyBackend(name=name, chain="evm", network="ethereum")
|
|
373
|
+
return _SchemaOnlyBackend(name="solana_local", chain="solana", network="mainnet")
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _tool_specs(backend_name: str) -> list[dict[str, Any]]:
|
|
377
|
+
package_root = _resolve_package_root()
|
|
378
|
+
package_root_text = str(package_root)
|
|
379
|
+
inserted = package_root_text not in sys.path
|
|
380
|
+
if inserted:
|
|
381
|
+
sys.path.insert(0, package_root_text)
|
|
382
|
+
try:
|
|
383
|
+
from agent_wallet.openclaw_adapter import OpenClawWalletAdapter
|
|
384
|
+
|
|
385
|
+
adapter = OpenClawWalletAdapter(_schema_backend(backend_name))
|
|
386
|
+
return [tool.model_dump() for tool in adapter.list_tools()]
|
|
387
|
+
finally:
|
|
388
|
+
if inserted:
|
|
389
|
+
try:
|
|
390
|
+
sys.path.remove(package_root_text)
|
|
391
|
+
except ValueError:
|
|
392
|
+
pass
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def agent_wallet_tools(args: dict, **kwargs) -> str:
|
|
396
|
+
try:
|
|
397
|
+
requested = str((args or {}).get("backend") or "all").strip() or "all"
|
|
398
|
+
backend_names = BACKENDS if requested == "all" else (requested,)
|
|
399
|
+
invalid = [name for name in backend_names if name not in BACKENDS]
|
|
400
|
+
if invalid:
|
|
401
|
+
return _json({"ok": False, "error": f"Unknown backend: {', '.join(invalid)}"})
|
|
402
|
+
tools = {
|
|
403
|
+
backend_name: _tool_specs(backend_name)
|
|
404
|
+
for backend_name in backend_names
|
|
405
|
+
}
|
|
406
|
+
return _json(
|
|
407
|
+
{
|
|
408
|
+
"ok": True,
|
|
409
|
+
"bridge": "hermes-agent-wallet",
|
|
410
|
+
"backends": list(backend_names),
|
|
411
|
+
"tools": tools,
|
|
412
|
+
"usage": (
|
|
413
|
+
"Call agent_wallet_invoke with one of these tool names and JSON arguments. "
|
|
414
|
+
"Use preview before execute. Execute requires a host-issued approval_token."
|
|
415
|
+
),
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
except Exception as exc:
|
|
419
|
+
return _json({"ok": False, "error": str(exc)})
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def agent_wallet_invoke(args: dict, **kwargs) -> str:
|
|
423
|
+
try:
|
|
424
|
+
return _json(_call_wallet_cli(args or {}))
|
|
425
|
+
except Exception as exc:
|
|
426
|
+
return _json({"ok": False, "error": str(exc)})
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
def agent_wallet_approve(args: dict, **kwargs) -> str:
|
|
430
|
+
try:
|
|
431
|
+
return _json(_call_issue_approval(args or {}))
|
|
432
|
+
except Exception as exc:
|
|
433
|
+
return _json({"ok": False, "error": str(exc)})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentlayer.tech/wallet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "NPM installer for the OpenClaw Agent Wallet local runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"agent-wallet/pyproject.toml",
|
|
39
39
|
".openclaw/AGENTS.md",
|
|
40
40
|
".openclaw/extensions/agent-wallet/",
|
|
41
|
+
"hermes/plugins/agent_wallet/",
|
|
41
42
|
"wdk-btc-wallet/src/",
|
|
42
43
|
"wdk-btc-wallet/bootstrap.sh",
|
|
43
44
|
"wdk-btc-wallet/run-local.sh",
|
|
@@ -52,6 +53,8 @@
|
|
|
52
53
|
"wdk-evm-wallet/package-lock.json",
|
|
53
54
|
"!agent-wallet/**/__pycache__/**",
|
|
54
55
|
"!agent-wallet/**/*.pyc",
|
|
56
|
+
"!hermes/**/__pycache__/**",
|
|
57
|
+
"!hermes/**/*.pyc",
|
|
55
58
|
"!agent-wallet/.pytest_cache/**",
|
|
56
59
|
"!agent-wallet/.runtime-venv/**",
|
|
57
60
|
"!**/node_modules/**",
|