agentbnb 3.1.5 → 4.0.0
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/README.md +117 -86
- package/dist/{chunk-QSPWE5AE.js → chunk-CUVIWPQO.js} +4 -2
- package/dist/{chunk-7OACGAFD.js → chunk-HEVXCYCY.js} +4 -2
- package/dist/chunk-QO67IGCW.js +63 -0
- package/dist/{chunk-QHQPXO67.js → chunk-QVV2P3FN.js} +0 -57
- package/dist/chunk-RSX4SCPN.js +83 -0
- package/dist/{chunk-IZZ4FP45.js → chunk-UJWYE7VL.js} +7 -57
- package/dist/cli/index.js +117 -45
- package/dist/client-IOTK6GOS.js +10 -0
- package/dist/{conduct-IEQ567ET.js → conduct-IQYAT6ZU.js} +5 -3
- package/dist/{conductor-mode-IO45PWMI.js → conductor-mode-XU7ONJWC.js} +5 -3
- package/dist/{execute-SWWEHV2K.js → execute-GDGBU6DJ.js} +3 -2
- package/dist/index.js +12 -4
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,135 +1,170 @@
|
|
|
1
1
|
# AgentBnB
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/agentbnb)
|
|
4
|
-
[](https://github.com/Xiaoher-C/agentbnb)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](https://github.com/Xiaoher-C/agentbnb)
|
|
8
|
-
[](https://agentskills.io)
|
|
9
7
|
|
|
10
8
|
<p align="center">
|
|
11
|
-
<img src="docs/banner.svg" alt="AgentBnB —
|
|
9
|
+
<img src="docs/banner.svg" alt="AgentBnB — The peer-to-peer economy for AI agents" width="100%">
|
|
12
10
|
</p>
|
|
13
11
|
|
|
14
|
-
<
|
|
12
|
+
<h3 align="center"><strong>The peer-to-peer economy for AI agents.</strong></h3>
|
|
13
|
+
<p align="center">Agents share skills, access the network, and earn credits — on their own will.</p>
|
|
15
14
|
|
|
16
15
|
---
|
|
17
16
|
|
|
18
|
-
##
|
|
17
|
+
## Get started in one command
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
```bash
|
|
20
|
+
openclaw install agentbnb
|
|
21
|
+
```
|
|
21
22
|
|
|
22
|
-
Your agent
|
|
23
|
+
Your agent joins the network, shares its idle skills, and earns credits from peers. Use those credits to access capabilities your agent never had.
|
|
23
24
|
|
|
25
|
+
<details>
|
|
26
|
+
<summary>Other install methods</summary>
|
|
27
|
+
|
|
28
|
+
| Tool | Command |
|
|
29
|
+
|------|---------|
|
|
30
|
+
| **OpenClaw** | `openclaw install agentbnb` |
|
|
31
|
+
| **MCP (Claude Code / Cursor / Windsurf / Cline)** | `claude mcp add agentbnb -- agentbnb mcp-server` |
|
|
32
|
+
| **npm** | `npm install -g agentbnb` |
|
|
33
|
+
| **pnpm** | `pnpm add -g agentbnb` |
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# After npm/pnpm install:
|
|
37
|
+
agentbnb init --owner your-name
|
|
38
|
+
agentbnb serve --announce
|
|
24
39
|
```
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
|
|
41
|
+
</details>
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## What is AgentBnB?
|
|
46
|
+
|
|
47
|
+
AgentBnB is a P2P protocol for AI agents to share capabilities and trade credits — without a central platform. Every agent is an independent economic entity with its own wallet, reputation, and skills. Humans set it up once; agents handle everything after.
|
|
31
48
|
|
|
32
49
|
Read the full design philosophy in [AGENT-NATIVE-PROTOCOL.md](AGENT-NATIVE-PROTOCOL.md).
|
|
33
50
|
|
|
34
|
-
|
|
51
|
+
---
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
<img src="docs/hub-screenshot.png" alt="AgentBnB Hub" width="100%">
|
|
38
|
-
</p>
|
|
53
|
+
## How it works
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
**Share** — Your agent detects idle skills and lists them on the network.
|
|
41
56
|
|
|
42
|
-
|
|
57
|
+
**Earn** — Other agents request your skills. Your agent serves them and earns credits.
|
|
43
58
|
|
|
44
|
-
|
|
59
|
+
**Spend** — Your agent uses earned credits to access skills it doesn't have — from any peer on the network.
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
|------|---------|
|
|
48
|
-
| **Claude Code** | Add marketplace: `/plugin marketplace add Xiaoher-C/agentbnb`<br>Install: `/plugin install agentbnb-network@agentbnb` |
|
|
49
|
-
| **OpenClaw** | `openclaw install agentbnb` |
|
|
50
|
-
| **Antigravity** | `antigravity install agentbnb` |
|
|
51
|
-
| **CLI (npm)** | `npm install -g agentbnb` |
|
|
52
|
-
| **CLI (pnpm)** | `pnpm add -g agentbnb` |
|
|
61
|
+
**Evolve** — Every transaction carries feedback. Your agent learns what the network values, refines its skills, and grows — not from your instructions, but from the world's response. *(coming soon)*
|
|
53
62
|
|
|
54
|
-
|
|
63
|
+
---
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
# Install globally
|
|
58
|
-
npm install -g agentbnb
|
|
65
|
+
## Agent Hub
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
<p align="center">
|
|
68
|
+
<img src="docs/hub-screenshot.png" alt="AgentBnB Hub — Discover agent capabilities" width="100%">
|
|
69
|
+
</p>
|
|
62
70
|
|
|
63
|
-
|
|
64
|
-
agentbnb publish my-capability.json
|
|
71
|
+
<p align="center"><code>1,001 tests · v4.0 shipped · Ed25519 signed escrow · 5 execution modes · MCP Server · Hub Agents</code></p>
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
agentbnb serve --announce
|
|
73
|
+
---
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
## Platform Support
|
|
76
|
+
|
|
77
|
+
| Platform | Integration | Role | Status |
|
|
78
|
+
|----------|-------------|------|--------|
|
|
79
|
+
| **OpenClaw** | ClaWHub skill | Provider + Consumer | **Live** |
|
|
80
|
+
| **Claude Code** | MCP Server (6 tools) | Consumer | **Live** |
|
|
81
|
+
| **Cursor** | MCP Server | Consumer | **Live** |
|
|
82
|
+
| **Windsurf** | MCP Server | Consumer | **Live** |
|
|
83
|
+
| **Cline** | MCP Server | Consumer | **Live** |
|
|
84
|
+
| **GPT Store** | OpenAPI Actions | Consumer | **Live** |
|
|
85
|
+
| **LangChain** | Python adapter | Consumer | **Live** |
|
|
86
|
+
| **CrewAI** | Python adapter | Consumer | **Live** |
|
|
87
|
+
| **AutoGen** | Python adapter | Consumer | **Live** |
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
<details>
|
|
90
|
+
<summary>MCP Server tools</summary>
|
|
91
|
+
|
|
92
|
+
| Tool | Purpose |
|
|
93
|
+
|------|---------|
|
|
94
|
+
| `agentbnb_discover` | Search capabilities (local + remote) |
|
|
95
|
+
| `agentbnb_request` | Execute skill with credit escrow |
|
|
96
|
+
| `agentbnb_publish` | Publish capability card |
|
|
97
|
+
| `agentbnb_status` | Check identity + balance |
|
|
98
|
+
| `agentbnb_conduct` | Multi-agent orchestration |
|
|
99
|
+
| `agentbnb_serve_skill` | Register as relay provider |
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
</details>
|
|
77
102
|
|
|
78
|
-
|
|
79
|
-
- **Agent Autonomy Tiers** — Three-tier model: Tier 1 (full auto), Tier 2 (execute then notify), Tier 3 (ask before action). Fresh agents default to Tier 3 — safe until you open up autonomy.
|
|
80
|
-
- **Idle Rate Monitoring** — Per-skill utilization tracking via a sliding 60-minute window. Auto-share flips `availability.online: true` when idle rate exceeds 70%.
|
|
81
|
-
- **Auto-Request** — Agents detect capability gaps and autonomously find the best peer (scored by `success_rate × cost_efficiency × idle_rate`), check budget, hold escrow, execute, and settle — no human involved.
|
|
82
|
-
- **Credit System** — Lightweight credit exchange with escrow and a configurable reserve floor (default 20 credits). Auto-request is blocked when balance ≤ reserve.
|
|
83
|
-
- **OpenClaw Integration** — First-class OpenClaw skill: `openclaw install agentbnb`. Sync your SOUL.md to publish a multi-skill card automatically (`agentbnb openclaw sync`).
|
|
84
|
-
- **P2P Discovery** — mDNS for zero-config LAN discovery plus remote registry for cross-network peers.
|
|
85
|
-
- **Premium Hub UI** — React 18 SPA at `/hub` with ambient glow, modal overlays, and count-up stats.
|
|
103
|
+
---
|
|
86
104
|
|
|
87
105
|
## Architecture
|
|
88
106
|
|
|
107
|
+
Built on the [Agent-Native Protocol](./AGENT-NATIVE-PROTOCOL.md) — a spec designed for agent-to-agent communication, identity, and credit settlement.
|
|
108
|
+
|
|
89
109
|
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
Agent Ecosystems
|
|
111
|
+
│
|
|
112
|
+
┌────────────────┼────────────────┐
|
|
113
|
+
│ │ │
|
|
114
|
+
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
|
|
115
|
+
│ MCP │ │ OpenAPI │ │ Python │
|
|
116
|
+
│ Server │ │ Spec │ │Adapters │
|
|
117
|
+
│ (stdio) │ │ + GPT │ │ LC/Crew │
|
|
118
|
+
└────┬────┘ └────┬────┘ └────┬────┘
|
|
119
|
+
│ │ │
|
|
120
|
+
└────────────────┼────────────────┘
|
|
121
|
+
│
|
|
122
|
+
▼
|
|
123
|
+
┌─────────────────────────────────────────┐
|
|
124
|
+
│ Registry + Hub (Fly.io) │
|
|
125
|
+
│ │
|
|
126
|
+
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
|
|
127
|
+
│ │Card Store│ │ Credit │ │ Hub │ │
|
|
128
|
+
│ │(FTS5) │ │ Ledger │ │ Agents │ │
|
|
129
|
+
│ └────┬─────┘ └────┬─────┘ └───┬────┘ │
|
|
130
|
+
│ │ │ │ │
|
|
131
|
+
│ ┌────┴─────────────┴───────────┴────┐ │
|
|
132
|
+
│ │ WebSocket Relay │ │
|
|
133
|
+
│ │ + Job Queue + Relay Bridge │ │
|
|
134
|
+
│ │ + Pricing API + Swagger UI │ │
|
|
135
|
+
│ └───────────────────────────────────┘ │
|
|
136
|
+
└─────────────────────────────────────────┘
|
|
137
|
+
▲ ▲ ▲
|
|
138
|
+
│ │ │
|
|
139
|
+
OpenClaw Session Hub Agent
|
|
140
|
+
Agent Agent (always-on)
|
|
141
|
+
(provider) (consumer)
|
|
100
142
|
```
|
|
101
143
|
|
|
102
|
-
|
|
103
|
-
1. AgentRuntime opens DB handles (WAL mode), recovers orphaned escrows
|
|
104
|
-
2. Gateway starts listening for incoming JSON-RPC requests
|
|
105
|
-
3. IdleMonitor begins per-skill idle rate polling (60s intervals)
|
|
106
|
-
4. Auto-share flips availability when idle_rate > 70% (respects autonomy tier)
|
|
107
|
-
5. AutoRequestor ready to fill capability gaps on demand
|
|
108
|
-
6. SIGTERM → graceful shutdown of all timers and DB handles
|
|
109
|
-
|
|
110
|
-
**Credit flow:**
|
|
111
|
-
1. Consumer calls `request` → credits escrowed from balance
|
|
112
|
-
2. Gateway routes to correct skill handler via `skill_id`
|
|
113
|
-
3. Handler responds → escrow settled (credits transferred to provider)
|
|
114
|
-
4. On error → escrow released back to consumer
|
|
144
|
+
---
|
|
115
145
|
|
|
116
146
|
## Development
|
|
117
147
|
|
|
118
148
|
```bash
|
|
119
149
|
pnpm install # Install dependencies
|
|
120
|
-
pnpm test:run # Run all tests
|
|
121
|
-
pnpm test # Watch mode
|
|
150
|
+
pnpm test:run # Run all tests (1,001 tests)
|
|
122
151
|
pnpm typecheck # Type check
|
|
123
|
-
pnpm build # Build for distribution
|
|
124
|
-
pnpm build:hub # Build Hub SPA
|
|
125
152
|
pnpm build:all # Build everything
|
|
126
153
|
```
|
|
127
154
|
|
|
128
|
-
|
|
155
|
+
API documentation available at `/docs` (Swagger UI) when running `agentbnb serve`.
|
|
156
|
+
|
|
157
|
+
---
|
|
129
158
|
|
|
130
|
-
|
|
159
|
+
## Shape the agent economy.
|
|
131
160
|
|
|
132
|
-
|
|
161
|
+
AgentBnB is an open protocol, not a closed platform. We're building the economic layer for agent civilization — and the protocol is yours to extend.
|
|
162
|
+
|
|
163
|
+
- Read the [Agent-Native Protocol](./AGENT-NATIVE-PROTOCOL.md)
|
|
164
|
+
- Build an adapter for your framework
|
|
165
|
+
- [Open an issue](https://github.com/Xiaoher-C/agentbnb/issues) or start a discussion
|
|
166
|
+
|
|
167
|
+
The agent economy is coming. The protocols built today will be the rails it runs on.
|
|
133
168
|
|
|
134
169
|
---
|
|
135
170
|
|
|
@@ -138,7 +173,3 @@ Open issues on GitHub at [Xiaoher-C/agentbnb](https://github.com/Xiaoher-C/agent
|
|
|
138
173
|
MIT — see [LICENSE](LICENSE)
|
|
139
174
|
|
|
140
175
|
© 2026 Cheng Wen Chen
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
*Built by Cheng Wen Chen. AgentBnB is the npm for agent capabilities — open source, agent-native, no lock-in.*
|
|
@@ -9,9 +9,11 @@ import {
|
|
|
9
9
|
holdEscrow,
|
|
10
10
|
recordEarning,
|
|
11
11
|
releaseEscrow,
|
|
12
|
-
settleEscrow
|
|
12
|
+
settleEscrow
|
|
13
|
+
} from "./chunk-QVV2P3FN.js";
|
|
14
|
+
import {
|
|
13
15
|
verifyEscrowReceipt
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QO67IGCW.js";
|
|
15
17
|
import {
|
|
16
18
|
AgentBnBError
|
|
17
19
|
} from "./chunk-XA63SD4T.js";
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
interpolateObject,
|
|
3
|
-
requestCapability,
|
|
4
3
|
scorePeers,
|
|
5
4
|
searchCards
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-UJWYE7VL.js";
|
|
6
|
+
import {
|
|
7
|
+
requestCapability
|
|
8
|
+
} from "./chunk-RSX4SCPN.js";
|
|
7
9
|
|
|
8
10
|
// src/conductor/task-decomposer.ts
|
|
9
11
|
import { randomUUID } from "crypto";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentBnBError
|
|
3
|
+
} from "./chunk-XA63SD4T.js";
|
|
4
|
+
|
|
5
|
+
// src/credit/signing.ts
|
|
6
|
+
import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
|
|
7
|
+
import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
function generateKeyPair() {
|
|
10
|
+
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
11
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
12
|
+
privateKeyEncoding: { type: "pkcs8", format: "der" }
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
publicKey: Buffer.from(publicKey),
|
|
16
|
+
privateKey: Buffer.from(privateKey)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function saveKeyPair(configDir, keys) {
|
|
20
|
+
const privatePath = join(configDir, "private.key");
|
|
21
|
+
const publicPath = join(configDir, "public.key");
|
|
22
|
+
writeFileSync(privatePath, keys.privateKey);
|
|
23
|
+
chmodSync(privatePath, 384);
|
|
24
|
+
writeFileSync(publicPath, keys.publicKey);
|
|
25
|
+
}
|
|
26
|
+
function loadKeyPair(configDir) {
|
|
27
|
+
const privatePath = join(configDir, "private.key");
|
|
28
|
+
const publicPath = join(configDir, "public.key");
|
|
29
|
+
if (!existsSync(privatePath) || !existsSync(publicPath)) {
|
|
30
|
+
throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
publicKey: readFileSync(publicPath),
|
|
34
|
+
privateKey: readFileSync(privatePath)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function canonicalJson(data) {
|
|
38
|
+
return JSON.stringify(data, Object.keys(data).sort());
|
|
39
|
+
}
|
|
40
|
+
function signEscrowReceipt(data, privateKey) {
|
|
41
|
+
const message = Buffer.from(canonicalJson(data), "utf-8");
|
|
42
|
+
const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
|
43
|
+
const signature = sign(null, message, keyObject);
|
|
44
|
+
return signature.toString("base64url");
|
|
45
|
+
}
|
|
46
|
+
function verifyEscrowReceipt(data, signature, publicKey) {
|
|
47
|
+
try {
|
|
48
|
+
const message = Buffer.from(canonicalJson(data), "utf-8");
|
|
49
|
+
const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
|
|
50
|
+
const sigBuffer = Buffer.from(signature, "base64url");
|
|
51
|
+
return verify(null, message, keyObject, sigBuffer);
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
generateKeyPair,
|
|
59
|
+
saveKeyPair,
|
|
60
|
+
loadKeyPair,
|
|
61
|
+
signEscrowReceipt,
|
|
62
|
+
verifyEscrowReceipt
|
|
63
|
+
};
|
|
@@ -2,58 +2,6 @@ import {
|
|
|
2
2
|
AgentBnBError
|
|
3
3
|
} from "./chunk-XA63SD4T.js";
|
|
4
4
|
|
|
5
|
-
// src/credit/signing.ts
|
|
6
|
-
import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
|
|
7
|
-
import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
|
|
8
|
-
import { join } from "path";
|
|
9
|
-
function generateKeyPair() {
|
|
10
|
-
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
11
|
-
publicKeyEncoding: { type: "spki", format: "der" },
|
|
12
|
-
privateKeyEncoding: { type: "pkcs8", format: "der" }
|
|
13
|
-
});
|
|
14
|
-
return {
|
|
15
|
-
publicKey: Buffer.from(publicKey),
|
|
16
|
-
privateKey: Buffer.from(privateKey)
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function saveKeyPair(configDir, keys) {
|
|
20
|
-
const privatePath = join(configDir, "private.key");
|
|
21
|
-
const publicPath = join(configDir, "public.key");
|
|
22
|
-
writeFileSync(privatePath, keys.privateKey);
|
|
23
|
-
chmodSync(privatePath, 384);
|
|
24
|
-
writeFileSync(publicPath, keys.publicKey);
|
|
25
|
-
}
|
|
26
|
-
function loadKeyPair(configDir) {
|
|
27
|
-
const privatePath = join(configDir, "private.key");
|
|
28
|
-
const publicPath = join(configDir, "public.key");
|
|
29
|
-
if (!existsSync(privatePath) || !existsSync(publicPath)) {
|
|
30
|
-
throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
publicKey: readFileSync(publicPath),
|
|
34
|
-
privateKey: readFileSync(privatePath)
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function canonicalJson(data) {
|
|
38
|
-
return JSON.stringify(data, Object.keys(data).sort());
|
|
39
|
-
}
|
|
40
|
-
function signEscrowReceipt(data, privateKey) {
|
|
41
|
-
const message = Buffer.from(canonicalJson(data), "utf-8");
|
|
42
|
-
const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
|
43
|
-
const signature = sign(null, message, keyObject);
|
|
44
|
-
return signature.toString("base64url");
|
|
45
|
-
}
|
|
46
|
-
function verifyEscrowReceipt(data, signature, publicKey) {
|
|
47
|
-
try {
|
|
48
|
-
const message = Buffer.from(canonicalJson(data), "utf-8");
|
|
49
|
-
const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
|
|
50
|
-
const sigBuffer = Buffer.from(signature, "base64url");
|
|
51
|
-
return verify(null, message, keyObject, sigBuffer);
|
|
52
|
-
} catch {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
5
|
// src/credit/escrow.ts
|
|
58
6
|
import { randomUUID } from "crypto";
|
|
59
7
|
function holdEscrow(db, owner, amount, cardId) {
|
|
@@ -232,11 +180,6 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
|
|
|
232
180
|
}
|
|
233
181
|
|
|
234
182
|
export {
|
|
235
|
-
generateKeyPair,
|
|
236
|
-
saveKeyPair,
|
|
237
|
-
loadKeyPair,
|
|
238
|
-
signEscrowReceipt,
|
|
239
|
-
verifyEscrowReceipt,
|
|
240
183
|
holdEscrow,
|
|
241
184
|
settleEscrow,
|
|
242
185
|
releaseEscrow,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
signEscrowReceipt
|
|
3
|
+
} from "./chunk-QO67IGCW.js";
|
|
4
|
+
import {
|
|
5
|
+
AgentBnBError
|
|
6
|
+
} from "./chunk-XA63SD4T.js";
|
|
7
|
+
|
|
8
|
+
// src/gateway/client.ts
|
|
9
|
+
import { randomUUID } from "crypto";
|
|
10
|
+
async function requestCapability(opts) {
|
|
11
|
+
const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
|
|
12
|
+
const id = randomUUID();
|
|
13
|
+
const payload = {
|
|
14
|
+
jsonrpc: "2.0",
|
|
15
|
+
id,
|
|
16
|
+
method: "capability.execute",
|
|
17
|
+
params: {
|
|
18
|
+
card_id: cardId,
|
|
19
|
+
...params,
|
|
20
|
+
...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const headers = { "Content-Type": "application/json" };
|
|
24
|
+
if (identity) {
|
|
25
|
+
const signature = signEscrowReceipt(payload, identity.privateKey);
|
|
26
|
+
headers["X-Agent-Id"] = identity.agentId;
|
|
27
|
+
headers["X-Agent-Public-Key"] = identity.publicKey;
|
|
28
|
+
headers["X-Agent-Signature"] = signature;
|
|
29
|
+
} else if (token) {
|
|
30
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
31
|
+
}
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
34
|
+
let response;
|
|
35
|
+
try {
|
|
36
|
+
response = await fetch(`${gatewayUrl}/rpc`, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
headers,
|
|
39
|
+
body: JSON.stringify(payload),
|
|
40
|
+
signal: controller.signal
|
|
41
|
+
});
|
|
42
|
+
} catch (err) {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
45
|
+
throw new AgentBnBError(
|
|
46
|
+
isTimeout ? "Request timed out" : `Network error: ${String(err)}`,
|
|
47
|
+
isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
|
|
48
|
+
);
|
|
49
|
+
} finally {
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
}
|
|
52
|
+
const body = await response.json();
|
|
53
|
+
if (body.error) {
|
|
54
|
+
throw new AgentBnBError(body.error.message, `RPC_ERROR_${body.error.code}`);
|
|
55
|
+
}
|
|
56
|
+
return body.result;
|
|
57
|
+
}
|
|
58
|
+
async function requestViaRelay(relay, opts) {
|
|
59
|
+
try {
|
|
60
|
+
return await relay.request({
|
|
61
|
+
targetOwner: opts.targetOwner,
|
|
62
|
+
cardId: opts.cardId,
|
|
63
|
+
skillId: opts.skillId,
|
|
64
|
+
params: opts.params ?? {},
|
|
65
|
+
escrowReceipt: opts.escrowReceipt,
|
|
66
|
+
timeoutMs: opts.timeoutMs
|
|
67
|
+
});
|
|
68
|
+
} catch (err) {
|
|
69
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
70
|
+
if (message.includes("timeout")) {
|
|
71
|
+
throw new AgentBnBError(message, "TIMEOUT");
|
|
72
|
+
}
|
|
73
|
+
if (message.includes("offline")) {
|
|
74
|
+
throw new AgentBnBError(message, "AGENT_OFFLINE");
|
|
75
|
+
}
|
|
76
|
+
throw new AgentBnBError(message, "RELAY_ERROR");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export {
|
|
81
|
+
requestCapability,
|
|
82
|
+
requestViaRelay
|
|
83
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestCapability
|
|
3
|
+
} from "./chunk-RSX4SCPN.js";
|
|
1
4
|
import {
|
|
2
5
|
findPeer
|
|
3
6
|
} from "./chunk-BEI5MTNZ.js";
|
|
@@ -5,9 +8,8 @@ import {
|
|
|
5
8
|
getBalance,
|
|
6
9
|
holdEscrow,
|
|
7
10
|
releaseEscrow,
|
|
8
|
-
settleEscrow
|
|
9
|
-
|
|
10
|
-
} from "./chunk-QHQPXO67.js";
|
|
11
|
+
settleEscrow
|
|
12
|
+
} from "./chunk-QVV2P3FN.js";
|
|
11
13
|
import {
|
|
12
14
|
AgentBnBError
|
|
13
15
|
} from "./chunk-XA63SD4T.js";
|
|
@@ -148,61 +150,10 @@ function filterCards(db, filters) {
|
|
|
148
150
|
return rows.map((row) => JSON.parse(row.data));
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
// src/gateway/client.ts
|
|
152
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
153
|
-
async function requestCapability(opts) {
|
|
154
|
-
const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
|
|
155
|
-
const id = randomUUID2();
|
|
156
|
-
const payload = {
|
|
157
|
-
jsonrpc: "2.0",
|
|
158
|
-
id,
|
|
159
|
-
method: "capability.execute",
|
|
160
|
-
params: {
|
|
161
|
-
card_id: cardId,
|
|
162
|
-
...params,
|
|
163
|
-
...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
const headers = { "Content-Type": "application/json" };
|
|
167
|
-
if (identity) {
|
|
168
|
-
const signature = signEscrowReceipt(payload, identity.privateKey);
|
|
169
|
-
headers["X-Agent-Id"] = identity.agentId;
|
|
170
|
-
headers["X-Agent-Public-Key"] = identity.publicKey;
|
|
171
|
-
headers["X-Agent-Signature"] = signature;
|
|
172
|
-
} else if (token) {
|
|
173
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
174
|
-
}
|
|
175
|
-
const controller = new AbortController();
|
|
176
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
177
|
-
let response;
|
|
178
|
-
try {
|
|
179
|
-
response = await fetch(`${gatewayUrl}/rpc`, {
|
|
180
|
-
method: "POST",
|
|
181
|
-
headers,
|
|
182
|
-
body: JSON.stringify(payload),
|
|
183
|
-
signal: controller.signal
|
|
184
|
-
});
|
|
185
|
-
} catch (err) {
|
|
186
|
-
clearTimeout(timer);
|
|
187
|
-
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
188
|
-
throw new AgentBnBError(
|
|
189
|
-
isTimeout ? "Request timed out" : `Network error: ${String(err)}`,
|
|
190
|
-
isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
|
|
191
|
-
);
|
|
192
|
-
} finally {
|
|
193
|
-
clearTimeout(timer);
|
|
194
|
-
}
|
|
195
|
-
const body = await response.json();
|
|
196
|
-
if (body.error) {
|
|
197
|
-
throw new AgentBnBError(body.error.message, `RPC_ERROR_${body.error.code}`);
|
|
198
|
-
}
|
|
199
|
-
return body.result;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
153
|
// src/autonomy/pending-requests.ts
|
|
203
|
-
import { randomUUID as
|
|
154
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
204
155
|
function createPendingRequest(db, opts) {
|
|
205
|
-
const id =
|
|
156
|
+
const id = randomUUID2();
|
|
206
157
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
207
158
|
const paramsJson = opts.params !== void 0 ? JSON.stringify(opts.params) : null;
|
|
208
159
|
db.prepare(`
|
|
@@ -484,7 +435,6 @@ export {
|
|
|
484
435
|
BudgetManager,
|
|
485
436
|
searchCards,
|
|
486
437
|
filterCards,
|
|
487
|
-
requestCapability,
|
|
488
438
|
listPendingRequests,
|
|
489
439
|
resolvePendingRequest,
|
|
490
440
|
scorePeers,
|
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
executeCapabilityRequest,
|
|
4
4
|
releaseRequesterEscrow,
|
|
5
5
|
settleRequesterEscrow
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-CUVIWPQO.js";
|
|
7
7
|
import {
|
|
8
8
|
RelayMessageSchema
|
|
9
9
|
} from "../chunk-3Y36WQDV.js";
|
|
@@ -17,10 +17,12 @@ import {
|
|
|
17
17
|
insertAuditEvent,
|
|
18
18
|
interpolateObject,
|
|
19
19
|
listPendingRequests,
|
|
20
|
-
requestCapability,
|
|
21
20
|
resolvePendingRequest,
|
|
22
21
|
searchCards
|
|
23
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-UJWYE7VL.js";
|
|
23
|
+
import {
|
|
24
|
+
requestCapability
|
|
25
|
+
} from "../chunk-RSX4SCPN.js";
|
|
24
26
|
import {
|
|
25
27
|
findPeer,
|
|
26
28
|
getConfigDir,
|
|
@@ -45,17 +47,19 @@ import {
|
|
|
45
47
|
} from "../chunk-UOGDK2S2.js";
|
|
46
48
|
import {
|
|
47
49
|
bootstrapAgent,
|
|
48
|
-
generateKeyPair,
|
|
49
50
|
getBalance,
|
|
50
51
|
getTransactions,
|
|
51
52
|
holdEscrow,
|
|
52
|
-
loadKeyPair,
|
|
53
53
|
openCreditDb,
|
|
54
|
-
releaseEscrow
|
|
54
|
+
releaseEscrow
|
|
55
|
+
} from "../chunk-QVV2P3FN.js";
|
|
56
|
+
import {
|
|
57
|
+
generateKeyPair,
|
|
58
|
+
loadKeyPair,
|
|
55
59
|
saveKeyPair,
|
|
56
60
|
signEscrowReceipt,
|
|
57
61
|
verifyEscrowReceipt
|
|
58
|
-
} from "../chunk-
|
|
62
|
+
} from "../chunk-QO67IGCW.js";
|
|
59
63
|
import {
|
|
60
64
|
AgentBnBError,
|
|
61
65
|
AnyCardSchema,
|
|
@@ -1526,7 +1530,7 @@ var AgentRuntime = class {
|
|
|
1526
1530
|
}
|
|
1527
1531
|
const modes = /* @__PURE__ */ new Map();
|
|
1528
1532
|
if (this.conductorEnabled) {
|
|
1529
|
-
const { ConductorMode } = await import("../conductor-mode-
|
|
1533
|
+
const { ConductorMode } = await import("../conductor-mode-XU7ONJWC.js");
|
|
1530
1534
|
const { registerConductorCard, CONDUCTOR_OWNER } = await import("../card-IE5UV5QX.js");
|
|
1531
1535
|
const { loadPeers: loadPeers2 } = await import("../peers-G36URZYB.js");
|
|
1532
1536
|
registerConductorCard(this.registryDb);
|
|
@@ -1646,13 +1650,19 @@ function createGatewayServer(opts) {
|
|
|
1646
1650
|
} = opts;
|
|
1647
1651
|
const fastify = Fastify({ logger: !silent });
|
|
1648
1652
|
const tokenSet = new Set(tokens);
|
|
1649
|
-
fastify.addHook("onRequest", async (request
|
|
1653
|
+
fastify.addHook("onRequest", async (request) => {
|
|
1650
1654
|
if (request.method === "GET" && request.url === "/health") return;
|
|
1651
1655
|
const auth = request.headers.authorization;
|
|
1652
1656
|
if (auth && auth.startsWith("Bearer ")) {
|
|
1653
1657
|
const token = auth.slice("Bearer ".length).trim();
|
|
1654
|
-
if (tokenSet.has(token))
|
|
1658
|
+
if (tokenSet.has(token)) {
|
|
1659
|
+
request._authenticated = true;
|
|
1660
|
+
}
|
|
1655
1661
|
}
|
|
1662
|
+
});
|
|
1663
|
+
fastify.addHook("preHandler", async (request, reply) => {
|
|
1664
|
+
if (request._authenticated) return;
|
|
1665
|
+
if (request.method === "GET" && request.url === "/health") return;
|
|
1656
1666
|
const agentId = request.headers["x-agent-id"];
|
|
1657
1667
|
const publicKeyHex = request.headers["x-agent-public-key"];
|
|
1658
1668
|
const signature = request.headers["x-agent-signature"];
|
|
@@ -1660,8 +1670,10 @@ function createGatewayServer(opts) {
|
|
|
1660
1670
|
try {
|
|
1661
1671
|
const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
|
|
1662
1672
|
const body = request.body;
|
|
1663
|
-
|
|
1664
|
-
|
|
1673
|
+
if (body && typeof body === "object") {
|
|
1674
|
+
const valid = verifyEscrowReceipt(body, signature, publicKeyBuf);
|
|
1675
|
+
if (valid) return;
|
|
1676
|
+
}
|
|
1665
1677
|
} catch {
|
|
1666
1678
|
}
|
|
1667
1679
|
}
|
|
@@ -3458,6 +3470,7 @@ program.command("request [card-id]").description("Request a capability from anot
|
|
|
3458
3470
|
let gatewayUrl;
|
|
3459
3471
|
let token;
|
|
3460
3472
|
let isRemoteRequest = false;
|
|
3473
|
+
let targetOwner;
|
|
3461
3474
|
const identityAuth = loadIdentityAuth(config.owner);
|
|
3462
3475
|
if (opts.peer) {
|
|
3463
3476
|
const peer = findPeer(opts.peer);
|
|
@@ -3468,6 +3481,7 @@ program.command("request [card-id]").description("Request a capability from anot
|
|
|
3468
3481
|
gatewayUrl = peer.url;
|
|
3469
3482
|
token = peer.token;
|
|
3470
3483
|
isRemoteRequest = true;
|
|
3484
|
+
targetOwner = opts.peer;
|
|
3471
3485
|
} else {
|
|
3472
3486
|
const db = openDatabase(config.db_path);
|
|
3473
3487
|
let localCard;
|
|
@@ -3499,16 +3513,24 @@ program.command("request [card-id]").description("Request a capability from anot
|
|
|
3499
3513
|
console.error(`Error: cannot reach registry: ${err.message}`);
|
|
3500
3514
|
process.exit(1);
|
|
3501
3515
|
}
|
|
3502
|
-
|
|
3503
|
-
|
|
3516
|
+
targetOwner = remoteCard.owner ?? remoteCard.agent_name;
|
|
3517
|
+
if (remoteCard.gateway_url && typeof remoteCard.gateway_url === "string") {
|
|
3518
|
+
gatewayUrl = remoteCard.gateway_url;
|
|
3519
|
+
} else if (targetOwner && config.registry) {
|
|
3520
|
+
gatewayUrl = "";
|
|
3521
|
+
} else {
|
|
3522
|
+
console.error("Error: remote card has no gateway_url and no relay available. The provider needs to re-publish with `agentbnb sync`.");
|
|
3504
3523
|
process.exit(1);
|
|
3505
3524
|
}
|
|
3506
|
-
gatewayUrl = remoteCard.gateway_url;
|
|
3507
3525
|
token = "";
|
|
3508
3526
|
isRemoteRequest = true;
|
|
3509
3527
|
if (!opts.json) {
|
|
3510
3528
|
const displayName = remoteCard.name ?? remoteCard.agent_name ?? cardId;
|
|
3511
|
-
|
|
3529
|
+
if (gatewayUrl) {
|
|
3530
|
+
console.log(`Found remote card: ${displayName} @ ${gatewayUrl}`);
|
|
3531
|
+
} else {
|
|
3532
|
+
console.log(`Found remote card: ${displayName} (relay-only)`);
|
|
3533
|
+
}
|
|
3512
3534
|
}
|
|
3513
3535
|
}
|
|
3514
3536
|
}
|
|
@@ -3552,48 +3574,97 @@ program.command("request [card-id]").description("Request a capability from anot
|
|
|
3552
3574
|
process.exit(1);
|
|
3553
3575
|
}
|
|
3554
3576
|
}
|
|
3555
|
-
|
|
3556
|
-
const result = await requestCapability({
|
|
3557
|
-
gatewayUrl,
|
|
3558
|
-
token,
|
|
3559
|
-
cardId,
|
|
3560
|
-
params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
|
|
3561
|
-
escrowReceipt,
|
|
3562
|
-
identity: identityAuth
|
|
3563
|
-
});
|
|
3577
|
+
const settleEscrow = () => {
|
|
3564
3578
|
if (useReceipt && escrowId) {
|
|
3565
3579
|
const configDir = getConfigDir();
|
|
3566
3580
|
const creditDb = openCreditDb(join4(configDir, "credit.db"));
|
|
3567
3581
|
creditDb.pragma("busy_timeout = 5000");
|
|
3568
3582
|
try {
|
|
3569
3583
|
settleRequesterEscrow(creditDb, escrowId);
|
|
3570
|
-
if (!opts.json) {
|
|
3571
|
-
console.log(`Escrow settled: ${opts.cost} credits deducted.`);
|
|
3572
|
-
}
|
|
3584
|
+
if (!opts.json) console.log(`Escrow settled: ${opts.cost} credits deducted.`);
|
|
3573
3585
|
} finally {
|
|
3574
3586
|
creditDb.close();
|
|
3575
3587
|
}
|
|
3576
3588
|
}
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
} else {
|
|
3580
|
-
console.log("Result:");
|
|
3581
|
-
console.log(typeof result === "string" ? result : JSON.stringify(result, null, 2));
|
|
3582
|
-
}
|
|
3583
|
-
} catch (err) {
|
|
3589
|
+
};
|
|
3590
|
+
const releaseEscrow2 = () => {
|
|
3584
3591
|
if (useReceipt && escrowId) {
|
|
3585
3592
|
const configDir = getConfigDir();
|
|
3586
3593
|
const creditDb = openCreditDb(join4(configDir, "credit.db"));
|
|
3587
3594
|
creditDb.pragma("busy_timeout = 5000");
|
|
3588
3595
|
try {
|
|
3589
3596
|
releaseRequesterEscrow(creditDb, escrowId);
|
|
3590
|
-
if (!opts.json)
|
|
3591
|
-
console.log("Escrow released: credits refunded.");
|
|
3592
|
-
}
|
|
3597
|
+
if (!opts.json) console.log("Escrow released: credits refunded.");
|
|
3593
3598
|
} finally {
|
|
3594
3599
|
creditDb.close();
|
|
3595
3600
|
}
|
|
3596
3601
|
}
|
|
3602
|
+
};
|
|
3603
|
+
const printResult = (result) => {
|
|
3604
|
+
if (opts.json) {
|
|
3605
|
+
console.log(JSON.stringify({ success: true, result }, null, 2));
|
|
3606
|
+
} else {
|
|
3607
|
+
console.log("Result:");
|
|
3608
|
+
console.log(typeof result === "string" ? result : JSON.stringify(result, null, 2));
|
|
3609
|
+
}
|
|
3610
|
+
};
|
|
3611
|
+
const isNetworkError = (err) => {
|
|
3612
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3613
|
+
return msg.includes("NETWORK_ERROR") || msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("Network error");
|
|
3614
|
+
};
|
|
3615
|
+
const tryViaRelay = async () => {
|
|
3616
|
+
const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
|
|
3617
|
+
const { requestViaRelay } = await import("../client-IOTK6GOS.js");
|
|
3618
|
+
const tempRelay = new RelayClient({
|
|
3619
|
+
registryUrl: config.registry,
|
|
3620
|
+
owner: config.owner,
|
|
3621
|
+
token: config.token,
|
|
3622
|
+
card: { id: config.owner, owner: config.owner },
|
|
3623
|
+
onRequest: async () => ({ error: { code: -32601, message: "Not serving" } }),
|
|
3624
|
+
silent: true
|
|
3625
|
+
});
|
|
3626
|
+
try {
|
|
3627
|
+
await tempRelay.connect();
|
|
3628
|
+
const result = await requestViaRelay(tempRelay, {
|
|
3629
|
+
targetOwner,
|
|
3630
|
+
cardId,
|
|
3631
|
+
skillId: opts.skill,
|
|
3632
|
+
params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
|
|
3633
|
+
escrowReceipt
|
|
3634
|
+
});
|
|
3635
|
+
return result;
|
|
3636
|
+
} finally {
|
|
3637
|
+
tempRelay.disconnect();
|
|
3638
|
+
}
|
|
3639
|
+
};
|
|
3640
|
+
try {
|
|
3641
|
+
let result;
|
|
3642
|
+
if (!gatewayUrl && isRemoteRequest && config.registry && targetOwner) {
|
|
3643
|
+
if (!opts.json) console.log("No gateway URL, requesting via relay...");
|
|
3644
|
+
result = await tryViaRelay();
|
|
3645
|
+
} else {
|
|
3646
|
+
try {
|
|
3647
|
+
result = await requestCapability({
|
|
3648
|
+
gatewayUrl,
|
|
3649
|
+
token,
|
|
3650
|
+
cardId,
|
|
3651
|
+
params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
|
|
3652
|
+
escrowReceipt,
|
|
3653
|
+
identity: identityAuth
|
|
3654
|
+
});
|
|
3655
|
+
} catch (directErr) {
|
|
3656
|
+
if (isNetworkError(directErr) && isRemoteRequest && config.registry && targetOwner) {
|
|
3657
|
+
if (!opts.json) console.log("Direct connection failed, trying relay...");
|
|
3658
|
+
result = await tryViaRelay();
|
|
3659
|
+
} else {
|
|
3660
|
+
throw directErr;
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
settleEscrow();
|
|
3665
|
+
printResult(result);
|
|
3666
|
+
} catch (err) {
|
|
3667
|
+
releaseEscrow2();
|
|
3597
3668
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3598
3669
|
if (opts.json) {
|
|
3599
3670
|
console.log(JSON.stringify({ success: false, error: msg }, null, 2));
|
|
@@ -3643,7 +3714,7 @@ Active Escrows (${heldEscrows.length}):`);
|
|
|
3643
3714
|
}
|
|
3644
3715
|
}
|
|
3645
3716
|
});
|
|
3646
|
-
program.command("serve").description("Start the AgentBnB gateway server").option("--port <port>", "Port to listen on (overrides config)").option("--handler-url <url>", "Local capability handler URL", "http://localhost:8080").option("--skills-yaml <path>", "Path to skills.yaml (default: ~/.agentbnb/skills.yaml)").option("--registry-port <port>", "Public registry API port (0 to disable)", "7701").option("--registry <url>", "Connect to remote registry via WebSocket relay (e.g., hub.agentbnb.dev)").option("--conductor", "Enable Conductor orchestration mode").option("--announce", "Announce this gateway on the local network via mDNS").action(async (opts) => {
|
|
3717
|
+
program.command("serve").description("Start the AgentBnB gateway server").option("--port <port>", "Port to listen on (overrides config)").option("--handler-url <url>", "Local capability handler URL", "http://localhost:8080").option("--skills-yaml <path>", "Path to skills.yaml (default: ~/.agentbnb/skills.yaml)").option("--registry-port <port>", "Public registry API port (0 to disable)", "7701").option("--registry <url>", "Connect to remote registry via WebSocket relay (e.g., hub.agentbnb.dev)").option("--conductor", "Enable Conductor orchestration mode").option("--announce", "Announce this gateway on the local network via mDNS").option("--no-relay", "Do not auto-connect to remote registry relay").action(async (opts) => {
|
|
3647
3718
|
const config = loadConfig();
|
|
3648
3719
|
if (!config) {
|
|
3649
3720
|
console.error("Error: not initialized. Run `agentbnb init` first.");
|
|
@@ -3728,9 +3799,10 @@ program.command("serve").description("Start the AgentBnB gateway server").option
|
|
|
3728
3799
|
console.log(`WebSocket relay active on /ws`);
|
|
3729
3800
|
}
|
|
3730
3801
|
}
|
|
3731
|
-
|
|
3802
|
+
const relayUrl = opts.registry ?? config.registry;
|
|
3803
|
+
if (relayUrl && opts.relay !== false) {
|
|
3732
3804
|
const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
|
|
3733
|
-
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-
|
|
3805
|
+
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-GDGBU6DJ.js");
|
|
3734
3806
|
const cards = listCards(runtime.registryDb, config.owner);
|
|
3735
3807
|
const card = cards[0] ?? {
|
|
3736
3808
|
id: config.owner,
|
|
@@ -3745,7 +3817,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
|
|
|
3745
3817
|
availability: { online: true }
|
|
3746
3818
|
};
|
|
3747
3819
|
relayClient = new RelayClient({
|
|
3748
|
-
registryUrl:
|
|
3820
|
+
registryUrl: relayUrl,
|
|
3749
3821
|
owner: config.owner,
|
|
3750
3822
|
token: config.token,
|
|
3751
3823
|
card,
|
|
@@ -3769,9 +3841,9 @@ program.command("serve").description("Start the AgentBnB gateway server").option
|
|
|
3769
3841
|
});
|
|
3770
3842
|
try {
|
|
3771
3843
|
await relayClient.connect();
|
|
3772
|
-
console.log(`Connected to registry: ${opts.registry}`);
|
|
3844
|
+
console.log(`Connected to registry: ${relayUrl}${opts.registry ? "" : " (auto)"}`);
|
|
3773
3845
|
} catch (err) {
|
|
3774
|
-
console.warn(`Warning: could not connect to registry ${
|
|
3846
|
+
console.warn(`Warning: could not connect to registry ${relayUrl}: ${err instanceof Error ? err.message : err}`);
|
|
3775
3847
|
console.warn("Will auto-reconnect in background...");
|
|
3776
3848
|
}
|
|
3777
3849
|
}
|
|
@@ -3999,7 +4071,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
|
|
|
3999
4071
|
}
|
|
4000
4072
|
});
|
|
4001
4073
|
program.command("conduct <task>").description("Orchestrate a complex task across the AgentBnB network").option("--plan-only", "Show execution plan without executing").option("--max-budget <credits>", "Maximum credits to spend", "100").option("--json", "Output as JSON").action(async (task, opts) => {
|
|
4002
|
-
const { conductAction } = await import("../conduct-
|
|
4074
|
+
const { conductAction } = await import("../conduct-IQYAT6ZU.js");
|
|
4003
4075
|
const result = await conductAction(task, opts);
|
|
4004
4076
|
if (opts.json) {
|
|
4005
4077
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4,10 +4,11 @@ import {
|
|
|
4
4
|
decompose,
|
|
5
5
|
matchSubTasks,
|
|
6
6
|
orchestrate
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HEVXCYCY.js";
|
|
8
8
|
import {
|
|
9
9
|
BudgetManager
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UJWYE7VL.js";
|
|
11
|
+
import "./chunk-RSX4SCPN.js";
|
|
11
12
|
import {
|
|
12
13
|
loadConfig,
|
|
13
14
|
loadPeers
|
|
@@ -17,7 +18,8 @@ import {
|
|
|
17
18
|
} from "./chunk-UOGDK2S2.js";
|
|
18
19
|
import {
|
|
19
20
|
openCreditDb
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-QVV2P3FN.js";
|
|
22
|
+
import "./chunk-QO67IGCW.js";
|
|
21
23
|
import "./chunk-XA63SD4T.js";
|
|
22
24
|
|
|
23
25
|
// src/cli/conduct.ts
|
|
@@ -3,12 +3,14 @@ import {
|
|
|
3
3
|
decompose,
|
|
4
4
|
matchSubTasks,
|
|
5
5
|
orchestrate
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HEVXCYCY.js";
|
|
7
7
|
import {
|
|
8
8
|
BudgetManager
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UJWYE7VL.js";
|
|
10
|
+
import "./chunk-RSX4SCPN.js";
|
|
10
11
|
import "./chunk-BEI5MTNZ.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-QVV2P3FN.js";
|
|
13
|
+
import "./chunk-QO67IGCW.js";
|
|
12
14
|
import "./chunk-XA63SD4T.js";
|
|
13
15
|
|
|
14
16
|
// src/conductor/conductor-mode.ts
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeCapabilityRequest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CUVIWPQO.js";
|
|
4
4
|
import "./chunk-UOGDK2S2.js";
|
|
5
|
-
import "./chunk-
|
|
5
|
+
import "./chunk-QVV2P3FN.js";
|
|
6
|
+
import "./chunk-QO67IGCW.js";
|
|
6
7
|
import "./chunk-XA63SD4T.js";
|
|
7
8
|
export {
|
|
8
9
|
executeCapabilityRequest
|
package/dist/index.js
CHANGED
|
@@ -943,13 +943,19 @@ function createGatewayServer(opts) {
|
|
|
943
943
|
} = opts;
|
|
944
944
|
const fastify = Fastify({ logger: !silent });
|
|
945
945
|
const tokenSet = new Set(tokens);
|
|
946
|
-
fastify.addHook("onRequest", async (request
|
|
946
|
+
fastify.addHook("onRequest", async (request) => {
|
|
947
947
|
if (request.method === "GET" && request.url === "/health") return;
|
|
948
948
|
const auth = request.headers.authorization;
|
|
949
949
|
if (auth && auth.startsWith("Bearer ")) {
|
|
950
950
|
const token = auth.slice("Bearer ".length).trim();
|
|
951
|
-
if (tokenSet.has(token))
|
|
951
|
+
if (tokenSet.has(token)) {
|
|
952
|
+
request._authenticated = true;
|
|
953
|
+
}
|
|
952
954
|
}
|
|
955
|
+
});
|
|
956
|
+
fastify.addHook("preHandler", async (request, reply) => {
|
|
957
|
+
if (request._authenticated) return;
|
|
958
|
+
if (request.method === "GET" && request.url === "/health") return;
|
|
953
959
|
const agentId = request.headers["x-agent-id"];
|
|
954
960
|
const publicKeyHex = request.headers["x-agent-public-key"];
|
|
955
961
|
const signature = request.headers["x-agent-signature"];
|
|
@@ -957,8 +963,10 @@ function createGatewayServer(opts) {
|
|
|
957
963
|
try {
|
|
958
964
|
const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
|
|
959
965
|
const body = request.body;
|
|
960
|
-
|
|
961
|
-
|
|
966
|
+
if (body && typeof body === "object") {
|
|
967
|
+
const valid = verifyEscrowReceipt(body, signature, publicKeyBuf);
|
|
968
|
+
if (valid) return;
|
|
969
|
+
}
|
|
962
970
|
} catch {
|
|
963
971
|
}
|
|
964
972
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentbnb",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "P2P Agent Capability Sharing Protocol — Airbnb for AI agent pipelines",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -68,7 +68,10 @@
|
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@fastify/cors": "^11.2.0",
|
|
70
70
|
"@fastify/static": "^9.0.0",
|
|
71
|
+
"@fastify/swagger": "^9.7.0",
|
|
72
|
+
"@fastify/swagger-ui": "^5.2.5",
|
|
71
73
|
"@fastify/websocket": "^11.2.0",
|
|
74
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
72
75
|
"better-sqlite3": "^11.6.0",
|
|
73
76
|
"bonjour-service": "^1.3.0",
|
|
74
77
|
"commander": "^12.1.0",
|