agentbnb 3.1.2 → 3.1.4

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.
@@ -3,7 +3,7 @@ import {
3
3
  requestCapability,
4
4
  scorePeers,
5
5
  searchCards
6
- } from "./chunk-KTHJ5F3X.js";
6
+ } from "./chunk-IZZ4FP45.js";
7
7
 
8
8
  // src/conductor/task-decomposer.ts
9
9
  import { randomUUID } from "crypto";
@@ -5,8 +5,9 @@ import {
5
5
  getBalance,
6
6
  holdEscrow,
7
7
  releaseEscrow,
8
- settleEscrow
9
- } from "./chunk-QVV2P3FN.js";
8
+ settleEscrow,
9
+ signEscrowReceipt
10
+ } from "./chunk-QHQPXO67.js";
10
11
  import {
11
12
  AgentBnBError
12
13
  } from "./chunk-XA63SD4T.js";
@@ -150,7 +151,7 @@ function filterCards(db, filters) {
150
151
  // src/gateway/client.ts
151
152
  import { randomUUID as randomUUID2 } from "crypto";
152
153
  async function requestCapability(opts) {
153
- const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt } = opts;
154
+ const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
154
155
  const id = randomUUID2();
155
156
  const payload = {
156
157
  jsonrpc: "2.0",
@@ -162,16 +163,22 @@ async function requestCapability(opts) {
162
163
  ...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
163
164
  }
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
+ }
165
175
  const controller = new AbortController();
166
176
  const timer = setTimeout(() => controller.abort(), timeoutMs);
167
177
  let response;
168
178
  try {
169
179
  response = await fetch(`${gatewayUrl}/rpc`, {
170
180
  method: "POST",
171
- headers: {
172
- "Content-Type": "application/json",
173
- Authorization: `Bearer ${token}`
174
- },
181
+ headers,
175
182
  body: JSON.stringify(payload),
176
183
  signal: controller.signal
177
184
  });
@@ -2,6 +2,58 @@ 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
+
5
57
  // src/credit/escrow.ts
6
58
  import { randomUUID } from "crypto";
7
59
  function holdEscrow(db, owner, amount, cardId) {
@@ -180,6 +232,11 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
180
232
  }
181
233
 
182
234
  export {
235
+ generateKeyPair,
236
+ saveKeyPair,
237
+ loadKeyPair,
238
+ signEscrowReceipt,
239
+ verifyEscrowReceipt,
183
240
  holdEscrow,
184
241
  settleEscrow,
185
242
  releaseEscrow,
@@ -9,8 +9,9 @@ import {
9
9
  holdEscrow,
10
10
  recordEarning,
11
11
  releaseEscrow,
12
- settleEscrow
13
- } from "./chunk-QVV2P3FN.js";
12
+ settleEscrow,
13
+ verifyEscrowReceipt
14
+ } from "./chunk-QHQPXO67.js";
14
15
  import {
15
16
  AgentBnBError
16
17
  } from "./chunk-XA63SD4T.js";
@@ -18,58 +19,6 @@ import {
18
19
  // src/gateway/execute.ts
19
20
  import { randomUUID } from "crypto";
20
21
 
21
- // src/credit/signing.ts
22
- import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
23
- import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
24
- import { join } from "path";
25
- function generateKeyPair() {
26
- const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
27
- publicKeyEncoding: { type: "spki", format: "der" },
28
- privateKeyEncoding: { type: "pkcs8", format: "der" }
29
- });
30
- return {
31
- publicKey: Buffer.from(publicKey),
32
- privateKey: Buffer.from(privateKey)
33
- };
34
- }
35
- function saveKeyPair(configDir, keys) {
36
- const privatePath = join(configDir, "private.key");
37
- const publicPath = join(configDir, "public.key");
38
- writeFileSync(privatePath, keys.privateKey);
39
- chmodSync(privatePath, 384);
40
- writeFileSync(publicPath, keys.publicKey);
41
- }
42
- function loadKeyPair(configDir) {
43
- const privatePath = join(configDir, "private.key");
44
- const publicPath = join(configDir, "public.key");
45
- if (!existsSync(privatePath) || !existsSync(publicPath)) {
46
- throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
47
- }
48
- return {
49
- publicKey: readFileSync(publicPath),
50
- privateKey: readFileSync(privatePath)
51
- };
52
- }
53
- function canonicalJson(data) {
54
- return JSON.stringify(data, Object.keys(data).sort());
55
- }
56
- function signEscrowReceipt(data, privateKey) {
57
- const message = Buffer.from(canonicalJson(data), "utf-8");
58
- const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
59
- const signature = sign(null, message, keyObject);
60
- return signature.toString("base64url");
61
- }
62
- function verifyEscrowReceipt(data, signature, publicKey) {
63
- try {
64
- const message = Buffer.from(canonicalJson(data), "utf-8");
65
- const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
66
- const sigBuffer = Buffer.from(signature, "base64url");
67
- return verify(null, message, keyObject, sigBuffer);
68
- } catch {
69
- return false;
70
- }
71
- }
72
-
73
22
  // src/credit/settlement.ts
74
23
  function settleProviderEarning(providerDb, providerOwner, receipt) {
75
24
  recordEarning(
@@ -247,10 +196,6 @@ async function executeCapabilityRequest(opts) {
247
196
  }
248
197
 
249
198
  export {
250
- generateKeyPair,
251
- saveKeyPair,
252
- loadKeyPair,
253
- signEscrowReceipt,
254
199
  settleRequesterEscrow,
255
200
  releaseRequesterEscrow,
256
201
  executeCapabilityRequest
package/dist/cli/index.js CHANGED
@@ -1,13 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  executeCapabilityRequest,
4
- generateKeyPair,
5
- loadKeyPair,
6
4
  releaseRequesterEscrow,
7
- saveKeyPair,
8
- settleRequesterEscrow,
9
- signEscrowReceipt
10
- } from "../chunk-SVEZBIGE.js";
5
+ settleRequesterEscrow
6
+ } from "../chunk-QSPWE5AE.js";
11
7
  import {
12
8
  RelayMessageSchema
13
9
  } from "../chunk-3Y36WQDV.js";
@@ -24,7 +20,7 @@ import {
24
20
  requestCapability,
25
21
  resolvePendingRequest,
26
22
  searchCards
27
- } from "../chunk-KTHJ5F3X.js";
23
+ } from "../chunk-IZZ4FP45.js";
28
24
  import {
29
25
  findPeer,
30
26
  getConfigDir,
@@ -49,12 +45,17 @@ import {
49
45
  } from "../chunk-UOGDK2S2.js";
50
46
  import {
51
47
  bootstrapAgent,
48
+ generateKeyPair,
52
49
  getBalance,
53
50
  getTransactions,
54
51
  holdEscrow,
52
+ loadKeyPair,
55
53
  openCreditDb,
56
- releaseEscrow
57
- } from "../chunk-QVV2P3FN.js";
54
+ releaseEscrow,
55
+ saveKeyPair,
56
+ signEscrowReceipt,
57
+ verifyEscrowReceipt
58
+ } from "../chunk-QHQPXO67.js";
58
59
  import {
59
60
  AgentBnBError,
60
61
  AnyCardSchema,
@@ -1525,7 +1526,7 @@ var AgentRuntime = class {
1525
1526
  }
1526
1527
  const modes = /* @__PURE__ */ new Map();
1527
1528
  if (this.conductorEnabled) {
1528
- const { ConductorMode } = await import("../conductor-mode-6MIVMFBC.js");
1529
+ const { ConductorMode } = await import("../conductor-mode-IO45PWMI.js");
1529
1530
  const { registerConductorCard, CONDUCTOR_OWNER } = await import("../card-IE5UV5QX.js");
1530
1531
  const { loadPeers: loadPeers2 } = await import("../peers-G36URZYB.js");
1531
1532
  registerConductorCard(this.registryDb);
@@ -1648,22 +1649,27 @@ function createGatewayServer(opts) {
1648
1649
  fastify.addHook("onRequest", async (request, reply) => {
1649
1650
  if (request.method === "GET" && request.url === "/health") return;
1650
1651
  const auth = request.headers.authorization;
1651
- if (!auth || !auth.startsWith("Bearer ")) {
1652
- await reply.status(401).send({
1653
- jsonrpc: "2.0",
1654
- id: null,
1655
- error: { code: -32e3, message: "Unauthorized: missing token" }
1656
- });
1657
- return;
1658
- }
1659
- const token = auth.slice("Bearer ".length).trim();
1660
- if (!tokenSet.has(token)) {
1661
- await reply.status(401).send({
1662
- jsonrpc: "2.0",
1663
- id: null,
1664
- error: { code: -32e3, message: "Unauthorized: invalid token" }
1665
- });
1652
+ if (auth && auth.startsWith("Bearer ")) {
1653
+ const token = auth.slice("Bearer ".length).trim();
1654
+ if (tokenSet.has(token)) return;
1655
+ }
1656
+ const agentId = request.headers["x-agent-id"];
1657
+ const publicKeyHex = request.headers["x-agent-public-key"];
1658
+ const signature = request.headers["x-agent-signature"];
1659
+ if (agentId && publicKeyHex && signature) {
1660
+ try {
1661
+ const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
1662
+ const body = request.body;
1663
+ const valid = verifyEscrowReceipt(body, signature, publicKeyBuf);
1664
+ if (valid) return;
1665
+ } catch {
1666
+ }
1666
1667
  }
1668
+ await reply.status(401).send({
1669
+ jsonrpc: "2.0",
1670
+ id: null,
1671
+ error: { code: -32e3, message: "Unauthorized: provide Bearer token or X-Agent-Id/Signature headers" }
1672
+ });
1667
1673
  });
1668
1674
  fastify.get("/health", async () => {
1669
1675
  return { status: "ok", version: VERSION, uptime: process.uptime() };
@@ -2899,6 +2905,22 @@ async function confirm(question) {
2899
2905
  rl.close();
2900
2906
  }
2901
2907
  }
2908
+ function loadIdentityAuth(owner) {
2909
+ const configDir = getConfigDir();
2910
+ let keys;
2911
+ try {
2912
+ keys = loadKeyPair(configDir);
2913
+ } catch {
2914
+ keys = generateKeyPair();
2915
+ saveKeyPair(configDir, keys);
2916
+ }
2917
+ const identity = ensureIdentity(configDir, owner);
2918
+ return {
2919
+ agentId: identity.agent_id,
2920
+ publicKey: identity.public_key,
2921
+ privateKey: keys.privateKey
2922
+ };
2923
+ }
2902
2924
  function getLanIp() {
2903
2925
  const nets = networkInterfaces();
2904
2926
  for (const ifaces of Object.values(nets)) {
@@ -3434,6 +3456,7 @@ program.command("request [card-id]").description("Request a capability from anot
3434
3456
  let gatewayUrl;
3435
3457
  let token;
3436
3458
  let isRemoteRequest = false;
3459
+ let identityAuth;
3437
3460
  if (opts.peer) {
3438
3461
  const peer = findPeer(opts.peer);
3439
3462
  if (!peer) {
@@ -3443,6 +3466,7 @@ program.command("request [card-id]").description("Request a capability from anot
3443
3466
  gatewayUrl = peer.url;
3444
3467
  token = peer.token;
3445
3468
  isRemoteRequest = true;
3469
+ identityAuth = loadIdentityAuth(config.owner);
3446
3470
  } else {
3447
3471
  const db = openDatabase(config.db_path);
3448
3472
  let localCard;
@@ -3481,6 +3505,7 @@ program.command("request [card-id]").description("Request a capability from anot
3481
3505
  gatewayUrl = remoteCard.gateway_url;
3482
3506
  token = "";
3483
3507
  isRemoteRequest = true;
3508
+ identityAuth = loadIdentityAuth(config.owner);
3484
3509
  if (!opts.json) {
3485
3510
  const displayName = remoteCard.name ?? remoteCard.agent_name ?? cardId;
3486
3511
  console.log(`Found remote card: ${displayName} @ ${gatewayUrl}`);
@@ -3533,7 +3558,8 @@ program.command("request [card-id]").description("Request a capability from anot
3533
3558
  token,
3534
3559
  cardId,
3535
3560
  params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
3536
- escrowReceipt
3561
+ escrowReceipt,
3562
+ identity: identityAuth
3537
3563
  });
3538
3564
  if (useReceipt && escrowId) {
3539
3565
  const configDir = getConfigDir();
@@ -3704,7 +3730,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
3704
3730
  }
3705
3731
  if (opts.registry) {
3706
3732
  const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
3707
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-HM25IOG7.js");
3733
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-SWWEHV2K.js");
3708
3734
  const cards = listCards(runtime.registryDb, config.owner);
3709
3735
  const card = cards[0] ?? {
3710
3736
  id: config.owner,
@@ -3973,7 +3999,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
3973
3999
  }
3974
4000
  });
3975
4001
  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) => {
3976
- const { conductAction } = await import("../conduct-5XKKALNX.js");
4002
+ const { conductAction } = await import("../conduct-IEQ567ET.js");
3977
4003
  const result = await conductAction(task, opts);
3978
4004
  if (opts.json) {
3979
4005
  console.log(JSON.stringify(result, null, 2));
@@ -4,10 +4,10 @@ import {
4
4
  decompose,
5
5
  matchSubTasks,
6
6
  orchestrate
7
- } from "./chunk-P35546JW.js";
7
+ } from "./chunk-7OACGAFD.js";
8
8
  import {
9
9
  BudgetManager
10
- } from "./chunk-KTHJ5F3X.js";
10
+ } from "./chunk-IZZ4FP45.js";
11
11
  import {
12
12
  loadConfig,
13
13
  loadPeers
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-UOGDK2S2.js";
18
18
  import {
19
19
  openCreditDb
20
- } from "./chunk-QVV2P3FN.js";
20
+ } from "./chunk-QHQPXO67.js";
21
21
  import "./chunk-XA63SD4T.js";
22
22
 
23
23
  // src/cli/conduct.ts
@@ -3,12 +3,12 @@ import {
3
3
  decompose,
4
4
  matchSubTasks,
5
5
  orchestrate
6
- } from "./chunk-P35546JW.js";
6
+ } from "./chunk-7OACGAFD.js";
7
7
  import {
8
8
  BudgetManager
9
- } from "./chunk-KTHJ5F3X.js";
9
+ } from "./chunk-IZZ4FP45.js";
10
10
  import "./chunk-BEI5MTNZ.js";
11
- import "./chunk-QVV2P3FN.js";
11
+ import "./chunk-QHQPXO67.js";
12
12
  import "./chunk-XA63SD4T.js";
13
13
 
14
14
  // src/conductor/conductor-mode.ts
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  executeCapabilityRequest
3
- } from "./chunk-SVEZBIGE.js";
3
+ } from "./chunk-QSPWE5AE.js";
4
4
  import "./chunk-UOGDK2S2.js";
5
- import "./chunk-QVV2P3FN.js";
5
+ import "./chunk-QHQPXO67.js";
6
6
  import "./chunk-XA63SD4T.js";
7
7
  export {
8
8
  executeCapabilityRequest
package/dist/index.js CHANGED
@@ -946,22 +946,27 @@ function createGatewayServer(opts) {
946
946
  fastify.addHook("onRequest", async (request, reply) => {
947
947
  if (request.method === "GET" && request.url === "/health") return;
948
948
  const auth = request.headers.authorization;
949
- if (!auth || !auth.startsWith("Bearer ")) {
950
- await reply.status(401).send({
951
- jsonrpc: "2.0",
952
- id: null,
953
- error: { code: -32e3, message: "Unauthorized: missing token" }
954
- });
955
- return;
956
- }
957
- const token = auth.slice("Bearer ".length).trim();
958
- if (!tokenSet.has(token)) {
959
- await reply.status(401).send({
960
- jsonrpc: "2.0",
961
- id: null,
962
- error: { code: -32e3, message: "Unauthorized: invalid token" }
963
- });
949
+ if (auth && auth.startsWith("Bearer ")) {
950
+ const token = auth.slice("Bearer ".length).trim();
951
+ if (tokenSet.has(token)) return;
952
+ }
953
+ const agentId = request.headers["x-agent-id"];
954
+ const publicKeyHex = request.headers["x-agent-public-key"];
955
+ const signature = request.headers["x-agent-signature"];
956
+ if (agentId && publicKeyHex && signature) {
957
+ try {
958
+ const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
959
+ const body = request.body;
960
+ const valid = verifyEscrowReceipt(body, signature, publicKeyBuf);
961
+ if (valid) return;
962
+ } catch {
963
+ }
964
964
  }
965
+ await reply.status(401).send({
966
+ jsonrpc: "2.0",
967
+ id: null,
968
+ error: { code: -32e3, message: "Unauthorized: provide Bearer token or X-Agent-Id/Signature headers" }
969
+ });
965
970
  });
966
971
  fastify.get("/health", async () => {
967
972
  return { status: "ok", version: VERSION, uptime: process.uptime() };
@@ -1917,7 +1922,7 @@ function decompose(task, _availableCapabilities) {
1917
1922
  // src/gateway/client.ts
1918
1923
  import { randomUUID as randomUUID5 } from "crypto";
1919
1924
  async function requestCapability(opts) {
1920
- const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt } = opts;
1925
+ const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
1921
1926
  const id = randomUUID5();
1922
1927
  const payload = {
1923
1928
  jsonrpc: "2.0",
@@ -1929,16 +1934,22 @@ async function requestCapability(opts) {
1929
1934
  ...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
1930
1935
  }
1931
1936
  };
1937
+ const headers = { "Content-Type": "application/json" };
1938
+ if (identity) {
1939
+ const signature = signEscrowReceipt(payload, identity.privateKey);
1940
+ headers["X-Agent-Id"] = identity.agentId;
1941
+ headers["X-Agent-Public-Key"] = identity.publicKey;
1942
+ headers["X-Agent-Signature"] = signature;
1943
+ } else if (token) {
1944
+ headers["Authorization"] = `Bearer ${token}`;
1945
+ }
1932
1946
  const controller = new AbortController();
1933
1947
  const timer = setTimeout(() => controller.abort(), timeoutMs);
1934
1948
  let response;
1935
1949
  try {
1936
1950
  response = await fetch(`${gatewayUrl}/rpc`, {
1937
1951
  method: "POST",
1938
- headers: {
1939
- "Content-Type": "application/json",
1940
- Authorization: `Bearer ${token}`
1941
- },
1952
+ headers,
1942
1953
  body: JSON.stringify(payload),
1943
1954
  signal: controller.signal
1944
1955
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbnb",
3
- "version": "3.1.2",
3
+ "version": "3.1.4",
4
4
  "description": "P2P Agent Capability Sharing Protocol — Airbnb for AI agent pipelines",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",