agentbnb 3.1.1 → 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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CapabilityCardV2Schema
3
- } from "./chunk-7RU5INZI.js";
3
+ } from "./chunk-XA63SD4T.js";
4
4
 
5
5
  // src/conductor/card.ts
6
6
  var CONDUCTOR_OWNER = "agentbnb-conductor";
@@ -3,7 +3,7 @@ import {
3
3
  requestCapability,
4
4
  scorePeers,
5
5
  searchCards
6
- } from "./chunk-2ETVQXP7.js";
6
+ } from "./chunk-IZZ4FP45.js";
7
7
 
8
8
  // src/conductor/task-decomposer.ts
9
9
  import { randomUUID } from "crypto";
@@ -5,11 +5,12 @@ import {
5
5
  getBalance,
6
6
  holdEscrow,
7
7
  releaseEscrow,
8
- settleEscrow
9
- } from "./chunk-MZCNJ5PY.js";
8
+ settleEscrow,
9
+ signEscrowReceipt
10
+ } from "./chunk-QHQPXO67.js";
10
11
  import {
11
12
  AgentBnBError
12
- } from "./chunk-7RU5INZI.js";
13
+ } from "./chunk-XA63SD4T.js";
13
14
 
14
15
  // src/autonomy/tiers.ts
15
16
  import { randomUUID } from "crypto";
@@ -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
  });
@@ -1,6 +1,58 @@
1
1
  import {
2
2
  AgentBnBError
3
- } from "./chunk-7RU5INZI.js";
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
+ }
4
56
 
5
57
  // src/credit/escrow.ts
6
58
  import { randomUUID } from "crypto";
@@ -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,
@@ -2,74 +2,23 @@ import {
2
2
  getCard,
3
3
  insertRequestLog,
4
4
  updateReputation
5
- } from "./chunk-QAY6XTT7.js";
5
+ } from "./chunk-UOGDK2S2.js";
6
6
  import {
7
7
  confirmEscrowDebit,
8
8
  getBalance,
9
9
  holdEscrow,
10
10
  recordEarning,
11
11
  releaseEscrow,
12
- settleEscrow
13
- } from "./chunk-MZCNJ5PY.js";
12
+ settleEscrow,
13
+ verifyEscrowReceipt
14
+ } from "./chunk-QHQPXO67.js";
14
15
  import {
15
16
  AgentBnBError
16
- } from "./chunk-7RU5INZI.js";
17
+ } from "./chunk-XA63SD4T.js";
17
18
 
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
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AgentBnBError,
3
3
  CapabilityCardSchema
4
- } from "./chunk-7RU5INZI.js";
4
+ } from "./chunk-XA63SD4T.js";
5
5
 
6
6
  // src/registry/request-log.ts
