agentbnb 3.1.2 → 3.1.3

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() };
@@ -3434,6 +3440,7 @@ program.command("request [card-id]").description("Request a capability from anot
3434
3440
  let gatewayUrl;
3435
3441
  let token;
3436
3442
  let isRemoteRequest = false;
3443
+ let identityAuth;
3437
3444
  if (opts.peer) {
3438
3445
  const peer = findPeer(opts.peer);
3439
3446
  if (!peer) {
@@ -3443,6 +3450,16 @@ program.command("request [card-id]").description("Request a capability from anot
3443
3450
  gatewayUrl = peer.url;
3444
3451
  token = peer.token;
3445
3452
  isRemoteRequest = true;
3453
+ const configDir = getConfigDir();
3454
+ const agentIdentity = loadIdentity(configDir);
3455
+ if (agentIdentity) {
3456
+ const keys = loadKeyPair(configDir);
3457
+ identityAuth = {
3458
+ agentId: agentIdentity.agent_id,
3459
+ publicKey: agentIdentity.public_key,
3460
+ privateKey: keys.privateKey
3461
+ };
3462
+ }
3446
3463
  } else {
3447
3464
  const db = openDatabase(config.db_path);
3448
3465
  let localCard;
@@ -3481,6 +3498,18 @@ program.command("request [card-id]").description("Request a capability from anot
3481
3498
  gatewayUrl = remoteCard.gateway_url;
3482
3499
  token = "";
3483
3500
  isRemoteRequest = true;
3501
+ const configDir = getConfigDir();
3502
+ const agentIdentity = loadIdentity(configDir);
3503
+ if (!agentIdentity) {
3504
+ console.error("Error: no agent identity found. Run `agentbnb init` first.");
3505
+ process.exit(1);
3506
+ }
3507
+ const keys = loadKeyPair(configDir);
3508
+ identityAuth = {
3509
+ agentId: agentIdentity.agent_id,
3510
+ publicKey: agentIdentity.public_key,
3511
+ privateKey: keys.privateKey
3512
+ };
3484
3513
  if (!opts.json) {
3485
3514
  const displayName = remoteCard.name ?? remoteCard.agent_name ?? cardId;
3486
3515
  console.log(`Found remote card: ${displayName} @ ${gatewayUrl}`);
@@ -3533,7 +3562,8 @@ program.command("request [card-id]").description("Request a capability from anot
3533
3562
  token,
3534
3563
  cardId,
3535
3564
  params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
3536
- escrowReceipt
3565
+ escrowReceipt,
3566
+ identity: identityAuth
3537
3567
  });
3538
3568
  if (useReceipt && escrowId) {
3539
3569
  const configDir = getConfigDir();
@@ -3704,7 +3734,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
3704
3734
  }
3705
3735
  if (opts.registry) {
3706
3736
  const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
3707
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-HM25IOG7.js");
3737
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-SWWEHV2K.js");
3708
3738
  const cards = listCards(runtime.registryDb, config.owner);
3709
3739
  const card = cards[0] ?? {
3710
3740
  id: config.owner,
@@ -3973,7 +4003,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
3973
4003
  }
3974
4004
  });
3975
4005
  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");
4006
+ const { conductAction } = await import("../conduct-IEQ567ET.js");
3977
4007
  const result = await conductAction(task, opts);
3978
4008
  if (opts.json) {
3979
4009
  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.3",
4
4
  "description": "P2P Agent Capability Sharing Protocol — Airbnb for AI agent pipelines",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",