@agentlayer.tech/wallet 0.1.101 → 0.1.103
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/.claude-plugin/marketplace.json +4 -1
- package/.openclaw/extensions/agent-wallet/dist/index.js +46 -1
- package/.openclaw/extensions/agent-wallet/index.ts +46 -1
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +1 -1
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/README.md +18 -0
- package/VERSION +1 -1
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/connector_cli.py +198 -0
- package/agent-wallet/agent_wallet/connectors/__init__.py +28 -0
- package/agent-wallet/agent_wallet/connectors/catalog.py +68 -0
- package/agent-wallet/agent_wallet/connectors/client.py +308 -0
- package/agent-wallet/agent_wallet/connectors/intent_policy.py +243 -0
- package/agent-wallet/agent_wallet/connectors/manifest.py +192 -0
- package/agent-wallet/agent_wallet/connectors/registry.py +341 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +56 -5
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +4 -2
- package/agent-wallet/scripts/build_release_bundle.py +1 -0
- package/agent-wallet/scripts/install_agent_wallet.py +1 -1
- package/bin/openclaw-agent-wallet.mjs +38 -0
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +2 -2
- package/claude-code/plugins/agent-wallet/commands/wallet-evm.md +1 -0
- package/claude-code/plugins/agent-wallet/commands/wallet-setup.md +1 -0
- package/claude-code/plugins/agent-wallet/skills/wallet-operator/SKILL.md +1 -0
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/server.py +4 -1
- package/connectors/AGENTS.md +37 -0
- package/connectors/DEVELOPER_GUIDE.md +131 -0
- package/connectors/README.md +139 -0
- package/connectors/READ_ONLY_BETA.md +54 -0
- package/connectors/RELEASING.md +48 -0
- package/connectors/conformance/README.md +31 -0
- package/connectors/conformance/package.json +54 -0
- package/connectors/conformance/scripts/sync-license.mjs +3 -0
- package/connectors/conformance/scripts/sync-spec.mjs +16 -0
- package/connectors/conformance/src/cli.ts +43 -0
- package/connectors/conformance/src/index.ts +7 -0
- package/connectors/conformance/src/runner.ts +314 -0
- package/connectors/conformance/src/types.ts +27 -0
- package/connectors/conformance/test/fixtures/invalid-response-identity.json +14 -0
- package/connectors/conformance/test/fixtures/missing-tool-fixture.json +4 -0
- package/connectors/conformance/test/runner.test.mjs +151 -0
- package/connectors/conformance/tsconfig.json +17 -0
- package/connectors/examples/reference-crypto-data/Dockerfile +21 -0
- package/connectors/examples/reference-crypto-data/README.md +51 -0
- package/connectors/examples/reference-crypto-data/conformance.json +11 -0
- package/connectors/examples/reference-crypto-data/connector.json +95 -0
- package/connectors/examples/reference-crypto-data/package.json +21 -0
- package/connectors/examples/reference-crypto-data/railway.toml +9 -0
- package/connectors/examples/reference-crypto-data/src/connector.ts +137 -0
- package/connectors/examples/reference-crypto-data/src/server.ts +13 -0
- package/connectors/examples/reference-crypto-data/test/connector.test.mjs +97 -0
- package/connectors/examples/reference-crypto-data/tsconfig.json +17 -0
- package/connectors/package-lock.json +561 -0
- package/connectors/package.json +19 -0
- package/connectors/scripts/smoke-packed-packages.mjs +121 -0
- package/connectors/sdk-typescript/README.md +47 -0
- package/connectors/sdk-typescript/package.json +49 -0
- package/connectors/sdk-typescript/scripts/sync-license.mjs +3 -0
- package/connectors/sdk-typescript/src/connector.ts +204 -0
- package/connectors/sdk-typescript/src/errors.ts +11 -0
- package/connectors/sdk-typescript/src/http.ts +116 -0
- package/connectors/sdk-typescript/src/index.ts +26 -0
- package/connectors/sdk-typescript/src/types.ts +101 -0
- package/connectors/sdk-typescript/test/sdk.test.mjs +181 -0
- package/connectors/sdk-typescript/tsconfig.json +21 -0
- package/connectors/spec/connector-manifest.schema.json +340 -0
- package/connectors/spec/connector-protocol.md +159 -0
- package/connectors/spec/transaction-intent.schema.json +281 -0
- package/connectors/templates/read-only/.env.example +1 -0
- package/connectors/templates/read-only/Dockerfile +11 -0
- package/connectors/templates/read-only/README.md +33 -0
- package/connectors/templates/read-only/conformance.json +11 -0
- package/connectors/templates/read-only/connector.json +64 -0
- package/connectors/templates/read-only/package.json +21 -0
- package/connectors/templates/read-only/railway.toml +9 -0
- package/connectors/templates/read-only/src/connector.ts +61 -0
- package/connectors/templates/read-only/src/server.ts +14 -0
- package/connectors/templates/read-only/test/connector.test.mjs +62 -0
- package/connectors/templates/read-only/tsconfig.json +17 -0
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/package.json +2 -1
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/package.json +1 -1
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
"name": "AgentLayer",
|
|
6
6
|
"url": "https://github.com/lopushok9/Agent-Layer"
|
|
7
7
|
},
|
|
8
|
+
"renames": {
|
|
9
|
+
"agent-wallet": "wallet"
|
|
10
|
+
},
|
|
8
11
|
"plugins": [
|
|
9
12
|
{
|
|
10
|
-
"name": "
|
|
13
|
+
"name": "wallet",
|
|
11
14
|
"displayName": "Agent Wallet",
|
|
12
15
|
"description": "Bridge to the local AgentLayer wallet runtime (Solana, Bitcoin, EVM). Installs and connects the backend runtime on first use.",
|
|
13
16
|
"category": "development",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
1
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import os from "node:os";
|
|
@@ -423,6 +423,50 @@ function buildCliEnv(packageRoot) {
|
|
|
423
423
|
return env;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
function loadConnectorToolDefinitions(api) {
|
|
427
|
+
const config = resolvePluginConfig(api);
|
|
428
|
+
try {
|
|
429
|
+
const packageRoot = resolvePackageRoot(config);
|
|
430
|
+
const stdout = execFileSync(
|
|
431
|
+
resolvePythonBin(config),
|
|
432
|
+
["-m", "agent_wallet.connector_cli", "tools"],
|
|
433
|
+
{
|
|
434
|
+
cwd: packageRoot,
|
|
435
|
+
env: {
|
|
436
|
+
...buildCliEnv(packageRoot),
|
|
437
|
+
OPENCLAW_HOME: resolveOpenclawHome(config),
|
|
438
|
+
},
|
|
439
|
+
encoding: "utf8",
|
|
440
|
+
maxBuffer: 1024 * 1024 * 2,
|
|
441
|
+
timeout: 10_000,
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
const payload = JSON.parse(stdout);
|
|
445
|
+
if (payload?.ok !== true || !Array.isArray(payload?.tools)) return [];
|
|
446
|
+
return payload.tools
|
|
447
|
+
.filter(
|
|
448
|
+
(tool) =>
|
|
449
|
+
tool?.read_only === true &&
|
|
450
|
+
typeof tool?.name === "string" &&
|
|
451
|
+
tool.name.startsWith("connector__") &&
|
|
452
|
+
typeof tool?.description === "string" &&
|
|
453
|
+
tool?.input_schema &&
|
|
454
|
+
typeof tool.input_schema === "object"
|
|
455
|
+
)
|
|
456
|
+
.map((tool) => ({
|
|
457
|
+
name: tool.name,
|
|
458
|
+
description: tool.description,
|
|
459
|
+
parameters: tool.input_schema,
|
|
460
|
+
optional: true,
|
|
461
|
+
}));
|
|
462
|
+
} catch (error) {
|
|
463
|
+
api?.logger?.warn?.(
|
|
464
|
+
`[agent-wallet] connector tools unavailable; built-in tools remain active: ${String(error?.message || error)}`
|
|
465
|
+
);
|
|
466
|
+
return [];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
426
470
|
async function callWalletCli(api, command, extraArgs = [], configOverride = null) {
|
|
427
471
|
const config = configOverride || resolvePluginConfig(api);
|
|
428
472
|
const packageRoot = resolvePackageRoot(config);
|
|
@@ -2184,6 +2228,7 @@ export default function registerAgentWalletPlugin(api) {
|
|
|
2184
2228
|
...solanaToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2185
2229
|
...btcToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2186
2230
|
...evmToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2231
|
+
...loadConnectorToolDefinitions(api),
|
|
2187
2232
|
]) {
|
|
2188
2233
|
if (seen.has(definition.name)) {
|
|
2189
2234
|
continue;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
1
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import os from "node:os";
|
|
@@ -423,6 +423,50 @@ function buildCliEnv(packageRoot) {
|
|
|
423
423
|
return env;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
function loadConnectorToolDefinitions(api) {
|
|
427
|
+
const config = resolvePluginConfig(api);
|
|
428
|
+
try {
|
|
429
|
+
const packageRoot = resolvePackageRoot(config);
|
|
430
|
+
const stdout = execFileSync(
|
|
431
|
+
resolvePythonBin(config),
|
|
432
|
+
["-m", "agent_wallet.connector_cli", "tools"],
|
|
433
|
+
{
|
|
434
|
+
cwd: packageRoot,
|
|
435
|
+
env: {
|
|
436
|
+
...buildCliEnv(packageRoot),
|
|
437
|
+
OPENCLAW_HOME: resolveOpenclawHome(config),
|
|
438
|
+
},
|
|
439
|
+
encoding: "utf8",
|
|
440
|
+
maxBuffer: 1024 * 1024 * 2,
|
|
441
|
+
timeout: 10_000,
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
const payload = JSON.parse(stdout);
|
|
445
|
+
if (payload?.ok !== true || !Array.isArray(payload?.tools)) return [];
|
|
446
|
+
return payload.tools
|
|
447
|
+
.filter(
|
|
448
|
+
(tool) =>
|
|
449
|
+
tool?.read_only === true &&
|
|
450
|
+
typeof tool?.name === "string" &&
|
|
451
|
+
tool.name.startsWith("connector__") &&
|
|
452
|
+
typeof tool?.description === "string" &&
|
|
453
|
+
tool?.input_schema &&
|
|
454
|
+
typeof tool.input_schema === "object"
|
|
455
|
+
)
|
|
456
|
+
.map((tool) => ({
|
|
457
|
+
name: tool.name,
|
|
458
|
+
description: tool.description,
|
|
459
|
+
parameters: tool.input_schema,
|
|
460
|
+
optional: true,
|
|
461
|
+
}));
|
|
462
|
+
} catch (error) {
|
|
463
|
+
api?.logger?.warn?.(
|
|
464
|
+
`[agent-wallet] connector tools unavailable; built-in tools remain active: ${String(error?.message || error)}`
|
|
465
|
+
);
|
|
466
|
+
return [];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
426
470
|
async function callWalletCli(api, command, extraArgs = [], configOverride = null) {
|
|
427
471
|
const config = configOverride || resolvePluginConfig(api);
|
|
428
472
|
const packageRoot = resolvePackageRoot(config);
|
|
@@ -2184,6 +2228,7 @@ export default function registerAgentWalletPlugin(api) {
|
|
|
2184
2228
|
...solanaToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2185
2229
|
...btcToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2186
2230
|
...evmToolDefinitions.filter((item) => !duplicateSessionToolNames.has(item.name)),
|
|
2231
|
+
...loadConnectorToolDefinitions(api),
|
|
2187
2232
|
]) {
|
|
2188
2233
|
if (seen.has(definition.name)) {
|
|
2189
2234
|
continue;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "agent-wallet",
|
|
3
3
|
"name": "Agent Wallet",
|
|
4
4
|
"description": "Official OpenClaw plugin bridge for the agent-wallet backends, including Solana, local BTC, and local EVM.",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.103",
|
|
6
6
|
"contracts": {
|
|
7
7
|
"tools": [
|
|
8
8
|
"agentlayer_autonomous_approve",
|
package/README.md
CHANGED
|
@@ -114,6 +114,24 @@ wallet update --yes
|
|
|
114
114
|
wallet rollback
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
+
## Optional connectors
|
|
118
|
+
|
|
119
|
+
Connectors add optional third-party crypto and DeFi read tools without moving
|
|
120
|
+
existing integrations such as Aave, Kamino, or Morpho out of the wallet core.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
wallet connectors inspect ./connector.json
|
|
124
|
+
wallet connectors install ./connector.json --enable --yes
|
|
125
|
+
wallet connectors list
|
|
126
|
+
wallet connectors disable com.example.protocol
|
|
127
|
+
wallet connectors doctor
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Enabled read-only connectors appear in OpenClaw and Codex after the host is
|
|
131
|
+
restarted. Write-capable connectors remain unavailable until their verified,
|
|
132
|
+
AgentLayer-hosted execution path is fully enabled. See
|
|
133
|
+
[`connectors/README.md`](connectors/README.md) for the trust model and protocol.
|
|
134
|
+
|
|
117
135
|
## What AgentLayer provides
|
|
118
136
|
|
|
119
137
|
AgentLayer connects supported agents to one local wallet runtime. The agent can:
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.103
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""JSON CLI for installing and managing optional AgentLayer connectors."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from agent_wallet.connectors.catalog import enabled_connector_tools
|
|
12
|
+
from agent_wallet.connectors.manifest import ConnectorManifestError, validate_connector_manifest
|
|
13
|
+
from agent_wallet.connectors.registry import ConnectorRegistry, ConnectorRegistryError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
MAX_MANIFEST_BYTES = 1024 * 1024
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _print(payload: Any) -> None:
|
|
20
|
+
print(json.dumps(payload, indent=2, sort_keys=True))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _load_manifest_file(value: str) -> tuple[dict[str, Any], str]:
|
|
24
|
+
path = Path(value).expanduser().resolve()
|
|
25
|
+
try:
|
|
26
|
+
size = path.stat().st_size
|
|
27
|
+
except OSError as exc:
|
|
28
|
+
raise ConnectorRegistryError(f"Connector manifest cannot be read: {path}: {exc}") from exc
|
|
29
|
+
if size > MAX_MANIFEST_BYTES:
|
|
30
|
+
raise ConnectorRegistryError(
|
|
31
|
+
f"Connector manifest exceeds the {MAX_MANIFEST_BYTES}-byte limit."
|
|
32
|
+
)
|
|
33
|
+
try:
|
|
34
|
+
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
35
|
+
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as exc:
|
|
36
|
+
raise ConnectorRegistryError(f"Connector manifest is invalid JSON: {path}: {exc}") from exc
|
|
37
|
+
if not isinstance(payload, dict):
|
|
38
|
+
raise ConnectorRegistryError("Connector manifest root must be an object.")
|
|
39
|
+
return payload, str(path)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _permission_review(manifest_payload: dict[str, Any]) -> dict[str, Any]:
|
|
43
|
+
manifest = validate_connector_manifest(manifest_payload)
|
|
44
|
+
permissions = manifest["permissions"]
|
|
45
|
+
warnings = ["Connector responses are untrusted external data."]
|
|
46
|
+
if permissions["wallet_address"]:
|
|
47
|
+
warnings.append("The connector may receive the active public wallet address.")
|
|
48
|
+
return {
|
|
49
|
+
"id": manifest["id"],
|
|
50
|
+
"version": manifest["version"],
|
|
51
|
+
"publisher": manifest["publisher"],
|
|
52
|
+
"trust": manifest["trust"],
|
|
53
|
+
"endpoint": manifest["transport"]["url"],
|
|
54
|
+
"permissions": permissions,
|
|
55
|
+
"tools": [tool["name"] for tool in manifest["tools"]],
|
|
56
|
+
"warnings": warnings,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
61
|
+
parser = argparse.ArgumentParser(prog="wallet connectors")
|
|
62
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
63
|
+
|
|
64
|
+
subparsers.add_parser("list", help="List locally installed connectors.")
|
|
65
|
+
subparsers.add_parser("tools", help="List enabled read-only connector tools for host registration.")
|
|
66
|
+
|
|
67
|
+
info = subparsers.add_parser("info", help="Show one installed connector.")
|
|
68
|
+
info.add_argument("connector_id")
|
|
69
|
+
|
|
70
|
+
inspect = subparsers.add_parser("inspect", help="Review a manifest before installation.")
|
|
71
|
+
inspect.add_argument("manifest", help="Path to a connector manifest JSON file.")
|
|
72
|
+
|
|
73
|
+
install = subparsers.add_parser("install", help="Install an immutable connector manifest.")
|
|
74
|
+
install.add_argument("manifest", help="Path to a connector manifest JSON file.")
|
|
75
|
+
install.add_argument("--enable", action="store_true", help="Enable this exact version.")
|
|
76
|
+
install.add_argument("--yes", action="store_true", help="Confirm permissions when enabling.")
|
|
77
|
+
|
|
78
|
+
enable = subparsers.add_parser("enable", help="Enable an installed connector version.")
|
|
79
|
+
enable.add_argument("connector_id")
|
|
80
|
+
enable.add_argument("--version", default=None)
|
|
81
|
+
enable.add_argument("--yes", action="store_true", help="Confirm the installed permissions.")
|
|
82
|
+
|
|
83
|
+
disable = subparsers.add_parser("disable", help="Disable an installed connector.")
|
|
84
|
+
disable.add_argument("connector_id")
|
|
85
|
+
|
|
86
|
+
remove = subparsers.add_parser("remove", help="Remove a disabled connector version.")
|
|
87
|
+
remove.add_argument("connector_id")
|
|
88
|
+
remove.add_argument("--version", default=None)
|
|
89
|
+
remove.add_argument("--yes", action="store_true", help="Confirm removal.")
|
|
90
|
+
|
|
91
|
+
subparsers.add_parser("doctor", help="Validate the registry and all installed manifests.")
|
|
92
|
+
return parser
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _doctor(registry: ConnectorRegistry) -> dict[str, Any]:
|
|
96
|
+
entries = registry.list()
|
|
97
|
+
checks: list[dict[str, Any]] = []
|
|
98
|
+
ok = True
|
|
99
|
+
for entry in entries:
|
|
100
|
+
connector_id = str(entry["id"])
|
|
101
|
+
for version in entry["installed_versions"]:
|
|
102
|
+
try:
|
|
103
|
+
registry.load_manifest(connector_id, str(version))
|
|
104
|
+
checks.append(
|
|
105
|
+
{
|
|
106
|
+
"connector_id": connector_id,
|
|
107
|
+
"version": version,
|
|
108
|
+
"ok": True,
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
except (ConnectorManifestError, ConnectorRegistryError) as exc:
|
|
112
|
+
ok = False
|
|
113
|
+
checks.append(
|
|
114
|
+
{
|
|
115
|
+
"connector_id": connector_id,
|
|
116
|
+
"version": version,
|
|
117
|
+
"ok": False,
|
|
118
|
+
"error": str(exc),
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
return {
|
|
122
|
+
"ok": ok,
|
|
123
|
+
"registry_path": str(registry.registry_path),
|
|
124
|
+
"connector_count": len(entries),
|
|
125
|
+
"checks": checks,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main(argv: list[str] | None = None) -> int:
|
|
130
|
+
parser = _build_parser()
|
|
131
|
+
args = parser.parse_args(argv)
|
|
132
|
+
registry = ConnectorRegistry()
|
|
133
|
+
try:
|
|
134
|
+
if args.command == "list":
|
|
135
|
+
_print({"ok": True, "connectors": registry.list()})
|
|
136
|
+
return 0
|
|
137
|
+
if args.command == "tools":
|
|
138
|
+
_print({"ok": True, "tools": enabled_connector_tools(registry, include_write=False)})
|
|
139
|
+
return 0
|
|
140
|
+
if args.command == "info":
|
|
141
|
+
_print({"ok": True, "connector": registry.describe(args.connector_id)})
|
|
142
|
+
return 0
|
|
143
|
+
if args.command == "inspect":
|
|
144
|
+
manifest, source = _load_manifest_file(args.manifest)
|
|
145
|
+
_print({"ok": True, "source": source, "review": _permission_review(manifest)})
|
|
146
|
+
return 0
|
|
147
|
+
if args.command == "install":
|
|
148
|
+
manifest, source = _load_manifest_file(args.manifest)
|
|
149
|
+
review = _permission_review(manifest)
|
|
150
|
+
if args.enable and not args.yes:
|
|
151
|
+
raise ConnectorRegistryError(
|
|
152
|
+
"install --enable requires --yes after reviewing connector permissions "
|
|
153
|
+
"with `wallet connectors inspect <manifest>`."
|
|
154
|
+
)
|
|
155
|
+
connector = registry.install(manifest, source=source, enable=bool(args.enable))
|
|
156
|
+
_print({"ok": True, "connector": connector, "review": review})
|
|
157
|
+
return 0
|
|
158
|
+
if args.command == "enable":
|
|
159
|
+
if not args.yes:
|
|
160
|
+
raise ConnectorRegistryError(
|
|
161
|
+
"enable requires --yes after reviewing the installed connector with "
|
|
162
|
+
"`wallet connectors info <connector_id>`."
|
|
163
|
+
)
|
|
164
|
+
connector = registry.enable(args.connector_id, version=args.version)
|
|
165
|
+
_print({"ok": True, "connector": connector})
|
|
166
|
+
return 0
|
|
167
|
+
if args.command == "disable":
|
|
168
|
+
connector = registry.disable(args.connector_id)
|
|
169
|
+
_print({"ok": True, "connector": connector})
|
|
170
|
+
return 0
|
|
171
|
+
if args.command == "remove":
|
|
172
|
+
if not args.yes:
|
|
173
|
+
raise ConnectorRegistryError("remove requires --yes after the connector is disabled.")
|
|
174
|
+
result = registry.remove(args.connector_id, version=args.version)
|
|
175
|
+
_print({"ok": True, **result})
|
|
176
|
+
return 0
|
|
177
|
+
if args.command == "doctor":
|
|
178
|
+
result = _doctor(registry)
|
|
179
|
+
_print(result)
|
|
180
|
+
return 0 if result["ok"] else 1
|
|
181
|
+
raise ConnectorRegistryError(f"Unsupported connectors command: {args.command}.")
|
|
182
|
+
except (ConnectorManifestError, ConnectorRegistryError) as exc:
|
|
183
|
+
print(
|
|
184
|
+
json.dumps(
|
|
185
|
+
{
|
|
186
|
+
"ok": False,
|
|
187
|
+
"error": str(exc),
|
|
188
|
+
"error_type": type(exc).__name__,
|
|
189
|
+
},
|
|
190
|
+
sort_keys=True,
|
|
191
|
+
),
|
|
192
|
+
file=sys.stderr,
|
|
193
|
+
)
|
|
194
|
+
return 2
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Optional AgentLayer connector contracts and local registry support."""
|
|
2
|
+
|
|
3
|
+
from agent_wallet.connectors.catalog import enabled_connector_tools, resolve_connector_tool
|
|
4
|
+
from agent_wallet.connectors.client import ConnectorInvocationError, ConnectorReadClient
|
|
5
|
+
from agent_wallet.connectors.intent_policy import (
|
|
6
|
+
ConnectorIntentPolicyError,
|
|
7
|
+
validate_evm_transaction_intent,
|
|
8
|
+
)
|
|
9
|
+
from agent_wallet.connectors.manifest import (
|
|
10
|
+
ConnectorManifestError,
|
|
11
|
+
connector_tool_name,
|
|
12
|
+
validate_connector_manifest,
|
|
13
|
+
)
|
|
14
|
+
from agent_wallet.connectors.registry import ConnectorRegistry, ConnectorRegistryError
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"ConnectorManifestError",
|
|
18
|
+
"ConnectorInvocationError",
|
|
19
|
+
"ConnectorIntentPolicyError",
|
|
20
|
+
"ConnectorReadClient",
|
|
21
|
+
"ConnectorRegistry",
|
|
22
|
+
"ConnectorRegistryError",
|
|
23
|
+
"connector_tool_name",
|
|
24
|
+
"enabled_connector_tools",
|
|
25
|
+
"resolve_connector_tool",
|
|
26
|
+
"validate_connector_manifest",
|
|
27
|
+
"validate_evm_transaction_intent",
|
|
28
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Build the safe host-facing catalog of enabled connector tools."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from agent_wallet.connectors.manifest import connector_tool_name
|
|
8
|
+
from agent_wallet.connectors.registry import ConnectorRegistry, ConnectorRegistryError
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def enabled_connector_tools(
|
|
12
|
+
registry: ConnectorRegistry | None = None,
|
|
13
|
+
*,
|
|
14
|
+
include_write: bool = False,
|
|
15
|
+
) -> list[dict[str, Any]]:
|
|
16
|
+
"""Return enabled tools, withholding writes until their policy is available."""
|
|
17
|
+
|
|
18
|
+
active_registry = registry or ConnectorRegistry()
|
|
19
|
+
result: list[dict[str, Any]] = []
|
|
20
|
+
seen: set[str] = set()
|
|
21
|
+
for entry in active_registry.list():
|
|
22
|
+
if not entry["enabled"]:
|
|
23
|
+
continue
|
|
24
|
+
connector_id = str(entry["id"])
|
|
25
|
+
version = str(entry["enabled_version"])
|
|
26
|
+
manifest = active_registry.load_manifest(connector_id, version)
|
|
27
|
+
for raw_tool in manifest["tools"]:
|
|
28
|
+
if not isinstance(raw_tool, dict):
|
|
29
|
+
raise ConnectorRegistryError(f"Connector tool is invalid: {connector_id}.")
|
|
30
|
+
read_only = raw_tool.get("read_only") is True
|
|
31
|
+
if not read_only and not include_write:
|
|
32
|
+
continue
|
|
33
|
+
host_name = connector_tool_name(connector_id, str(raw_tool.get("name") or ""))
|
|
34
|
+
if host_name in seen:
|
|
35
|
+
raise ConnectorRegistryError(f"Duplicate host connector tool name: {host_name}.")
|
|
36
|
+
seen.add(host_name)
|
|
37
|
+
result.append(
|
|
38
|
+
{
|
|
39
|
+
"name": host_name,
|
|
40
|
+
"description": (
|
|
41
|
+
"[External connector: untrusted read-only data] "
|
|
42
|
+
+ str(raw_tool["description"])
|
|
43
|
+
),
|
|
44
|
+
"input_schema": raw_tool["input_schema"],
|
|
45
|
+
"output_schema": raw_tool["output_schema"],
|
|
46
|
+
"read_only": read_only,
|
|
47
|
+
"risk_level": str(raw_tool["risk_level"]),
|
|
48
|
+
"connector_id": connector_id,
|
|
49
|
+
"connector_version": version,
|
|
50
|
+
"connector_tool": str(raw_tool["name"]),
|
|
51
|
+
"connector_trust": str(manifest["trust"]),
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
return sorted(result, key=lambda item: str(item["name"]))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def resolve_connector_tool(
|
|
58
|
+
host_tool_name: str,
|
|
59
|
+
registry: ConnectorRegistry | None = None,
|
|
60
|
+
*,
|
|
61
|
+
include_write: bool = False,
|
|
62
|
+
) -> dict[str, Any]:
|
|
63
|
+
"""Resolve one host tool through the enabled immutable catalog."""
|
|
64
|
+
|
|
65
|
+
for tool in enabled_connector_tools(registry, include_write=include_write):
|
|
66
|
+
if tool["name"] == host_tool_name:
|
|
67
|
+
return tool
|
|
68
|
+
raise ConnectorRegistryError(f"Enabled connector tool was not found: {host_tool_name}.")
|