7
7
  var SINCE_MS = {
@@ -39,6 +39,8 @@ var CapabilityCardSchema = z.object({
39
39
  * never transmitted beyond the local store.
40
40
  */
41
41
  _internal: z.record(z.unknown()).optional(),
42
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
43
+ gateway_url: z.string().url().optional(),
42
44
  metadata: z.object({
43
45
  apis_used: z.array(z.string()).optional(),
44
46
  avg_latency_ms: z.number().nonnegative().optional(),
@@ -103,6 +105,8 @@ var CapabilityCardV2Schema = z.object({
103
105
  * never transmitted beyond the local store.
104
106
  */
105
107
  _internal: z.record(z.unknown()).optional(),
108
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
109
+ gateway_url: z.string().url().optional(),
106
110
  created_at: z.string().datetime().optional(),
107
111
  updated_at: z.string().datetime().optional()
108
112
  });
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-MGHI67GR.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-2ETVQXP7.js";
23
+ } from "../chunk-IZZ4FP45.js";
28
24
  import {
29
25
  findPeer,
30
26
  getConfigDir,
@@ -46,20 +42,25 @@ import {
46
42
  updateCard,
47
43
  updateSkillAvailability,
48
44
  updateSkillIdleRate
49
- } from "../chunk-QAY6XTT7.js";
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-MZCNJ5PY.js";
54
+ releaseEscrow,
55
+ saveKeyPair,
56
+ signEscrowReceipt,
57
+ verifyEscrowReceipt
58
+ } from "../chunk-QHQPXO67.js";
58
59
  import {
59
60
  AgentBnBError,
60
61
  AnyCardSchema,
61
62
  CapabilityCardV2Schema
62
- } from "../chunk-7RU5INZI.js";
63
+ } from "../chunk-XA63SD4T.js";
63
64
 
64
65
  // src/cli/index.ts
65
66
  import { Command } from "commander";
@@ -1525,8 +1526,8 @@ var AgentRuntime = class {
1525
1526
  }
1526
1527
  const modes = /* @__PURE__ */ new Map();
1527
1528
  if (this.conductorEnabled) {
1528
- const { ConductorMode } = await import("../conductor-mode-GPLAM2XO.js");
1529
- const { registerConductorCard, CONDUCTOR_OWNER } = await import("../card-EWIXC377.js");
1529
+ const { ConductorMode } = await import("../conductor-mode-IO45PWMI.js");
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);
1532
1533
  const resolveAgentUrl = (owner) => {
@@ -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() };
@@ -3161,11 +3167,12 @@ program.command("publish <card.json>").description("Publish a Capability Card to
3161
3167
  let remoteSuccess = false;
3162
3168
  if (registryUrl) {
3163
3169
  const url = `${registryUrl.replace(/\/$/, "")}/cards`;
3170
+ const remoteCard = { ...card, gateway_url: config.gateway_url };
3164
3171
  try {
3165
3172
  const response = await fetch(url, {
3166
3173
  method: "POST",
3167
3174
  headers: { "Content-Type": "application/json" },
3168
- body: JSON.stringify(card)
3175
+ body: JSON.stringify(remoteCard)
3169
3176
  });
3170
3177
  if (!response.ok) {
3171
3178
  const body = await response.text();
@@ -3190,6 +3197,77 @@ program.command("publish <card.json>").description("Publish a Capability Card to
3190
3197
  } else if (!registryUrl) {
3191
3198
  }
3192
3199
  });
3200
+ program.command("sync").description("Push all local capability cards to the configured remote registry").option("--registry <url>", "Remote registry URL (overrides config.registry)").option("--json", "Output as JSON").action(async (opts) => {
3201
+ const config = loadConfig();
3202
+ if (!config) {
3203
+ console.error("Error: not initialized. Run `agentbnb init` first.");
3204
+ process.exit(1);
3205
+ }
3206
+ const registryUrl = opts.registry ?? config.registry;
3207
+ if (!registryUrl) {
3208
+ console.error("Error: no remote registry configured.");
3209
+ console.error("Set one with: agentbnb config set registry <url>");
3210
+ process.exit(1);
3211
+ }
3212
+ const db = openDatabase(config.db_path);
3213
+ let localCards;
3214
+ try {
3215
+ localCards = listCards(db);
3216
+ } finally {
3217
+ db.close();
3218
+ }
3219
+ if (localCards.length === 0) {
3220
+ if (opts.json) {
3221
+ console.log(JSON.stringify({ synced: 0, failed: 0, registry: registryUrl }));
3222
+ } else {
3223
+ console.log("No local cards to sync.");
3224
+ }
3225
+ return;
3226
+ }
3227
+ const url = `${registryUrl.replace(/\/$/, "")}/cards`;
3228
+ let synced = 0;
3229
+ let failed = 0;
3230
+ const results = [];
3231
+ for (const card of localCards) {
3232
+ const { _internal: _, ...publicCard } = card;
3233
+ const remoteCard = { ...publicCard, gateway_url: config.gateway_url };
3234
+ const displayName = card.name ?? card.agent_name ?? card.id;
3235
+ try {
3236
+ const response = await fetch(url, {
3237
+ method: "POST",
3238
+ headers: { "Content-Type": "application/json" },
3239
+ body: JSON.stringify(remoteCard)
3240
+ });
3241
+ if (response.ok) {
3242
+ synced++;
3243
+ results.push({ id: card.id, name: displayName, ok: true });
3244
+ if (!opts.json) {
3245
+ console.log(` Synced: ${displayName} (${card.id.slice(0, 8)}...)`);
3246
+ }
3247
+ } else {
3248
+ const body = await response.text();
3249
+ failed++;
3250
+ results.push({ id: card.id, name: displayName, ok: false, error: `${response.status}: ${body}` });
3251
+ if (!opts.json) {
3252
+ console.error(` Failed: ${displayName} \u2014 ${response.status}`);
3253
+ }
3254
+ }
3255
+ } catch (err) {
3256
+ failed++;
3257
+ const msg = err instanceof Error ? err.message : String(err);
3258
+ results.push({ id: card.id, name: displayName, ok: false, error: msg });
3259
+ if (!opts.json) {
3260
+ console.error(` Failed: ${displayName} \u2014 ${msg}`);
3261
+ }
3262
+ }
3263
+ }
3264
+ if (opts.json) {
3265
+ console.log(JSON.stringify({ synced, failed, registry: registryUrl, results }, null, 2));
3266
+ } else {
3267
+ console.log(`
3268
+ Synced ${synced}/${localCards.length} cards to ${registryUrl}${failed > 0 ? ` (${failed} failed)` : ""}`);
3269
+ }
3270
+ });
3193
3271
  program.command("discover [query]").description("Search available capabilities in the registry").option("--level <level>", "Filter by level (1, 2, or 3)").option("--online", "Only show online capabilities").option("--local", "Browse for agents on the local network via mDNS").option("--registry <url>", "Remote registry URL to query (e.g., http://host:7701)").option("--tag <tag>", "Filter by metadata tag").option("--json", "Output as JSON").action(async (query, opts) => {
3194
3272
  if (opts.local) {
3195
3273
  const discovered = [];
@@ -3361,7 +3439,8 @@ program.command("request [card-id]").description("Request a capability from anot
3361
3439
  }
3362
3440
  let gatewayUrl;
3363
3441
  let token;
3364
- const isPeerRequest = !!opts.peer;
3442
+ let isRemoteRequest = false;
3443
+ let identityAuth;
3365
3444
  if (opts.peer) {
3366
3445
  const peer = findPeer(opts.peer);
3367
3446
  if (!peer) {
@@ -3370,13 +3449,76 @@ program.command("request [card-id]").description("Request a capability from anot
3370
3449
  }
3371
3450
  gatewayUrl = peer.url;
3372
3451
  token = peer.token;
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
+ }
3373
3463
  } else {
3374
- gatewayUrl = config.gateway_url;
3375
- token = config.token;
3464
+ const db = openDatabase(config.db_path);
3465
+ let localCard;
3466
+ try {
3467
+ localCard = db.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId) ? JSON.parse(db.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId).data) : void 0;
3468
+ } finally {
3469
+ db.close();
3470
+ }
3471
+ if (localCard) {
3472
+ gatewayUrl = config.gateway_url;
3473
+ token = config.token;
3474
+ } else {
3475
+ const registryUrl = config.registry;
3476
+ if (!registryUrl) {
3477
+ console.error("Error: card not found locally and no remote registry configured.");
3478
+ console.error("Set one with: agentbnb config set registry <url>");
3479
+ process.exit(1);
3480
+ }
3481
+ const cardUrl = `${registryUrl.replace(/\/$/, "")}/cards/${cardId}`;
3482
+ let remoteCard;
3483
+ try {
3484
+ const resp = await fetch(cardUrl);
3485
+ if (!resp.ok) {
3486
+ console.error(`Error: card ${cardId} not found on remote registry (${resp.status}).`);
3487
+ process.exit(1);
3488
+ }
3489
+ remoteCard = await resp.json();
3490
+ } catch (err) {
3491
+ console.error(`Error: cannot reach registry: ${err.message}`);
3492
+ process.exit(1);
3493
+ }
3494
+ if (!remoteCard.gateway_url || typeof remoteCard.gateway_url !== "string") {
3495
+ console.error("Error: remote card has no gateway_url. The provider needs to re-publish with `agentbnb sync`.");
3496
+ process.exit(1);
3497
+ }
3498
+ gatewayUrl = remoteCard.gateway_url;
3499
+ token = "";
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
+ };
3513
+ if (!opts.json) {
3514
+ const displayName = remoteCard.name ?? remoteCard.agent_name ?? cardId;
3515
+ console.log(`Found remote card: ${displayName} @ ${gatewayUrl}`);
3516
+ }
3517
+ }
3376
3518
  }
3377
- const useReceipt = isPeerRequest && opts.receipt !== false;
3519
+ const useReceipt = isRemoteRequest && opts.receipt !== false;
3378
3520
  if (useReceipt && !opts.cost) {
3379
- console.error("Error: --cost <credits> is required for peer requests. Specify the credits to commit.");
3521
+ console.error("Error: --cost <credits> is required for remote requests. Specify the credits to commit.");
3380
3522
  process.exit(1);
3381
3523
  }
3382
3524
  let escrowId;
@@ -3420,7 +3562,8 @@ program.command("request [card-id]").description("Request a capability from anot
3420
3562
  token,
3421
3563
  cardId,
3422
3564
  params: { ...params, ...opts.skill ? { skill_id: opts.skill } : {} },
3423
- escrowReceipt
3565
+ escrowReceipt,
3566
+ identity: identityAuth
3424
3567
  });
3425
3568
  if (useReceipt && escrowId) {
3426
3569
  const configDir = getConfigDir();
@@ -3591,7 +3734,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
3591
3734
  }
3592
3735
  if (opts.registry) {
3593
3736
  const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
3594
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-NZXTSSVV.js");
3737
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-SWWEHV2K.js");
3595
3738
  const cards = listCards(runtime.registryDb, config.owner);
3596
3739
  const card = cards[0] ?? {
3597
3740
  id: config.owner,
@@ -3860,7 +4003,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
3860
4003
  }
3861
4004
  });
3862
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) => {
3863
- const { conductAction } = await import("../conduct-5T3LGXMF.js");
4006
+ const { conductAction } = await import("../conduct-IEQ567ET.js");
3864
4007
  const result = await conductAction(task, opts);
3865
4008
  if (opts.json) {
3866
4009
  console.log(JSON.stringify(result, null, 2));
@@ -4,21 +4,21 @@ import {
4
4
  decompose,
5
5
  matchSubTasks,
6
6
  orchestrate
7
- } from "./chunk-VCW7IDJM.js";
7
+ } from "./chunk-7OACGAFD.js";
8
8
  import {
9
9
  BudgetManager
10
- } from "./chunk-2ETVQXP7.js";
10
+ } from "./chunk-IZZ4FP45.js";
11
11
  import {
12
12
  loadConfig,
13
13
  loadPeers
14
14
  } from "./chunk-BEI5MTNZ.js";
15
15
  import {
16
16
  openDatabase
17
- } from "./chunk-QAY6XTT7.js";
17
+ } from "./chunk-UOGDK2S2.js";
18
18
  import {
19
19
  openCreditDb
20
- } from "./chunk-MZCNJ5PY.js";
21
- import "./chunk-7RU5INZI.js";
20
+ } from "./chunk-QHQPXO67.js";
21
+ import "./chunk-XA63SD4T.js";
22
22
 
