@agentlayer.tech/wallet 0.1.12 → 0.1.13
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/.openclaw/extensions/agent-wallet/index.ts +454 -18
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +96 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +2 -0
- package/README.md +15 -1
- package/agent-wallet/.env.example +11 -0
- package/agent-wallet/README.md +29 -0
- package/agent-wallet/agent_wallet/approval.py +4 -0
- package/agent-wallet/agent_wallet/config.py +6 -0
- package/agent-wallet/agent_wallet/exceptions.py +2 -1
- package/agent-wallet/agent_wallet/openclaw_adapter.py +361 -2
- package/agent-wallet/agent_wallet/openclaw_cli.py +13 -1
- package/agent-wallet/agent_wallet/openclaw_runtime.py +2 -5
- package/agent-wallet/agent_wallet/providers/houdini.py +539 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +251 -0
- package/agent-wallet/agent_wallet/user_wallets.py +83 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +40 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +885 -16
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/install_agent_wallet.py +54 -2
- package/agent-wallet/scripts/install_openclaw_local_config.py +75 -4
- package/hermes/plugins/agent_wallet/tools.py +93 -9
- package/package.json +2 -2
|
@@ -44,6 +44,7 @@ EXCLUDED_RUNTIME_DIR_NAMES = {
|
|
|
44
44
|
}
|
|
45
45
|
EXCLUDED_RUNTIME_FILE_NAMES = {
|
|
46
46
|
".DS_Store",
|
|
47
|
+
".env",
|
|
47
48
|
}
|
|
48
49
|
EXCLUDED_RUNTIME_SUFFIXES = {
|
|
49
50
|
".pyc",
|
|
@@ -270,6 +271,39 @@ def _ensure_env_file(env_path: Path, env_example_path: Path) -> bool:
|
|
|
270
271
|
return True
|
|
271
272
|
|
|
272
273
|
|
|
274
|
+
def _upsert_env_value(env_path: Path, key: str, value: str) -> bool:
|
|
275
|
+
if not env_path.exists():
|
|
276
|
+
return False
|
|
277
|
+
lines = env_path.read_text(encoding="utf-8").splitlines()
|
|
278
|
+
updated = False
|
|
279
|
+
replaced = False
|
|
280
|
+
prefix = f"{key}="
|
|
281
|
+
new_line = f"{key}={value}"
|
|
282
|
+
for index, line in enumerate(lines):
|
|
283
|
+
if line.startswith(prefix):
|
|
284
|
+
replaced = True
|
|
285
|
+
if line != new_line:
|
|
286
|
+
lines[index] = new_line
|
|
287
|
+
updated = True
|
|
288
|
+
break
|
|
289
|
+
if not replaced:
|
|
290
|
+
if lines and lines[-1] != "":
|
|
291
|
+
lines.append("")
|
|
292
|
+
lines.append(new_line)
|
|
293
|
+
updated = True
|
|
294
|
+
if updated:
|
|
295
|
+
_atomic_write_text(env_path, "\n".join(lines) + "\n", mode=0o600)
|
|
296
|
+
_chmod_if_exists(env_path, 0o600)
|
|
297
|
+
return updated
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def _ensure_runtime_boot_key_file_env(env_path: Path) -> bool:
|
|
301
|
+
boot_key_file = _resolve_openclaw_home() / "agent-wallet-runtime" / "boot-key"
|
|
302
|
+
if not boot_key_file.exists():
|
|
303
|
+
return False
|
|
304
|
+
return _upsert_env_value(env_path, "AGENT_WALLET_BOOT_KEY_FILE", str(boot_key_file))
|
|
305
|
+
|
|
306
|
+
|
|
273
307
|
def _ensure_openclaw_config(config_path: Path) -> bool:
|
|
274
308
|
if config_path.exists():
|
|
275
309
|
return False
|
|
@@ -288,6 +322,22 @@ def _venv_python(venv_path: Path) -> Path:
|
|
|
288
322
|
return venv_path / "bin" / "python"
|
|
289
323
|
|
|
290
324
|
|
|
325
|
+
def _venv_python_wrapper(venv_path: Path) -> Path:
|
|
326
|
+
if os.name == "nt":
|
|
327
|
+
return _venv_python(venv_path)
|
|
328
|
+
return venv_path / "bin" / "openclaw-agent-wallet-python"
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _ensure_python_wrapper(venv_path: Path) -> Path:
|
|
332
|
+
if os.name == "nt":
|
|
333
|
+
return _venv_python(venv_path)
|
|
334
|
+
wrapper = _venv_python_wrapper(venv_path)
|
|
335
|
+
wrapper.parent.mkdir(parents=True, exist_ok=True)
|
|
336
|
+
wrapper.write_text('#!/bin/sh\nexec "$(dirname "$0")/python" "$@"\n', encoding="utf-8")
|
|
337
|
+
wrapper.chmod(0o755)
|
|
338
|
+
return wrapper
|
|
339
|
+
|
|
340
|
+
|
|
291
341
|
def _ensure_python_runtime(venv_path: Path, package_root: Path) -> tuple[Path, bool]:
|
|
292
342
|
created = False
|
|
293
343
|
python_bin = _venv_python(venv_path)
|
|
@@ -299,7 +349,7 @@ def _ensure_python_runtime(venv_path: Path, package_root: Path) -> tuple[Path, b
|
|
|
299
349
|
[str(python_bin), "-m", "pip", "install", "-e", str(package_root)],
|
|
300
350
|
check=True,
|
|
301
351
|
)
|
|
302
|
-
return
|
|
352
|
+
return _ensure_python_wrapper(venv_path), created
|
|
303
353
|
|
|
304
354
|
|
|
305
355
|
def _ensure_node_runtime(npm_bin: str, project_root: Path) -> dict[str, object]:
|
|
@@ -441,6 +491,7 @@ def main() -> None:
|
|
|
441
491
|
env_example_path = package_root / ".env.example"
|
|
442
492
|
|
|
443
493
|
env_created = _ensure_env_file(env_path, env_example_path)
|
|
494
|
+
boot_key_file_env_updated = _ensure_runtime_boot_key_file_env(env_path)
|
|
444
495
|
config_created = _ensure_openclaw_config(config_path)
|
|
445
496
|
|
|
446
497
|
python_bin = Path(sys.executable)
|
|
@@ -449,7 +500,7 @@ def main() -> None:
|
|
|
449
500
|
if not args.dry_run:
|
|
450
501
|
python_bin, venv_created = _ensure_python_runtime(venv_path, package_root)
|
|
451
502
|
else:
|
|
452
|
-
python_bin =
|
|
503
|
+
python_bin = _venv_python_wrapper(venv_path)
|
|
453
504
|
|
|
454
505
|
node_runtime = {
|
|
455
506
|
"skipped": bool(args.skip_node_setup),
|
|
@@ -500,6 +551,7 @@ def main() -> None:
|
|
|
500
551
|
"ok": True,
|
|
501
552
|
"env_path": str(env_path),
|
|
502
553
|
"env_created": env_created,
|
|
554
|
+
"boot_key_file_env_updated": boot_key_file_env_updated,
|
|
503
555
|
"config_path": str(config_path),
|
|
504
556
|
"config_created": config_created,
|
|
505
557
|
"package_root": str(package_root),
|
|
@@ -16,6 +16,25 @@ from agent_wallet.sealed_keys import resolve_sealed_keys_path, seal_keys, unseal
|
|
|
16
16
|
from security_utils import write_redacted_backup
|
|
17
17
|
|
|
18
18
|
OPTIONAL_TOOLS = [
|
|
19
|
+
"get_wallet_capabilities",
|
|
20
|
+
"get_wallet_address",
|
|
21
|
+
"get_wallet_balance",
|
|
22
|
+
"get_active_wallet_backend",
|
|
23
|
+
"set_wallet_backend",
|
|
24
|
+
"get_wallet_portfolio",
|
|
25
|
+
"get_solana_token_prices",
|
|
26
|
+
"swap_solana_privately",
|
|
27
|
+
"continue_solana_private_swap",
|
|
28
|
+
"list_pending_solana_private_swaps",
|
|
29
|
+
"get_solana_private_swap_status",
|
|
30
|
+
"get_kamino_lend_markets",
|
|
31
|
+
"get_kamino_lend_market_reserves",
|
|
32
|
+
"get_kamino_lend_user_obligations",
|
|
33
|
+
"get_kamino_lend_user_rewards",
|
|
34
|
+
"kamino_lend_deposit",
|
|
35
|
+
"kamino_lend_withdraw",
|
|
36
|
+
"kamino_lend_borrow",
|
|
37
|
+
"kamino_lend_repay",
|
|
19
38
|
"sign_wallet_message",
|
|
20
39
|
"transfer_sol",
|
|
21
40
|
"transfer_btc",
|
|
@@ -30,20 +49,60 @@ def _default_config_path() -> Path:
|
|
|
30
49
|
return Path(os.path.expanduser("~/.openclaw/openclaw.json"))
|
|
31
50
|
|
|
32
51
|
|
|
52
|
+
def _resolve_openclaw_home() -> Path:
|
|
53
|
+
return Path(os.path.expanduser(os.getenv("OPENCLAW_HOME", "~/.openclaw")))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _default_runtime_root() -> Path:
|
|
57
|
+
explicit_target = os.getenv("OPENCLAW_INSTALL_TARGET", "").strip()
|
|
58
|
+
if explicit_target:
|
|
59
|
+
return Path(explicit_target).expanduser()
|
|
60
|
+
explicit_root = os.getenv("OPENCLAW_INSTALL_ROOT", "").strip()
|
|
61
|
+
if explicit_root:
|
|
62
|
+
return Path(explicit_root).expanduser() / "current"
|
|
63
|
+
return _resolve_openclaw_home() / "agent-wallet-runtime" / "current"
|
|
64
|
+
|
|
65
|
+
|
|
33
66
|
def _repo_root() -> Path:
|
|
34
67
|
return Path(__file__).resolve().parents[2]
|
|
35
68
|
|
|
36
69
|
|
|
70
|
+
def _trusted_runtime_root() -> Path | None:
|
|
71
|
+
runtime_root = _default_runtime_root().resolve()
|
|
72
|
+
plugin_manifest = runtime_root / ".openclaw" / "extensions" / "agent-wallet" / "openclaw.plugin.json"
|
|
73
|
+
package_root = runtime_root / "agent-wallet"
|
|
74
|
+
if plugin_manifest.exists() and package_root.exists():
|
|
75
|
+
return runtime_root
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
37
79
|
def _default_extension_path() -> Path:
|
|
80
|
+
runtime_root = _trusted_runtime_root()
|
|
81
|
+
if runtime_root is not None:
|
|
82
|
+
return runtime_root / ".openclaw" / "extensions" / "agent-wallet"
|
|
38
83
|
return _repo_root() / ".openclaw" / "extensions" / "agent-wallet"
|
|
39
84
|
|
|
40
85
|
|
|
41
86
|
def _default_package_root() -> Path:
|
|
87
|
+
runtime_root = _trusted_runtime_root()
|
|
88
|
+
if runtime_root is not None:
|
|
89
|
+
return runtime_root / "agent-wallet"
|
|
42
90
|
return Path(__file__).resolve().parents[1]
|
|
43
91
|
|
|
44
92
|
|
|
45
93
|
def _default_python_bin() -> str:
|
|
46
|
-
|
|
94
|
+
explicit = os.getenv("OPENCLAW_AGENT_WALLET_PYTHON", "").strip()
|
|
95
|
+
if explicit:
|
|
96
|
+
return explicit
|
|
97
|
+
runtime_root = _trusted_runtime_root()
|
|
98
|
+
if runtime_root is not None:
|
|
99
|
+
wrapper = runtime_root / "agent-wallet" / ".runtime-venv" / "bin" / "openclaw-agent-wallet-python"
|
|
100
|
+
if wrapper.exists():
|
|
101
|
+
return str(wrapper)
|
|
102
|
+
runtime_python = runtime_root / "agent-wallet" / ".runtime-venv" / "bin" / "python"
|
|
103
|
+
if runtime_python.exists():
|
|
104
|
+
return str(runtime_python)
|
|
105
|
+
return sys.executable
|
|
47
106
|
|
|
48
107
|
|
|
49
108
|
def _default_user_id() -> str:
|
|
@@ -64,7 +123,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
64
123
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
65
124
|
parser.add_argument("--config-path", default=str(_default_config_path()))
|
|
66
125
|
parser.add_argument("--plugin-id", default="agent-wallet")
|
|
67
|
-
parser.add_argument("--user-id", default=
|
|
126
|
+
parser.add_argument("--user-id", default="")
|
|
68
127
|
parser.add_argument("--backend", default="solana_local")
|
|
69
128
|
parser.add_argument("--network", default="devnet")
|
|
70
129
|
parser.add_argument("--rpc-url", default="")
|
|
@@ -164,8 +223,20 @@ def main() -> None:
|
|
|
164
223
|
|
|
165
224
|
entries = plugins.setdefault("entries", {})
|
|
166
225
|
effective_network = _normalize_network(args.backend, args.network)
|
|
226
|
+
existing_entry = entries.get(args.plugin_id) if isinstance(entries.get(args.plugin_id), dict) else {}
|
|
227
|
+
existing_config = (
|
|
228
|
+
dict(existing_entry.get("config"))
|
|
229
|
+
if isinstance(existing_entry.get("config"), dict)
|
|
230
|
+
else {}
|
|
231
|
+
)
|
|
232
|
+
resolved_user_id = (
|
|
233
|
+
args.user_id.strip()
|
|
234
|
+
or str(existing_config.get("userId") or "").strip()
|
|
235
|
+
or _default_user_id()
|
|
236
|
+
)
|
|
167
237
|
plugin_config = {
|
|
168
|
-
|
|
238
|
+
**existing_config,
|
|
239
|
+
"userId": resolved_user_id,
|
|
169
240
|
"backend": args.backend,
|
|
170
241
|
"network": effective_network,
|
|
171
242
|
"signOnly": args.sign_only,
|
|
@@ -223,7 +294,7 @@ def main() -> None:
|
|
|
223
294
|
"python_bin": args.python_bin,
|
|
224
295
|
"package_root": plugin_config["packageRoot"],
|
|
225
296
|
"plugin_id": args.plugin_id,
|
|
226
|
-
"user_id":
|
|
297
|
+
"user_id": resolved_user_id,
|
|
227
298
|
"sealed_keys_path": sealed_keys_path,
|
|
228
299
|
},
|
|
229
300
|
indent=2,
|
|
@@ -15,6 +15,7 @@ from typing import Any
|
|
|
15
15
|
|
|
16
16
|
SECRET_CONFIG_KEYS = {"privateKey", "masterKey", "approvalSecret"}
|
|
17
17
|
BACKENDS = ("solana_local", "wdk_btc_local", "wdk_evm_local")
|
|
18
|
+
PREVIEW_BOUND_SWAP_TOOLS = {"swap_solana_tokens", "swap_solana_privately"}
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def _json(data: dict[str, Any]) -> str:
|
|
@@ -75,12 +76,12 @@ def _prune_preview_cache(cache: dict[str, Any]) -> dict[str, Any]:
|
|
|
75
76
|
|
|
76
77
|
|
|
77
78
|
def _cache_swap_preview(tool_name: str, result: dict[str, Any], ttl_seconds: int = 900) -> None:
|
|
78
|
-
if tool_name
|
|
79
|
+
if tool_name not in PREVIEW_BOUND_SWAP_TOOLS or result.get("ok") is not True:
|
|
79
80
|
return
|
|
80
81
|
preview = result.get("data")
|
|
81
82
|
if not isinstance(preview, dict):
|
|
82
83
|
return
|
|
83
|
-
if preview.get("mode") != "preview" or preview.get("asset_type")
|
|
84
|
+
if preview.get("mode") != "preview" or preview.get("asset_type") not in {"swap", "solana-private-swap"}:
|
|
84
85
|
return
|
|
85
86
|
summary = preview.get("confirmation_summary")
|
|
86
87
|
if not isinstance(summary, dict):
|
|
@@ -192,6 +193,85 @@ def _user_id(args: dict[str, Any]) -> str:
|
|
|
192
193
|
return str(value).strip() or "hermes-local-user"
|
|
193
194
|
|
|
194
195
|
|
|
196
|
+
def _normalize_backend(value: Any) -> str:
|
|
197
|
+
normalized = str(value or "").strip().lower()
|
|
198
|
+
aliases = {
|
|
199
|
+
"sol": "solana_local",
|
|
200
|
+
"solana": "solana_local",
|
|
201
|
+
"solana_local": "solana_local",
|
|
202
|
+
"solana-local": "solana_local",
|
|
203
|
+
"evm": "wdk_evm_local",
|
|
204
|
+
"ethereum": "wdk_evm_local",
|
|
205
|
+
"eth": "wdk_evm_local",
|
|
206
|
+
"base": "wdk_evm_local",
|
|
207
|
+
"wdk_evm_local": "wdk_evm_local",
|
|
208
|
+
"wdk-evm-local": "wdk_evm_local",
|
|
209
|
+
"btc": "wdk_btc_local",
|
|
210
|
+
"bitcoin": "wdk_btc_local",
|
|
211
|
+
"wdk_btc_local": "wdk_btc_local",
|
|
212
|
+
"wdk-btc-local": "wdk_btc_local",
|
|
213
|
+
}
|
|
214
|
+
backend = aliases.get(normalized, normalized)
|
|
215
|
+
if backend not in BACKENDS:
|
|
216
|
+
raise RuntimeError(
|
|
217
|
+
"Wallet backend must be one of solana_local, wdk_btc_local, or wdk_evm_local."
|
|
218
|
+
)
|
|
219
|
+
return backend
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _infer_backend_for_tool(tool_name: str) -> str | None:
|
|
223
|
+
if (
|
|
224
|
+
tool_name.startswith("get_evm_")
|
|
225
|
+
or tool_name.startswith("manage_evm_")
|
|
226
|
+
or tool_name.startswith("swap_evm_")
|
|
227
|
+
or tool_name.startswith("transfer_evm_")
|
|
228
|
+
or tool_name == "agent_wallet_evm_status"
|
|
229
|
+
or tool_name == "agent_wallet_evm_setup"
|
|
230
|
+
):
|
|
231
|
+
return "wdk_evm_local"
|
|
232
|
+
if tool_name.startswith("get_btc_") or tool_name == "transfer_btc":
|
|
233
|
+
return "wdk_btc_local"
|
|
234
|
+
if (
|
|
235
|
+
"solana" in tool_name
|
|
236
|
+
or "jupiter" in tool_name
|
|
237
|
+
or "kamino" in tool_name
|
|
238
|
+
or "bags" in tool_name
|
|
239
|
+
or tool_name in {"transfer_sol", "transfer_spl_token", "sign_wallet_message", "close_empty_token_accounts", "request_devnet_airdrop", "get_wallet_portfolio", "get_solana_token_prices"}
|
|
240
|
+
):
|
|
241
|
+
return "solana_local"
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _normalize_network_for_backend(backend: str, raw_network: Any) -> str:
|
|
246
|
+
network = str(raw_network or "").strip().lower()
|
|
247
|
+
if backend == "wdk_evm_local":
|
|
248
|
+
aliases = {
|
|
249
|
+
"mainnet": "ethereum",
|
|
250
|
+
"eth": "ethereum",
|
|
251
|
+
"eth-mainnet": "ethereum",
|
|
252
|
+
"base-mainnet": "base",
|
|
253
|
+
}
|
|
254
|
+
normalized = aliases.get(network, network)
|
|
255
|
+
return normalized if normalized in {"ethereum", "base"} else "ethereum"
|
|
256
|
+
if backend == "wdk_btc_local":
|
|
257
|
+
aliases = {
|
|
258
|
+
"btc": "bitcoin",
|
|
259
|
+
"bitcoin_mainnet": "bitcoin",
|
|
260
|
+
"bitcoin-mainnet": "bitcoin",
|
|
261
|
+
"mainnet": "bitcoin",
|
|
262
|
+
}
|
|
263
|
+
normalized = aliases.get(network, network)
|
|
264
|
+
return normalized if normalized in {"bitcoin", "testnet", "regtest"} else "bitcoin"
|
|
265
|
+
aliases = {
|
|
266
|
+
"solana": "mainnet",
|
|
267
|
+
"solana-mainnet": "mainnet",
|
|
268
|
+
"mainnet_beta": "mainnet",
|
|
269
|
+
"mainnet-beta": "mainnet",
|
|
270
|
+
}
|
|
271
|
+
normalized = aliases.get(network, network)
|
|
272
|
+
return normalized if normalized in {"mainnet", "devnet", "testnet"} else "mainnet"
|
|
273
|
+
|
|
274
|
+
|
|
195
275
|
def _reject_secret_config(config: dict[str, Any]) -> None:
|
|
196
276
|
present = sorted(key for key in SECRET_CONFIG_KEYS if str(config.get(key) or "").strip())
|
|
197
277
|
if present:
|
|
@@ -202,16 +282,20 @@ def _reject_secret_config(config: dict[str, Any]) -> None:
|
|
|
202
282
|
)
|
|
203
283
|
|
|
204
284
|
|
|
205
|
-
def _base_config(args: dict[str, Any]) -> dict[str, Any]:
|
|
285
|
+
def _base_config(args: dict[str, Any], *, tool_name: str | None = None) -> dict[str, Any]:
|
|
206
286
|
raw = args.get("config") or {}
|
|
207
287
|
if not isinstance(raw, dict):
|
|
208
288
|
raise RuntimeError("config must be a JSON object when provided.")
|
|
209
289
|
config = dict(raw)
|
|
210
290
|
backend = args.get("backend") or os.getenv("AGENT_WALLET_BACKEND")
|
|
211
|
-
|
|
291
|
+
if not backend and tool_name:
|
|
292
|
+
backend = _infer_backend_for_tool(tool_name)
|
|
212
293
|
if backend:
|
|
213
|
-
config["backend"] =
|
|
214
|
-
|
|
294
|
+
config["backend"] = _normalize_backend(backend)
|
|
295
|
+
network = args.get("network") or os.getenv("AGENT_WALLET_NETWORK") or config.get("network")
|
|
296
|
+
if backend:
|
|
297
|
+
config["network"] = _normalize_network_for_backend(config["backend"], network)
|
|
298
|
+
elif network:
|
|
215
299
|
config["network"] = str(network).strip()
|
|
216
300
|
_reject_secret_config(config)
|
|
217
301
|
return config
|
|
@@ -235,15 +319,15 @@ def _cli_env(package_root: Path) -> dict[str, str]:
|
|
|
235
319
|
|
|
236
320
|
def _call_wallet_cli(args: dict[str, Any]) -> dict[str, Any]:
|
|
237
321
|
package_root = _resolve_package_root()
|
|
238
|
-
config = _base_config(args)
|
|
239
322
|
tool_name = str(args.get("tool_name") or "").strip()
|
|
240
323
|
if not tool_name:
|
|
241
324
|
raise RuntimeError("tool_name is required.")
|
|
325
|
+
config = _base_config(args, tool_name=tool_name)
|
|
242
326
|
|
|
243
327
|
tool_args = args.get("arguments") or {}
|
|
244
328
|
if not isinstance(tool_args, dict):
|
|
245
329
|
raise RuntimeError("arguments must be a JSON object when provided.")
|
|
246
|
-
if tool_name
|
|
330
|
+
if tool_name in PREVIEW_BOUND_SWAP_TOOLS and str(tool_args.get("mode") or "") == "execute":
|
|
247
331
|
approval_token = str(tool_args.get("approval_token") or "").strip()
|
|
248
332
|
cached_preview = _lookup_preview_for_token(approval_token)
|
|
249
333
|
if cached_preview is not None and "_approved_preview" not in tool_args:
|
|
@@ -321,10 +405,10 @@ def _call_issue_approval(args: dict[str, Any]) -> dict[str, Any]:
|
|
|
321
405
|
"user_confirmed=true is required after explicit user approval of the exact confirmation_summary."
|
|
322
406
|
)
|
|
323
407
|
package_root = _resolve_package_root()
|
|
324
|
-
config = _base_config(args)
|
|
325
408
|
tool_name = str(args.get("tool_name") or "").strip()
|
|
326
409
|
if not tool_name:
|
|
327
410
|
raise RuntimeError("tool_name is required.")
|
|
411
|
+
config = _base_config(args, tool_name=tool_name)
|
|
328
412
|
|
|
329
413
|
summary = args.get("confirmation_summary")
|
|
330
414
|
if not isinstance(summary, dict) or not summary:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentlayer.tech/wallet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "NPM installer for the OpenClaw Agent Wallet local runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -69,4 +69,4 @@
|
|
|
69
69
|
"evm"
|
|
70
70
|
],
|
|
71
71
|
"license": "SEE LICENSE IN LICENSE"
|
|
72
|
-
}
|
|
72
|
+
}
|