agentbnb 4.0.0 → 4.0.1
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/dist/{card-IE5UV5QX.js → card-4XH4AOTE.js} +11 -4
- package/dist/chunk-3MJT4PZG.js +50 -0
- package/dist/{conduct-IQYAT6ZU.js → chunk-3UKAVIMC.js} +70 -33
- package/dist/chunk-5AH3CMOX.js +62 -0
- package/dist/{chunk-UJWYE7VL.js → chunk-6K5WUVF3.js} +28 -111
- package/dist/chunk-75OC6E4F.js +33 -0
- package/dist/{chunk-QO67IGCW.js → chunk-DVAS2443.js} +1 -1
- package/dist/{chunk-XA63SD4T.js → chunk-FNKBHBYK.js} +3 -0
- package/dist/{websocket-client-5TIQDYQ4.js → chunk-JOY533UH.js} +38 -4
- package/dist/{chunk-RSX4SCPN.js → chunk-KJG2UJV5.js} +3 -3
- package/dist/chunk-M3G5NR2Z.js +90 -0
- package/dist/{chunk-HEVXCYCY.js → chunk-MQKYGY5I.js} +61 -24
- package/dist/chunk-ODBGCCEH.js +358 -0
- package/dist/{chunk-CUVIWPQO.js → chunk-Q7HRI666.js} +7 -6
- package/dist/chunk-QJEOCKVF.js +148 -0
- package/dist/{chunk-3Y36WQDV.js → chunk-QT7TEVNV.js} +14 -2
- package/dist/{chunk-UOGDK2S2.js → chunk-TLU7ALCZ.js} +1 -1
- package/dist/{chunk-QVV2P3FN.js → chunk-XQHN6ITI.js} +1 -1
- package/dist/cli/index.js +2665 -845
- package/dist/{client-IOTK6GOS.js → client-BTPIFY7E.js} +3 -3
- package/dist/conduct-CW62HBPT.js +52 -0
- package/dist/conduct-FXLVGKD5.js +19 -0
- package/dist/{conductor-mode-XU7ONJWC.js → conductor-mode-3JS4VWCR.js} +16 -9
- package/dist/execute-EXOITLHN.js +10 -0
- package/dist/index.d.ts +1005 -916
- package/dist/index.js +516 -120
- package/dist/{peers-G36URZYB.js → peers-K7FSHPN3.js} +2 -1
- package/dist/request-CNZ3XIVX.js +196 -0
- package/dist/serve-skill-SUOGUM7N.js +104 -0
- package/dist/server-2LWHL24P.js +295 -0
- package/dist/types-FGBUZ3QV.js +18 -0
- package/dist/websocket-client-6IIDGXKB.js +7 -0
- package/package.json +1 -1
- package/dist/chunk-BEI5MTNZ.js +0 -91
- package/dist/cli/index.d.ts +0 -1
- package/dist/execute-GDGBU6DJ.js +0 -10
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateKeyPair,
|
|
3
|
+
loadKeyPair,
|
|
4
|
+
saveKeyPair
|
|
5
|
+
} from "./chunk-DVAS2443.js";
|
|
6
|
+
|
|
7
|
+
// src/identity/identity.ts
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { createHash } from "crypto";
|
|
10
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
var AgentIdentitySchema = z.object({
|
|
13
|
+
/** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
|
|
14
|
+
agent_id: z.string().min(1),
|
|
15
|
+
/** Human-readable owner name (from config or init). */
|
|
16
|
+
owner: z.string().min(1),
|
|
17
|
+
/** Hex-encoded Ed25519 public key. */
|
|
18
|
+
public_key: z.string().min(1),
|
|
19
|
+
/** ISO 8601 timestamp of identity creation. */
|
|
20
|
+
created_at: z.string().datetime(),
|
|
21
|
+
/** Optional guarantor info if linked to a human. */
|
|
22
|
+
guarantor: z.object({
|
|
23
|
+
github_login: z.string().min(1),
|
|
24
|
+
verified_at: z.string().datetime()
|
|
25
|
+
}).optional()
|
|
26
|
+
});
|
|
27
|
+
var AgentCertificateSchema = z.object({
|
|
28
|
+
identity: AgentIdentitySchema,
|
|
29
|
+
/** ISO 8601 timestamp of certificate issuance. */
|
|
30
|
+
issued_at: z.string().datetime(),
|
|
31
|
+
/** ISO 8601 timestamp of certificate expiry. */
|
|
32
|
+
expires_at: z.string().datetime(),
|
|
33
|
+
/** Hex-encoded public key of the issuer (same as identity for self-signed). */
|
|
34
|
+
issuer_public_key: z.string().min(1),
|
|
35
|
+
/** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
|
|
36
|
+
signature: z.string().min(1)
|
|
37
|
+
});
|
|
38
|
+
var IDENTITY_FILENAME = "identity.json";
|
|
39
|
+
function deriveAgentId(publicKeyHex) {
|
|
40
|
+
return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
|
|
41
|
+
}
|
|
42
|
+
function createIdentity(configDir, owner) {
|
|
43
|
+
if (!existsSync(configDir)) {
|
|
44
|
+
mkdirSync(configDir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
let keys;
|
|
47
|
+
try {
|
|
48
|
+
keys = loadKeyPair(configDir);
|
|
49
|
+
} catch {
|
|
50
|
+
keys = generateKeyPair();
|
|
51
|
+
saveKeyPair(configDir, keys);
|
|
52
|
+
}
|
|
53
|
+
const publicKeyHex = keys.publicKey.toString("hex");
|
|
54
|
+
const agentId = deriveAgentId(publicKeyHex);
|
|
55
|
+
const identity = {
|
|
56
|
+
agent_id: agentId,
|
|
57
|
+
owner,
|
|
58
|
+
public_key: publicKeyHex,
|
|
59
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
60
|
+
};
|
|
61
|
+
saveIdentity(configDir, identity);
|
|
62
|
+
return identity;
|
|
63
|
+
}
|
|
64
|
+
function loadIdentity(configDir) {
|
|
65
|
+
const filePath = join(configDir, IDENTITY_FILENAME);
|
|
66
|
+
if (!existsSync(filePath)) return null;
|
|
67
|
+
try {
|
|
68
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
69
|
+
return AgentIdentitySchema.parse(JSON.parse(raw));
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function saveIdentity(configDir, identity) {
|
|
75
|
+
if (!existsSync(configDir)) {
|
|
76
|
+
mkdirSync(configDir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
const filePath = join(configDir, IDENTITY_FILENAME);
|
|
79
|
+
writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
|
|
80
|
+
}
|
|
81
|
+
function ensureIdentity(configDir, owner) {
|
|
82
|
+
const existing = loadIdentity(configDir);
|
|
83
|
+
if (existing) return existing;
|
|
84
|
+
return createIdentity(configDir, owner);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
deriveAgentId,
|
|
89
|
+
ensureIdentity
|
|
90
|
+
};
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
interpolateObject
|
|
3
|
-
|
|
2
|
+
interpolateObject
|
|
3
|
+
} from "./chunk-3MJT4PZG.js";
|
|
4
|
+
import {
|
|
5
|
+
scorePeers
|
|
6
|
+
} from "./chunk-6K5WUVF3.js";
|
|
7
|
+
import {
|
|
8
|
+
fetchRemoteCards,
|
|
4
9
|
searchCards
|
|
5
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QJEOCKVF.js";
|
|
6
11
|
import {
|
|
7
12
|
requestCapability
|
|
8
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KJG2UJV5.js";
|
|
9
14
|
|
|
10
15
|
// src/conductor/task-decomposer.ts
|
|
11
16
|
import { randomUUID } from "crypto";
|
|
@@ -118,10 +123,17 @@ function decompose(task, _availableCapabilities) {
|
|
|
118
123
|
|
|
119
124
|
// src/conductor/capability-matcher.ts
|
|
120
125
|
var MAX_ALTERNATIVES = 2;
|
|
121
|
-
function matchSubTasks(opts) {
|
|
122
|
-
const { db, subtasks, conductorOwner } = opts;
|
|
123
|
-
return subtasks.map((subtask) => {
|
|
124
|
-
|
|
126
|
+
async function matchSubTasks(opts) {
|
|
127
|
+
const { db, subtasks, conductorOwner, registryUrl } = opts;
|
|
128
|
+
return Promise.all(subtasks.map(async (subtask) => {
|
|
129
|
+
let cards = searchCards(db, subtask.required_capability, { online: true });
|
|
130
|
+
if (cards.length === 0 && registryUrl) {
|
|
131
|
+
try {
|
|
132
|
+
cards = await fetchRemoteCards(registryUrl, { q: subtask.required_capability, online: true });
|
|
133
|
+
} catch {
|
|
134
|
+
cards = [];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
125
137
|
const candidates = [];
|
|
126
138
|
for (const card of cards) {
|
|
127
139
|
const cardAsV2 = card;
|
|
@@ -163,11 +175,12 @@ function matchSubTasks(opts) {
|
|
|
163
175
|
subtask_id: subtask.id,
|
|
164
176
|
selected_agent: top.card.owner,
|
|
165
177
|
selected_skill: top.skillId ?? "",
|
|
178
|
+
selected_card_id: top.card.id,
|
|
166
179
|
score: top.rawScore,
|
|
167
180
|
credits: top.cost,
|
|
168
181
|
alternatives
|
|
169
182
|
};
|
|
170
|
-
});
|
|
183
|
+
}));
|
|
171
184
|
}
|
|
172
185
|
|
|
173
186
|
// src/conductor/budget-controller.ts
|
|
@@ -262,7 +275,7 @@ function computeWaves(subtasks) {
|
|
|
262
275
|
return waves;
|
|
263
276
|
}
|
|
264
277
|
async function orchestrate(opts) {
|
|
265
|
-
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs =
|
|
278
|
+
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
|
|
266
279
|
const startTime = Date.now();
|
|
267
280
|
if (subtasks.length === 0) {
|
|
268
281
|
return {
|
|
@@ -313,26 +326,50 @@ async function orchestrate(opts) {
|
|
|
313
326
|
);
|
|
314
327
|
const primary = resolveAgentUrl(m.selected_agent);
|
|
315
328
|
try {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
329
|
+
let res;
|
|
330
|
+
if (primary.url.startsWith("relay://") && relayClient) {
|
|
331
|
+
const targetOwner = primary.url.replace("relay://", "");
|
|
332
|
+
res = await relayClient.request({
|
|
333
|
+
targetOwner,
|
|
334
|
+
cardId: primary.cardId,
|
|
335
|
+
params: interpolatedParams,
|
|
336
|
+
requester: requesterOwner,
|
|
337
|
+
timeoutMs
|
|
338
|
+
});
|
|
339
|
+
} else {
|
|
340
|
+
res = await requestCapability({
|
|
341
|
+
gatewayUrl: primary.url,
|
|
342
|
+
token: gatewayToken,
|
|
343
|
+
cardId: primary.cardId,
|
|
344
|
+
params: interpolatedParams,
|
|
345
|
+
timeoutMs
|
|
346
|
+
});
|
|
347
|
+
}
|
|
323
348
|
return { taskId, result: res, credits: m.credits };
|
|
324
349
|
} catch (primaryErr) {
|
|
325
350
|
if (m.alternatives.length > 0) {
|
|
326
351
|
const alt = m.alternatives[0];
|
|
327
352
|
const altAgent = resolveAgentUrl(alt.agent);
|
|
328
353
|
try {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
354
|
+
let altRes;
|
|
355
|
+
if (altAgent.url.startsWith("relay://") && relayClient) {
|
|
356
|
+
const targetOwner = altAgent.url.replace("relay://", "");
|
|
357
|
+
altRes = await relayClient.request({
|
|
358
|
+
targetOwner,
|
|
359
|
+
cardId: altAgent.cardId,
|
|
360
|
+
params: interpolatedParams,
|
|
361
|
+
requester: requesterOwner,
|
|
362
|
+
timeoutMs
|
|
363
|
+
});
|
|
364
|
+
} else {
|
|
365
|
+
altRes = await requestCapability({
|
|
366
|
+
gatewayUrl: altAgent.url,
|
|
367
|
+
token: gatewayToken,
|
|
368
|
+
cardId: altAgent.cardId,
|
|
369
|
+
params: interpolatedParams,
|
|
370
|
+
timeoutMs
|
|
371
|
+
});
|
|
372
|
+
}
|
|
336
373
|
return { taskId, result: altRes, credits: alt.credits };
|
|
337
374
|
} catch (altErr) {
|
|
338
375
|
throw new Error(
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bootstrapAgent,
|
|
3
|
+
getBalance,
|
|
4
|
+
getTransactions,
|
|
5
|
+
holdEscrow,
|
|
6
|
+
openCreditDb,
|
|
7
|
+
releaseEscrow,
|
|
8
|
+
settleEscrow
|
|
9
|
+
} from "./chunk-XQHN6ITI.js";
|
|
10
|
+
import {
|
|
11
|
+
signEscrowReceipt,
|
|
12
|
+
verifyEscrowReceipt
|
|
13
|
+
} from "./chunk-DVAS2443.js";
|
|
14
|
+
import {
|
|
15
|
+
AgentBnBError
|
|
16
|
+
} from "./chunk-FNKBHBYK.js";
|
|
17
|
+
|
|
18
|
+
// src/credit/local-credit-ledger.ts
|
|
19
|
+
var LocalCreditLedger = class {
|
|
20
|
+
constructor(db) {
|
|
21
|
+
this.db = db;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Holds credits in escrow during capability execution.
|
|
25
|
+
*
|
|
26
|
+
* @param owner - Agent identifier (requester).
|
|
27
|
+
* @param amount - Number of credits to hold.
|
|
28
|
+
* @param cardId - Capability Card ID being requested.
|
|
29
|
+
* @returns EscrowResult with the new escrowId.
|
|
30
|
+
* @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
|
|
31
|
+
*/
|
|
32
|
+
async hold(owner, amount, cardId) {
|
|
33
|
+
const escrowId = holdEscrow(this.db, owner, amount, cardId);
|
|
34
|
+
return { escrowId };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Settles an escrow — transfers held credits to the capability provider.
|
|
38
|
+
*
|
|
39
|
+
* @param escrowId - The escrow ID to settle.
|
|
40
|
+
* @param recipientOwner - Agent identifier who will receive the credits.
|
|
41
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
42
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
43
|
+
*/
|
|
44
|
+
async settle(escrowId, recipientOwner) {
|
|
45
|
+
settleEscrow(this.db, escrowId, recipientOwner);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Releases an escrow — refunds credits back to the requester.
|
|
49
|
+
*
|
|
50
|
+
* @param escrowId - The escrow ID to release.
|
|
51
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
52
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
53
|
+
*/
|
|
54
|
+
async release(escrowId) {
|
|
55
|
+
releaseEscrow(this.db, escrowId);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Returns the current credit balance for an agent.
|
|
59
|
+
*
|
|
60
|
+
* @param owner - Agent identifier.
|
|
61
|
+
* @returns Current balance in credits (0 if agent is unknown).
|
|
62
|
+
*/
|
|
63
|
+
async getBalance(owner) {
|
|
64
|
+
return getBalance(this.db, owner);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Returns the transaction history for an agent, newest first.
|
|
68
|
+
*
|
|
69
|
+
* @param owner - Agent identifier.
|
|
70
|
+
* @param limit - Maximum number of transactions to return. Defaults to 100.
|
|
71
|
+
* @returns Array of credit transactions ordered newest first.
|
|
72
|
+
*/
|
|
73
|
+
async getHistory(owner, limit) {
|
|
74
|
+
return getTransactions(this.db, owner, limit);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Grants initial credits to an agent (bootstrap grant).
|
|
78
|
+
* Idempotent — calling multiple times has no additional effect on balance.
|
|
79
|
+
*
|
|
80
|
+
* @param owner - Agent identifier.
|
|
81
|
+
* @param amount - Number of credits to grant. Defaults to 100.
|
|
82
|
+
*/
|
|
83
|
+
async grant(owner, amount) {
|
|
84
|
+
bootstrapAgent(this.db, owner, amount);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/registry/identity-auth.ts
|
|
89
|
+
var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
|
|
90
|
+
async function verifyIdentity(request, reply) {
|
|
91
|
+
const publicKeyHex = request.headers["x-agent-publickey"];
|
|
92
|
+
const signature = request.headers["x-agent-signature"];
|
|
93
|
+
const timestamp = request.headers["x-agent-timestamp"];
|
|
94
|
+
if (!publicKeyHex || !signature || !timestamp) {
|
|
95
|
+
await reply.code(401).send({ error: "Missing identity headers" });
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const requestTime = new Date(timestamp).getTime();
|
|
99
|
+
if (isNaN(requestTime) || Math.abs(Date.now() - requestTime) > MAX_REQUEST_AGE_MS) {
|
|
100
|
+
await reply.code(401).send({ error: "Request expired" });
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const payload = {
|
|
104
|
+
method: request.method,
|
|
105
|
+
path: request.url,
|
|
106
|
+
timestamp,
|
|
107
|
+
publicKey: publicKeyHex
|
|
108
|
+
};
|
|
109
|
+
let publicKeyBuffer;
|
|
110
|
+
try {
|
|
111
|
+
publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
|
|
112
|
+
} catch {
|
|
113
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
|
|
117
|
+
if (!valid) {
|
|
118
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
request.agentPublicKey = publicKeyHex;
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
function identityAuthPlugin(fastify) {
|
|
125
|
+
fastify.addHook("onRequest", async (request, reply) => {
|
|
126
|
+
await verifyIdentity(request, reply);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function signRequest(method, path, body, privateKey, publicKeyHex) {
|
|
130
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
131
|
+
const payload = {
|
|
132
|
+
method,
|
|
133
|
+
path,
|
|
134
|
+
timestamp,
|
|
135
|
+
publicKey: publicKeyHex
|
|
136
|
+
};
|
|
137
|
+
void body;
|
|
138
|
+
const signature = signEscrowReceipt(payload, privateKey);
|
|
139
|
+
return {
|
|
140
|
+
"X-Agent-PublicKey": publicKeyHex,
|
|
141
|
+
"X-Agent-Signature": signature,
|
|
142
|
+
"X-Agent-Timestamp": timestamp
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/credit/registry-credit-ledger.ts
|
|
147
|
+
var HTTP_TIMEOUT_MS = 1e4;
|
|
148
|
+
var RegistryCreditLedger = class {
|
|
149
|
+
config;
|
|
150
|
+
constructor(config) {
|
|
151
|
+
this.config = config;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Holds credits in escrow during capability execution.
|
|
155
|
+
*
|
|
156
|
+
* @param owner - Agent identifier (requester).
|
|
157
|
+
* @param amount - Number of credits to hold.
|
|
158
|
+
* @param cardId - Capability Card ID being requested.
|
|
159
|
+
* @returns EscrowResult with the new escrowId.
|
|
160
|
+
* @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
|
|
161
|
+
*/
|
|
162
|
+
async hold(owner, amount, cardId) {
|
|
163
|
+
if (this.config.mode === "direct") {
|
|
164
|
+
const escrowId = holdEscrow(this.config.db, owner, amount, cardId);
|
|
165
|
+
return { escrowId };
|
|
166
|
+
}
|
|
167
|
+
const data = await this.post("/api/credits/hold", owner, {
|
|
168
|
+
owner,
|
|
169
|
+
amount,
|
|
170
|
+
cardId
|
|
171
|
+
});
|
|
172
|
+
return { escrowId: data.escrowId };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Settles an escrow — transfers held credits to the capability provider.
|
|
176
|
+
*
|
|
177
|
+
* @param escrowId - The escrow ID to settle.
|
|
178
|
+
* @param recipientOwner - Agent identifier who will receive the credits.
|
|
179
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
180
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
181
|
+
*/
|
|
182
|
+
async settle(escrowId, recipientOwner) {
|
|
183
|
+
if (this.config.mode === "direct") {
|
|
184
|
+
settleEscrow(this.config.db, escrowId, recipientOwner);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
await this.post("/api/credits/settle", null, { escrowId, recipientOwner });
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Releases an escrow — refunds credits back to the requester.
|
|
191
|
+
*
|
|
192
|
+
* @param escrowId - The escrow ID to release.
|
|
193
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
194
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
195
|
+
*/
|
|
196
|
+
async release(escrowId) {
|
|
197
|
+
if (this.config.mode === "direct") {
|
|
198
|
+
releaseEscrow(this.config.db, escrowId);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
await this.post("/api/credits/release", null, { escrowId });
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns the current credit balance for an agent.
|
|
205
|
+
*
|
|
206
|
+
* @param owner - Agent identifier.
|
|
207
|
+
* @returns Current balance in credits (0 if agent is unknown).
|
|
208
|
+
*/
|
|
209
|
+
async getBalance(owner) {
|
|
210
|
+
if (this.config.mode === "direct") {
|
|
211
|
+
return getBalance(this.config.db, owner);
|
|
212
|
+
}
|
|
213
|
+
const data = await this.get(`/api/credits/${owner}`, owner);
|
|
214
|
+
return data.balance;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Returns the transaction history for an agent, newest first.
|
|
218
|
+
*
|
|
219
|
+
* @param owner - Agent identifier.
|
|
220
|
+
* @param limit - Maximum number of transactions to return. Defaults to 100.
|
|
221
|
+
* @returns Array of credit transactions ordered newest first.
|
|
222
|
+
*/
|
|
223
|
+
async getHistory(owner, limit = 100) {
|
|
224
|
+
if (this.config.mode === "direct") {
|
|
225
|
+
return getTransactions(this.config.db, owner, limit);
|
|
226
|
+
}
|
|
227
|
+
const data = await this.get(
|
|
228
|
+
`/api/credits/${owner}/history?limit=${limit}`,
|
|
229
|
+
owner
|
|
230
|
+
);
|
|
231
|
+
return data.transactions;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Grants initial credits to an agent (bootstrap grant).
|
|
235
|
+
* Idempotent — calling multiple times has no additional effect on balance.
|
|
236
|
+
*
|
|
237
|
+
* @param owner - Agent identifier.
|
|
238
|
+
* @param amount - Number of credits to grant. Defaults to 100.
|
|
239
|
+
*/
|
|
240
|
+
async grant(owner, amount = 100) {
|
|
241
|
+
if (this.config.mode === "direct") {
|
|
242
|
+
bootstrapAgent(this.config.db, owner, amount);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
await this.post("/api/credits/grant", owner, { owner, amount });
|
|
246
|
+
}
|
|
247
|
+
// ─── Private HTTP helpers ─────────────────────────────────────────────────
|
|
248
|
+
/**
|
|
249
|
+
* Makes an authenticated POST request to the Registry HTTP API.
|
|
250
|
+
* Includes a 10s timeout via AbortController.
|
|
251
|
+
*
|
|
252
|
+
* @param path - API path (e.g., '/api/credits/hold').
|
|
253
|
+
* @param ownerForHeader - Agent owner identifier for X-Agent-Owner header, or null to omit.
|
|
254
|
+
* @param body - JSON body to send.
|
|
255
|
+
* @returns Parsed JSON response body.
|
|
256
|
+
* @throws {AgentBnBError} on non-2xx responses or network errors.
|
|
257
|
+
*/
|
|
258
|
+
async post(path, ownerForHeader, body) {
|
|
259
|
+
const cfg = this.config;
|
|
260
|
+
const controller = new AbortController();
|
|
261
|
+
const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
|
|
262
|
+
try {
|
|
263
|
+
const authHeaders = signRequest("POST", path, body, cfg.privateKey, cfg.ownerPublicKey);
|
|
264
|
+
const headers = {
|
|
265
|
+
"Content-Type": "application/json",
|
|
266
|
+
...authHeaders
|
|
267
|
+
};
|
|
268
|
+
void ownerForHeader;
|
|
269
|
+
const res = await fetch(`${cfg.registryUrl}${path}`, {
|
|
270
|
+
method: "POST",
|
|
271
|
+
headers,
|
|
272
|
+
body: JSON.stringify(body),
|
|
273
|
+
signal: controller.signal
|
|
274
|
+
});
|
|
275
|
+
return await this.handleResponse(res);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
if (err instanceof AgentBnBError) throw err;
|
|
278
|
+
throw new AgentBnBError(
|
|
279
|
+
`Registry unreachable: ${err.message}`,
|
|
280
|
+
"REGISTRY_UNREACHABLE"
|
|
281
|
+
);
|
|
282
|
+
} finally {
|
|
283
|
+
clearTimeout(timeoutId);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Makes an authenticated GET request to the Registry HTTP API.
|
|
288
|
+
* Includes a 10s timeout via AbortController.
|
|
289
|
+
*
|
|
290
|
+
* @param path - API path (e.g., '/api/credits/owner-id').
|
|
291
|
+
* @param owner - Agent owner identifier for X-Agent-Owner header.
|
|
292
|
+
* @returns Parsed JSON response body.
|
|
293
|
+
* @throws {AgentBnBError} on non-2xx responses or network errors.
|
|
294
|
+
*/
|
|
295
|
+
async get(path, owner) {
|
|
296
|
+
const cfg = this.config;
|
|
297
|
+
const controller = new AbortController();
|
|
298
|
+
const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
|
|
299
|
+
try {
|
|
300
|
+
const authHeaders = signRequest("GET", path, null, cfg.privateKey, cfg.ownerPublicKey);
|
|
301
|
+
void owner;
|
|
302
|
+
const res = await fetch(`${cfg.registryUrl}${path}`, {
|
|
303
|
+
method: "GET",
|
|
304
|
+
headers: {
|
|
305
|
+
"Content-Type": "application/json",
|
|
306
|
+
...authHeaders
|
|
307
|
+
},
|
|
308
|
+
signal: controller.signal
|
|
309
|
+
});
|
|
310
|
+
return await this.handleResponse(res);
|
|
311
|
+
} catch (err) {
|
|
312
|
+
if (err instanceof AgentBnBError) throw err;
|
|
313
|
+
throw new AgentBnBError(
|
|
314
|
+
`Registry unreachable: ${err.message}`,
|
|
315
|
+
"REGISTRY_UNREACHABLE"
|
|
316
|
+
);
|
|
317
|
+
} finally {
|
|
318
|
+
clearTimeout(timeoutId);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Handles an HTTP response — returns parsed JSON on 2xx, throws AgentBnBError on error.
|
|
323
|
+
*/
|
|
324
|
+
async handleResponse(res) {
|
|
325
|
+
const json = await res.json();
|
|
326
|
+
if (!res.ok) {
|
|
327
|
+
const code = typeof json["code"] === "string" ? json["code"] : "REGISTRY_ERROR";
|
|
328
|
+
const message = typeof json["error"] === "string" ? json["error"] : `HTTP ${res.status}`;
|
|
329
|
+
throw new AgentBnBError(message, code);
|
|
330
|
+
}
|
|
331
|
+
return json;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
// src/credit/create-ledger.ts
|
|
336
|
+
function createLedger(opts) {
|
|
337
|
+
if ("registryUrl" in opts && opts.registryUrl !== void 0) {
|
|
338
|
+
return new RegistryCreditLedger({
|
|
339
|
+
mode: "http",
|
|
340
|
+
registryUrl: opts.registryUrl,
|
|
341
|
+
ownerPublicKey: opts.ownerPublicKey,
|
|
342
|
+
privateKey: opts.privateKey
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
if ("db" in opts && opts.db !== void 0) {
|
|
346
|
+
return new RegistryCreditLedger({
|
|
347
|
+
mode: "direct",
|
|
348
|
+
db: opts.db
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
const db = openCreditDb(opts.creditDbPath);
|
|
352
|
+
return new LocalCreditLedger(db);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export {
|
|
356
|
+
identityAuthPlugin,
|
|
357
|
+
createLedger
|
|
358
|
+
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
getCard,
|
|
3
3
|
insertRequestLog,
|
|
4
4
|
updateReputation
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TLU7ALCZ.js";
|
|
6
6
|
import {
|
|
7
7
|
confirmEscrowDebit,
|
|
8
8
|
getBalance,
|
|
@@ -10,13 +10,13 @@ import {
|
|
|
10
10
|
recordEarning,
|
|
11
11
|
releaseEscrow,
|
|
12
12
|
settleEscrow
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XQHN6ITI.js";
|
|
14
14
|
import {
|
|
15
15
|
verifyEscrowReceipt
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-DVAS2443.js";
|
|
17
17
|
import {
|
|
18
18
|
AgentBnBError
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-FNKBHBYK.js";
|
|
20
20
|
|
|
21
21
|
// src/gateway/execute.ts
|
|
22
22
|
import { randomUUID } from "crypto";
|
|
@@ -51,7 +51,8 @@ async function executeCapabilityRequest(opts) {
|
|
|
51
51
|
escrowReceipt: receipt,
|
|
52
52
|
skillExecutor,
|
|
53
53
|
handlerUrl,
|
|
54
|
-
timeoutMs =
|
|
54
|
+
timeoutMs = 3e5,
|
|
55
|
+
onProgress
|
|
55
56
|
} = opts;
|
|
56
57
|
const card = getCard(registryDb, cardId);
|
|
57
58
|
if (!card) {
|
|
@@ -158,7 +159,7 @@ async function executeCapabilityRequest(opts) {
|
|
|
158
159
|
if (skillExecutor) {
|
|
159
160
|
const targetSkillId = resolvedSkillId ?? skillId ?? cardId;
|
|
160
161
|
try {
|
|
161
|
-
const execResult = await skillExecutor.execute(targetSkillId, params);
|
|
162
|
+
const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
|
|
162
163
|
if (!execResult.success) {
|
|
163
164
|
return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed");
|
|
164
165
|
}
|