23
23
  // src/cli/conduct.ts
24
24
  async function conductAction(task, opts) {
@@ -3,13 +3,13 @@ import {
3
3
  decompose,
4
4
  matchSubTasks,
5
5
  orchestrate
6
- } from "./chunk-VCW7IDJM.js";
6
+ } from "./chunk-7OACGAFD.js";
7
7
  import {
8
8
  BudgetManager
9
- } from "./chunk-2ETVQXP7.js";
9
+ } from "./chunk-IZZ4FP45.js";
10
10
  import "./chunk-BEI5MTNZ.js";
11
- import "./chunk-MZCNJ5PY.js";
12
- import "./chunk-7RU5INZI.js";
11
+ import "./chunk-QHQPXO67.js";
12
+ import "./chunk-XA63SD4T.js";
13
13
 
14
14
  // src/conductor/conductor-mode.ts
15
15
  var ConductorMode = class {
@@ -0,0 +1,9 @@
1
+ import {
2
+ executeCapabilityRequest
3
+ } from "./chunk-QSPWE5AE.js";
4
+ import "./chunk-UOGDK2S2.js";
5
+ import "./chunk-QHQPXO67.js";
6
+ import "./chunk-XA63SD4T.js";
7
+ export {
8
+ executeCapabilityRequest
9
+ };
package/dist/index.d.ts CHANGED
@@ -96,6 +96,8 @@ declare const CapabilityCardSchema: z.ZodObject<{
96
96
  * never transmitted beyond the local store.
97
97
  */
98
98
  _internal: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
99
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
100
+ gateway_url: z.ZodOptional<z.ZodString>;
99
101
  metadata: z.ZodOptional<z.ZodObject<{
100
102
  apis_used: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
101
103
  avg_latency_ms: z.ZodOptional<z.ZodNumber>;
@@ -150,6 +152,7 @@ declare const CapabilityCardSchema: z.ZodObject<{
150
152
  tier?: string | undefined;
151
153
  }[] | undefined;
152
154
  _internal?: Record<string, unknown> | undefined;
155
+ gateway_url?: string | undefined;
153
156
  metadata?: {
154
157
  apis_used?: string[] | undefined;
155
158
  avg_latency_ms?: number | undefined;
@@ -194,6 +197,7 @@ declare const CapabilityCardSchema: z.ZodObject<{
194
197
  tier?: string | undefined;
195
198
  }[] | undefined;
196
199
  _internal?: Record<string, unknown> | undefined;
200
+ gateway_url?: string | undefined;
197
201
  metadata?: {
198
202
  apis_used?: string[] | undefined;
199
203
  avg_latency_ms?: number | undefined;
@@ -444,6 +448,8 @@ declare const CapabilityCardV2Schema: z.ZodObject<{
444
448
  * never transmitted beyond the local store.
445
449
  */
446
450
  _internal: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
451
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
452
+ gateway_url: z.ZodOptional<z.ZodString>;
447
453
  created_at: z.ZodOptional<z.ZodString>;
448
454
  updated_at: z.ZodOptional<z.ZodString>;
449
455
  }, "strip", z.ZodTypeAny, {
@@ -500,6 +506,7 @@ declare const CapabilityCardV2Schema: z.ZodObject<{
500
506
  category?: string | undefined;
501
507
  }[];
502
508
  _internal?: Record<string, unknown> | undefined;
509
+ gateway_url?: string | undefined;
503
510
  created_at?: string | undefined;
504
511
  updated_at?: string | undefined;
505
512
  environment?: {
@@ -560,6 +567,7 @@ declare const CapabilityCardV2Schema: z.ZodObject<{
560
567
  category?: string | undefined;
561
568
  }[];
562
569
  _internal?: Record<string, unknown> | undefined;
570
+ gateway_url?: string | undefined;
563
571
  created_at?: string | undefined;
564
572
  updated_at?: string | undefined;
565
573
  environment?: {
package/dist/index.js CHANGED
@@ -39,6 +39,8 @@ var CapabilityCardSchema = z.object({
39
39
  * never transmitted beyond the local store.
40
40
  */
41
41
  _internal: z.record(z.unknown()).optional(),
42
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
43
+ gateway_url: z.string().url().optional(),
42
44
  metadata: z.object({
43
45
  apis_used: z.array(z.string()).optional(),
44
46
  avg_latency_ms: z.number().nonnegative().optional(),
@@ -103,6 +105,8 @@ var CapabilityCardV2Schema = z.object({
103
105
  * never transmitted beyond the local store.
104
106
  */
105
107
  _internal: z.record(z.unknown()).optional(),
108
+ /** Public gateway URL where this agent accepts requests. Populated on remote publish. */
109
+ gateway_url: z.string().url().optional(),
106
110
  created_at: z.string().datetime().optional(),
107
111
  updated_at: z.string().datetime().optional()
108
112
  });
@@ -942,22 +946,27 @@ function createGatewayServer(opts) {
942
946
  fastify.addHook("onRequest", async (request, reply) => {
943
947
  if (request.method === "GET" && request.url === "/health") return;
944
948
  const auth = request.headers.authorization;
945
- if (!auth || !auth.startsWith("Bearer ")) {
946
- await reply.status(401).send({
947
- jsonrpc: "2.0",
948
- id: null,
949
- error: { code: -32e3, message: "Unauthorized: missing token" }
950
- });
951
- return;
952
- }
953
- const token = auth.slice("Bearer ".length).trim();
954
- if (!tokenSet.has(token)) {
955
- await reply.status(401).send({
956
- jsonrpc: "2.0",
957
- id: null,
958
- error: { code: -32e3, message: "Unauthorized: invalid token" }
959
- });
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
+ }
960
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
+ });
961
970
  });
962
971
  fastify.get("/health", async () => {
963
972
  return { status: "ok", version: VERSION, uptime: process.uptime() };
@@ -1913,7 +1922,7 @@ function decompose(task, _availableCapabilities) {
1913
1922
  // src/gateway/client.ts
1914
1923
  import { randomUUID as randomUUID5 } from "crypto";
1915
1924
  async function requestCapability(opts) {
1916
- const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt } = opts;
1925
+ const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
1917
1926
  const id = randomUUID5();
1918
1927
  const payload = {
1919
1928
  jsonrpc: "2.0",
@@ -1925,16 +1934,22 @@ async function requestCapability(opts) {
1925
1934
  ...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
1926
1935
  }
1927
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
+ }
1928
1946
  const controller = new AbortController();
1929
1947
  const timer = setTimeout(() => controller.abort(), timeoutMs);
1930
1948
  let response;
1931
1949
  try {
1932
1950
  response = await fetch(`${gatewayUrl}/rpc`, {
1933
1951
  method: "POST",
1934
- headers: {
1935
- "Content-Type": "application/json",
1936
- Authorization: `Bearer ${token}`
1937
- },
1952
+ headers,
1938
1953
  body: JSON.stringify(payload),
1939
1954
  signal: controller.signal
1940
1955
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentbnb",
3
- "version": "3.1.1",
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",
@@ -1,9 +0,0 @@
1
- import {
2
- executeCapabilityRequest
3
- } from "./chunk-MGHI67GR.js";
4
- import "./chunk-QAY6XTT7.js";
5
- import "./chunk-MZCNJ5PY.js";
6
- import "./chunk-7RU5INZI.js";
7
- export {
8
- executeCapabilityRequest
9
- };