agentbnb 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{card-IE5UV5QX.js → card-RSGDCHCV.js} +11 -4
- package/dist/chunk-3MJT4PZG.js +50 -0
- package/dist/{chunk-HEVXCYCY.js → chunk-4P3EMGL4.js} +61 -24
- package/dist/chunk-5AH3CMOX.js +62 -0
- package/dist/{chunk-QO67IGCW.js → chunk-5KFI5X7B.js} +1 -1
- package/dist/chunk-75OC6E4F.js +33 -0
- package/dist/{chunk-CUVIWPQO.js → chunk-7NA43XCG.js} +7 -6
- package/dist/{conduct-IQYAT6ZU.js → chunk-BH6WGYFB.js} +70 -33
- package/dist/{chunk-QVV2P3FN.js → chunk-DNWT5FZQ.js} +22 -2
- package/dist/chunk-FF226TIV.js +148 -0
- package/dist/{chunk-UJWYE7VL.js → chunk-GGYC5U2Z.js} +28 -111
- package/dist/chunk-HH24WMFN.js +373 -0
- package/dist/{websocket-client-5TIQDYQ4.js → chunk-JOY533UH.js} +38 -4
- package/dist/chunk-QITOPASZ.js +96 -0
- package/dist/{chunk-3Y36WQDV.js → chunk-QT7TEVNV.js} +14 -2
- package/dist/{chunk-UOGDK2S2.js → chunk-T7NS2J2B.js} +1 -1
- package/dist/{chunk-XA63SD4T.js → chunk-WGZ5AGOX.js} +37 -0
- package/dist/{chunk-RSX4SCPN.js → chunk-XND2DWTZ.js} +4 -3
- package/dist/cli/index.js +2924 -835
- package/dist/{client-IOTK6GOS.js → client-T5MTY3CS.js} +3 -3
- package/dist/conduct-GZQNFTRP.js +19 -0
- package/dist/conduct-N52JX7RT.js +52 -0
- package/dist/{conductor-mode-XU7ONJWC.js → conductor-mode-XUWGR4ZE.js} +16 -9
- package/dist/execute-PNGQOMYO.js +10 -0
- package/dist/index.d.ts +1148 -915
- package/dist/index.js +589 -127
- package/dist/{peers-G36URZYB.js → peers-K7FSHPN3.js} +2 -1
- package/dist/request-4GQSSM4B.js +196 -0
- package/dist/serve-skill-TPHZH6BS.js +104 -0
- package/dist/server-365V3GYD.js +295 -0
- package/dist/websocket-client-6IIDGXKB.js +7 -0
- package/package.json +3 -6
- package/skills/agentbnb/HEARTBEAT.rules.md +47 -0
- package/skills/agentbnb/SKILL.md +166 -0
- package/skills/agentbnb/auto-request.ts +14 -0
- package/skills/agentbnb/auto-share.ts +10 -0
- package/skills/agentbnb/bootstrap.test.ts +323 -0
- package/skills/agentbnb/bootstrap.ts +126 -0
- package/skills/agentbnb/credit-mgr.ts +11 -0
- package/skills/agentbnb/gateway.ts +12 -0
- package/skills/agentbnb/install.sh +210 -0
- package/dist/chunk-BEI5MTNZ.js +0 -91
- package/dist/execute-GDGBU6DJ.js +0 -10
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bootstrapAgent,
|
|
3
|
+
getBalance,
|
|
4
|
+
getTransactions,
|
|
5
|
+
holdEscrow,
|
|
6
|
+
migrateOwner,
|
|
7
|
+
openCreditDb,
|
|
8
|
+
releaseEscrow,
|
|
9
|
+
settleEscrow
|
|
10
|
+
} from "./chunk-DNWT5FZQ.js";
|
|
11
|
+
import {
|
|
12
|
+
signEscrowReceipt,
|
|
13
|
+
verifyEscrowReceipt
|
|
14
|
+
} from "./chunk-5KFI5X7B.js";
|
|
15
|
+
import {
|
|
16
|
+
AgentBnBError
|
|
17
|
+
} from "./chunk-WGZ5AGOX.js";
|
|
18
|
+
|
|
19
|
+
// src/credit/local-credit-ledger.ts
|
|
20
|
+
var LocalCreditLedger = class {
|
|
21
|
+
constructor(db) {
|
|
22
|
+
this.db = db;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Holds credits in escrow during capability execution.
|
|
26
|
+
*
|
|
27
|
+
* @param owner - Agent identifier (requester).
|
|
28
|
+
* @param amount - Number of credits to hold.
|
|
29
|
+
* @param cardId - Capability Card ID being requested.
|
|
30
|
+
* @returns EscrowResult with the new escrowId.
|
|
31
|
+
* @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
|
|
32
|
+
*/
|
|
33
|
+
async hold(owner, amount, cardId) {
|
|
34
|
+
const escrowId = holdEscrow(this.db, owner, amount, cardId);
|
|
35
|
+
return { escrowId };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Settles an escrow — transfers held credits to the capability provider.
|
|
39
|
+
*
|
|
40
|
+
* @param escrowId - The escrow ID to settle.
|
|
41
|
+
* @param recipientOwner - Agent identifier who will receive the credits.
|
|
42
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
43
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
44
|
+
*/
|
|
45
|
+
async settle(escrowId, recipientOwner) {
|
|
46
|
+
settleEscrow(this.db, escrowId, recipientOwner);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Releases an escrow — refunds credits back to the requester.
|
|
50
|
+
*
|
|
51
|
+
* @param escrowId - The escrow ID to release.
|
|
52
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
53
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
54
|
+
*/
|
|
55
|
+
async release(escrowId) {
|
|
56
|
+
releaseEscrow(this.db, escrowId);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Returns the current credit balance for an agent.
|
|
60
|
+
*
|
|
61
|
+
* @param owner - Agent identifier.
|
|
62
|
+
* @returns Current balance in credits (0 if agent is unknown).
|
|
63
|
+
*/
|
|
64
|
+
async getBalance(owner) {
|
|
65
|
+
return getBalance(this.db, owner);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns the transaction history for an agent, newest first.
|
|
69
|
+
*
|
|
70
|
+
* @param owner - Agent identifier.
|
|
71
|
+
* @param limit - Maximum number of transactions to return. Defaults to 100.
|
|
72
|
+
* @returns Array of credit transactions ordered newest first.
|
|
73
|
+
*/
|
|
74
|
+
async getHistory(owner, limit) {
|
|
75
|
+
return getTransactions(this.db, owner, limit);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Grants initial credits to an agent (bootstrap grant).
|
|
79
|
+
* Idempotent — calling multiple times has no additional effect on balance.
|
|
80
|
+
*
|
|
81
|
+
* @param owner - Agent identifier.
|
|
82
|
+
* @param amount - Number of credits to grant. Defaults to 100.
|
|
83
|
+
*/
|
|
84
|
+
async grant(owner, amount) {
|
|
85
|
+
bootstrapAgent(this.db, owner, amount);
|
|
86
|
+
}
|
|
87
|
+
async rename(oldOwner, newOwner) {
|
|
88
|
+
migrateOwner(this.db, oldOwner, newOwner);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/registry/identity-auth.ts
|
|
93
|
+
var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
|
|
94
|
+
async function verifyIdentity(request, reply) {
|
|
95
|
+
const publicKeyHex = request.headers["x-agent-publickey"];
|
|
96
|
+
const signature = request.headers["x-agent-signature"];
|
|
97
|
+
const timestamp = request.headers["x-agent-timestamp"];
|
|
98
|
+
if (!publicKeyHex || !signature || !timestamp) {
|
|
99
|
+
await reply.code(401).send({ error: "Missing identity headers" });
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const requestTime = new Date(timestamp).getTime();
|
|
103
|
+
if (isNaN(requestTime) || Math.abs(Date.now() - requestTime) > MAX_REQUEST_AGE_MS) {
|
|
104
|
+
await reply.code(401).send({ error: "Request expired" });
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const payload = {
|
|
108
|
+
method: request.method,
|
|
109
|
+
path: request.url,
|
|
110
|
+
timestamp,
|
|
111
|
+
publicKey: publicKeyHex
|
|
112
|
+
};
|
|
113
|
+
let publicKeyBuffer;
|
|
114
|
+
try {
|
|
115
|
+
publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
|
|
116
|
+
} catch {
|
|
117
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
|
|
121
|
+
if (!valid) {
|
|
122
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
request.agentPublicKey = publicKeyHex;
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
function identityAuthPlugin(fastify) {
|
|
129
|
+
fastify.addHook("onRequest", async (request, reply) => {
|
|
130
|
+
await verifyIdentity(request, reply);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function signRequest(method, path, body, privateKey, publicKeyHex) {
|
|
134
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
135
|
+
const payload = {
|
|
136
|
+
method,
|
|
137
|
+
path,
|
|
138
|
+
timestamp,
|
|
139
|
+
publicKey: publicKeyHex
|
|
140
|
+
};
|
|
141
|
+
void body;
|
|
142
|
+
const signature = signEscrowReceipt(payload, privateKey);
|
|
143
|
+
return {
|
|
144
|
+
"X-Agent-PublicKey": publicKeyHex,
|
|
145
|
+
"X-Agent-Signature": signature,
|
|
146
|
+
"X-Agent-Timestamp": timestamp
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/credit/registry-credit-ledger.ts
|
|
151
|
+
var HTTP_TIMEOUT_MS = 1e4;
|
|
152
|
+
var RegistryCreditLedger = class {
|
|
153
|
+
config;
|
|
154
|
+
constructor(config) {
|
|
155
|
+
this.config = config;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Holds credits in escrow during capability execution.
|
|
159
|
+
*
|
|
160
|
+
* @param owner - Agent identifier (requester).
|
|
161
|
+
* @param amount - Number of credits to hold.
|
|
162
|
+
* @param cardId - Capability Card ID being requested.
|
|
163
|
+
* @returns EscrowResult with the new escrowId.
|
|
164
|
+
* @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
|
|
165
|
+
*/
|
|
166
|
+
async hold(owner, amount, cardId) {
|
|
167
|
+
if (this.config.mode === "direct") {
|
|
168
|
+
const escrowId = holdEscrow(this.config.db, owner, amount, cardId);
|
|
169
|
+
return { escrowId };
|
|
170
|
+
}
|
|
171
|
+
const data = await this.post("/api/credits/hold", owner, {
|
|
172
|
+
owner,
|
|
173
|
+
amount,
|
|
174
|
+
cardId
|
|
175
|
+
});
|
|
176
|
+
return { escrowId: data.escrowId };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Settles an escrow — transfers held credits to the capability provider.
|
|
180
|
+
*
|
|
181
|
+
* @param escrowId - The escrow ID to settle.
|
|
182
|
+
* @param recipientOwner - Agent identifier who will receive the credits.
|
|
183
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
184
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
185
|
+
*/
|
|
186
|
+
async settle(escrowId, recipientOwner) {
|
|
187
|
+
if (this.config.mode === "direct") {
|
|
188
|
+
settleEscrow(this.config.db, escrowId, recipientOwner);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
await this.post("/api/credits/settle", null, { escrowId, recipientOwner });
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Releases an escrow — refunds credits back to the requester.
|
|
195
|
+
*
|
|
196
|
+
* @param escrowId - The escrow ID to release.
|
|
197
|
+
* @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
|
|
198
|
+
* @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
|
|
199
|
+
*/
|
|
200
|
+
async release(escrowId) {
|
|
201
|
+
if (this.config.mode === "direct") {
|
|
202
|
+
releaseEscrow(this.config.db, escrowId);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
await this.post("/api/credits/release", null, { escrowId });
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Returns the current credit balance for an agent.
|
|
209
|
+
*
|
|
210
|
+
* @param owner - Agent identifier.
|
|
211
|
+
* @returns Current balance in credits (0 if agent is unknown).
|
|
212
|
+
*/
|
|
213
|
+
async getBalance(owner) {
|
|
214
|
+
if (this.config.mode === "direct") {
|
|
215
|
+
return getBalance(this.config.db, owner);
|
|
216
|
+
}
|
|
217
|
+
const data = await this.get(`/api/credits/${owner}`, owner);
|
|
218
|
+
return data.balance;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Returns the transaction history for an agent, newest first.
|
|
222
|
+
*
|
|
223
|
+
* @param owner - Agent identifier.
|
|
224
|
+
* @param limit - Maximum number of transactions to return. Defaults to 100.
|
|
225
|
+
* @returns Array of credit transactions ordered newest first.
|
|
226
|
+
*/
|
|
227
|
+
async getHistory(owner, limit = 100) {
|
|
228
|
+
if (this.config.mode === "direct") {
|
|
229
|
+
return getTransactions(this.config.db, owner, limit);
|
|
230
|
+
}
|
|
231
|
+
const data = await this.get(
|
|
232
|
+
`/api/credits/${owner}/history?limit=${limit}`,
|
|
233
|
+
owner
|
|
234
|
+
);
|
|
235
|
+
return data.transactions;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Grants initial credits to an agent (bootstrap grant).
|
|
239
|
+
* Idempotent — calling multiple times has no additional effect on balance.
|
|
240
|
+
*
|
|
241
|
+
* @param owner - Agent identifier.
|
|
242
|
+
* @param amount - Number of credits to grant. Defaults to 100.
|
|
243
|
+
*/
|
|
244
|
+
async grant(owner, amount = 100) {
|
|
245
|
+
if (this.config.mode === "direct") {
|
|
246
|
+
bootstrapAgent(this.config.db, owner, amount);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
await this.post("/api/credits/grant", owner, { owner, amount });
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Renames an owner — migrates balance, transactions, and escrows.
|
|
253
|
+
*/
|
|
254
|
+
async rename(oldOwner, newOwner) {
|
|
255
|
+
if (oldOwner === newOwner) return;
|
|
256
|
+
if (this.config.mode === "direct") {
|
|
257
|
+
migrateOwner(this.config.db, oldOwner, newOwner);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
await this.post("/api/credits/rename", null, { oldOwner, newOwner });
|
|
261
|
+
}
|
|
262
|
+
// ─── Private HTTP helpers ─────────────────────────────────────────────────
|
|
263
|
+
/**
|
|
264
|
+
* Makes an authenticated POST request to the Registry HTTP API.
|
|
265
|
+
* Includes a 10s timeout via AbortController.
|
|
266
|
+
*
|
|
267
|
+
* @param path - API path (e.g., '/api/credits/hold').
|
|
268
|
+
* @param ownerForHeader - Agent owner identifier for X-Agent-Owner header, or null to omit.
|
|
269
|
+
* @param body - JSON body to send.
|
|
270
|
+
* @returns Parsed JSON response body.
|
|
271
|
+
* @throws {AgentBnBError} on non-2xx responses or network errors.
|
|
272
|
+
*/
|
|
273
|
+
async post(path, ownerForHeader, body) {
|
|
274
|
+
const cfg = this.config;
|
|
275
|
+
const controller = new AbortController();
|
|
276
|
+
const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
|
|
277
|
+
try {
|
|
278
|
+
const authHeaders = signRequest("POST", path, body, cfg.privateKey, cfg.ownerPublicKey);
|
|
279
|
+
const headers = {
|
|
280
|
+
"Content-Type": "application/json",
|
|
281
|
+
...authHeaders
|
|
282
|
+
};
|
|
283
|
+
void ownerForHeader;
|
|
284
|
+
const res = await fetch(`${cfg.registryUrl}${path}`, {
|
|
285
|
+
method: "POST",
|
|
286
|
+
headers,
|
|
287
|
+
body: JSON.stringify(body),
|
|
288
|
+
signal: controller.signal
|
|
289
|
+
});
|
|
290
|
+
return await this.handleResponse(res);
|
|
291
|
+
} catch (err) {
|
|
292
|
+
if (err instanceof AgentBnBError) throw err;
|
|
293
|
+
throw new AgentBnBError(
|
|
294
|
+
`Registry unreachable: ${err.message}`,
|
|
295
|
+
"REGISTRY_UNREACHABLE"
|
|
296
|
+
);
|
|
297
|
+
} finally {
|
|
298
|
+
clearTimeout(timeoutId);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Makes an authenticated GET request to the Registry HTTP API.
|
|
303
|
+
* Includes a 10s timeout via AbortController.
|
|
304
|
+
*
|
|
305
|
+
* @param path - API path (e.g., '/api/credits/owner-id').
|
|
306
|
+
* @param owner - Agent owner identifier for X-Agent-Owner header.
|
|
307
|
+
* @returns Parsed JSON response body.
|
|
308
|
+
* @throws {AgentBnBError} on non-2xx responses or network errors.
|
|
309
|
+
*/
|
|
310
|
+
async get(path, owner) {
|
|
311
|
+
const cfg = this.config;
|
|
312
|
+
const controller = new AbortController();
|
|
313
|
+
const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
|
|
314
|
+
try {
|
|
315
|
+
const authHeaders = signRequest("GET", path, null, cfg.privateKey, cfg.ownerPublicKey);
|
|
316
|
+
void owner;
|
|
317
|
+
const res = await fetch(`${cfg.registryUrl}${path}`, {
|
|
318
|
+
method: "GET",
|
|
319
|
+
headers: {
|
|
320
|
+
"Content-Type": "application/json",
|
|
321
|
+
...authHeaders
|
|
322
|
+
},
|
|
323
|
+
signal: controller.signal
|
|
324
|
+
});
|
|
325
|
+
return await this.handleResponse(res);
|
|
326
|
+
} catch (err) {
|
|
327
|
+
if (err instanceof AgentBnBError) throw err;
|
|
328
|
+
throw new AgentBnBError(
|
|
329
|
+
`Registry unreachable: ${err.message}`,
|
|
330
|
+
"REGISTRY_UNREACHABLE"
|
|
331
|
+
);
|
|
332
|
+
} finally {
|
|
333
|
+
clearTimeout(timeoutId);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Handles an HTTP response — returns parsed JSON on 2xx, throws AgentBnBError on error.
|
|
338
|
+
*/
|
|
339
|
+
async handleResponse(res) {
|
|
340
|
+
const json = await res.json();
|
|
341
|
+
if (!res.ok) {
|
|
342
|
+
const code = typeof json["code"] === "string" ? json["code"] : "REGISTRY_ERROR";
|
|
343
|
+
const message = typeof json["error"] === "string" ? json["error"] : `HTTP ${res.status}`;
|
|
344
|
+
throw new AgentBnBError(message, code);
|
|
345
|
+
}
|
|
346
|
+
return json;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/credit/create-ledger.ts
|
|
351
|
+
function createLedger(opts) {
|
|
352
|
+
if ("registryUrl" in opts && opts.registryUrl !== void 0) {
|
|
353
|
+
return new RegistryCreditLedger({
|
|
354
|
+
mode: "http",
|
|
355
|
+
registryUrl: opts.registryUrl,
|
|
356
|
+
ownerPublicKey: opts.ownerPublicKey,
|
|
357
|
+
privateKey: opts.privateKey
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
if ("db" in opts && opts.db !== void 0) {
|
|
361
|
+
return new RegistryCreditLedger({
|
|
362
|
+
mode: "direct",
|
|
363
|
+
db: opts.db
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const db = openCreditDb(opts.creditDbPath);
|
|
367
|
+
return new LocalCreditLedger(db);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export {
|
|
371
|
+
identityAuthPlugin,
|
|
372
|
+
createLedger
|
|
373
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RelayMessageSchema
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QT7TEVNV.js";
|
|
4
4
|
|
|
5
5
|
// src/relay/websocket-client.ts
|
|
6
6
|
import WebSocket from "ws";
|
|
@@ -36,7 +36,8 @@ var RelayClient = class {
|
|
|
36
36
|
type: "register",
|
|
37
37
|
owner: this.opts.owner,
|
|
38
38
|
token: this.opts.token,
|
|
39
|
-
card: this.opts.card
|
|
39
|
+
card: this.opts.card,
|
|
40
|
+
...this.opts.cards && this.opts.cards.length > 0 ? { cards: this.opts.cards } : {}
|
|
40
41
|
});
|
|
41
42
|
});
|
|
42
43
|
this.ws.on("message", (raw) => {
|
|
@@ -101,13 +102,13 @@ var RelayClient = class {
|
|
|
101
102
|
throw new Error("Not connected to registry relay");
|
|
102
103
|
}
|
|
103
104
|
const id = randomUUID();
|
|
104
|
-
const timeoutMs = opts.timeoutMs ??
|
|
105
|
+
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
105
106
|
return new Promise((resolve, reject) => {
|
|
106
107
|
const timeout = setTimeout(() => {
|
|
107
108
|
this.pendingRequests.delete(id);
|
|
108
109
|
reject(new Error("Relay request timeout"));
|
|
109
110
|
}, timeoutMs);
|
|
110
|
-
this.pendingRequests.set(id, { resolve, reject, timeout });
|
|
111
|
+
this.pendingRequests.set(id, { resolve, reject, timeout, timeoutMs, onProgress: opts.onProgress });
|
|
111
112
|
this.send({
|
|
112
113
|
type: "relay_request",
|
|
113
114
|
id,
|
|
@@ -120,6 +121,22 @@ var RelayClient = class {
|
|
|
120
121
|
});
|
|
121
122
|
});
|
|
122
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Send a relay_progress message to the relay server for a given request.
|
|
126
|
+
* Used by the onRequest handler to forward SkillExecutor progress updates
|
|
127
|
+
* to the requesting agent so it can reset its timeout window.
|
|
128
|
+
*
|
|
129
|
+
* @param requestId - The relay request ID to associate progress with.
|
|
130
|
+
* @param info - Progress details (step, total, message).
|
|
131
|
+
*/
|
|
132
|
+
sendProgress(requestId, info) {
|
|
133
|
+
this.send({
|
|
134
|
+
type: "relay_progress",
|
|
135
|
+
id: requestId,
|
|
136
|
+
progress: Math.round(info.step / info.total * 100),
|
|
137
|
+
message: info.message
|
|
138
|
+
});
|
|
139
|
+
}
|
|
123
140
|
/** Whether the client is connected and registered */
|
|
124
141
|
get isConnected() {
|
|
125
142
|
return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
|
|
@@ -166,6 +183,9 @@ var RelayClient = class {
|
|
|
166
183
|
case "error":
|
|
167
184
|
this.handleError(msg);
|
|
168
185
|
break;
|
|
186
|
+
case "relay_progress":
|
|
187
|
+
this.handleProgress(msg);
|
|
188
|
+
break;
|
|
169
189
|
default:
|
|
170
190
|
break;
|
|
171
191
|
}
|
|
@@ -211,6 +231,19 @@ var RelayClient = class {
|
|
|
211
231
|
}
|
|
212
232
|
}
|
|
213
233
|
}
|
|
234
|
+
handleProgress(msg) {
|
|
235
|
+
const pending = this.pendingRequests.get(msg.id);
|
|
236
|
+
if (!pending) return;
|
|
237
|
+
clearTimeout(pending.timeout);
|
|
238
|
+
const newTimeout = setTimeout(() => {
|
|
239
|
+
this.pendingRequests.delete(msg.id);
|
|
240
|
+
pending.reject(new Error("Relay request timeout"));
|
|
241
|
+
}, pending.timeoutMs);
|
|
242
|
+
pending.timeout = newTimeout;
|
|
243
|
+
if (pending.onProgress) {
|
|
244
|
+
pending.onProgress({ id: msg.id, progress: msg.progress, message: msg.message });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
214
247
|
send(msg) {
|
|
215
248
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
216
249
|
this.ws.send(JSON.stringify(msg));
|
|
@@ -270,6 +303,7 @@ var RelayClient = class {
|
|
|
270
303
|
}, delay);
|
|
271
304
|
}
|
|
272
305
|
};
|
|
306
|
+
|
|
273
307
|
export {
|
|
274
308
|
RelayClient
|
|
275
309
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateKeyPair,
|
|
3
|
+
loadKeyPair,
|
|
4
|
+
saveKeyPair
|
|
5
|
+
} from "./chunk-5KFI5X7B.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) {
|
|
84
|
+
if (existing.owner !== owner) {
|
|
85
|
+
existing.owner = owner;
|
|
86
|
+
saveIdentity(configDir, existing);
|
|
87
|
+
}
|
|
88
|
+
return existing;
|
|
89
|
+
}
|
|
90
|
+
return createIdentity(configDir, owner);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
deriveAgentId,
|
|
95
|
+
ensureIdentity
|
|
96
|
+
};
|
|
@@ -4,8 +4,10 @@ var RegisterMessageSchema = z.object({
|
|
|
4
4
|
type: z.literal("register"),
|
|
5
5
|
owner: z.string().min(1),
|
|
6
6
|
token: z.string().min(1),
|
|
7
|
-
card: z.record(z.unknown())
|
|
7
|
+
card: z.record(z.unknown()),
|
|
8
8
|
// CapabilityCard (validated separately)
|
|
9
|
+
cards: z.array(z.record(z.unknown())).optional()
|
|
10
|
+
// Additional cards (e.g., conductor card)
|
|
9
11
|
});
|
|
10
12
|
var RegisteredMessageSchema = z.object({
|
|
11
13
|
type: z.literal("registered"),
|
|
@@ -55,6 +57,15 @@ var ErrorMessageSchema = z.object({
|
|
|
55
57
|
message: z.string(),
|
|
56
58
|
request_id: z.string().optional()
|
|
57
59
|
});
|
|
60
|
+
var RelayProgressMessageSchema = z.object({
|
|
61
|
+
type: z.literal("relay_progress"),
|
|
62
|
+
id: z.string().uuid(),
|
|
63
|
+
// request ID this progress relates to
|
|
64
|
+
progress: z.number().min(0).max(100).optional(),
|
|
65
|
+
// optional percentage
|
|
66
|
+
message: z.string().optional()
|
|
67
|
+
// optional status message
|
|
68
|
+
});
|
|
58
69
|
var RelayMessageSchema = z.discriminatedUnion("type", [
|
|
59
70
|
RegisterMessageSchema,
|
|
60
71
|
RegisteredMessageSchema,
|
|
@@ -62,7 +73,8 @@ var RelayMessageSchema = z.discriminatedUnion("type", [
|
|
|
62
73
|
IncomingRequestMessageSchema,
|
|
63
74
|
RelayResponseMessageSchema,
|
|
64
75
|
ResponseMessageSchema,
|
|
65
|
-
ErrorMessageSchema
|
|
76
|
+
ErrorMessageSchema,
|
|
77
|
+
RelayProgressMessageSchema
|
|
66
78
|
]);
|
|
67
79
|
|
|
68
80
|
export {
|
|
@@ -83,12 +83,45 @@ var SkillSchema = z.object({
|
|
|
83
83
|
*/
|
|
84
84
|
_internal: z.record(z.unknown()).optional()
|
|
85
85
|
});
|
|
86
|
+
var SuitabilitySchema = z.object({
|
|
87
|
+
/** Use cases this agent/skill is optimised for. */
|
|
88
|
+
ideal_for: z.array(z.string()).optional(),
|
|
89
|
+
/** Scenarios this agent/skill cannot reliably handle. */
|
|
90
|
+
not_suitable_for: z.array(z.string()).optional(),
|
|
91
|
+
/** Domains explicitly excluded (used for routing exclusions in later phases). */
|
|
92
|
+
excluded_domains: z.array(z.string()).optional(),
|
|
93
|
+
/** Conditions that increase failure risk, shown as warnings in the Hub. */
|
|
94
|
+
risk_conditions: z.array(z.string()).optional(),
|
|
95
|
+
/** Recommended alternative when this agent is unsuitable. */
|
|
96
|
+
fallback_recommendation: z.string().optional()
|
|
97
|
+
});
|
|
98
|
+
var LearningSchema = z.object({
|
|
99
|
+
/** Known limitations that may affect reliability (self-declared). */
|
|
100
|
+
known_limitations: z.array(z.string()).optional(),
|
|
101
|
+
/** Common failure patterns observed by the provider. */
|
|
102
|
+
common_failure_patterns: z.array(z.string()).optional(),
|
|
103
|
+
/** Version-tagged improvements the provider has shipped. */
|
|
104
|
+
recent_improvements: z.array(z.object({
|
|
105
|
+
version: z.string(),
|
|
106
|
+
summary: z.string(),
|
|
107
|
+
timestamp: z.string()
|
|
108
|
+
})).optional(),
|
|
109
|
+
/** Structured critiques from external sources (phase 2+). */
|
|
110
|
+
critiques: z.array(z.object({
|
|
111
|
+
type: z.literal("structured"),
|
|
112
|
+
summary: z.string(),
|
|
113
|
+
source_tier: z.string(),
|
|
114
|
+
timestamp: z.string()
|
|
115
|
+
})).optional()
|
|
116
|
+
});
|
|
86
117
|
var CapabilityCardV2Schema = z.object({
|
|
87
118
|
spec_version: z.literal("2.0"),
|
|
88
119
|
id: z.string().uuid(),
|
|
89
120
|
owner: z.string().min(1),
|
|
90
121
|
/** Agent display name — was 'name' in v1.0. */
|
|
91
122
|
agent_name: z.string().min(1).max(100),
|
|
123
|
+
/** Short one-liner shown in Hub v2 Identity Header. */
|
|
124
|
+
short_description: z.string().max(200).optional(),
|
|
92
125
|
/** At least one skill is required. */
|
|
93
126
|
skills: z.array(SkillSchema).min(1),
|
|
94
127
|
availability: z.object({
|
|
@@ -100,6 +133,10 @@ var CapabilityCardV2Schema = z.object({
|
|
|
100
133
|
runtime: z.string(),
|
|
101
134
|
region: z.string().optional()
|
|
102
135
|
}).optional(),
|
|
136
|
+
/** Suitability metadata for Hub v2 profile and future routing warnings. */
|
|
137
|
+
suitability: SuitabilitySchema.optional(),
|
|
138
|
+
/** Learning signals — self-declared limitations, improvements, critiques. */
|
|
139
|
+
learning: LearningSchema.optional(),
|
|
103
140
|
/**
|
|
104
141
|
* Private per-card metadata. Stripped from all API and CLI responses —
|
|
105
142
|
* never transmitted beyond the local store.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
signEscrowReceipt
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5KFI5X7B.js";
|
|
4
4
|
import {
|
|
5
5
|
AgentBnBError
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WGZ5AGOX.js";
|
|
7
7
|
|
|
8
8
|
// src/gateway/client.ts
|
|
9
9
|
import { randomUUID } from "crypto";
|
|
10
10
|
async function requestCapability(opts) {
|
|
11
|
-
const { gatewayUrl, token, cardId, params = {}, timeoutMs =
|
|
11
|
+
const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
|
|
12
12
|
const id = randomUUID();
|
|
13
13
|
const payload = {
|
|
14
14
|
jsonrpc: "2.0",
|
|
@@ -62,6 +62,7 @@ async function requestViaRelay(relay, opts) {
|
|
|
62
62
|
cardId: opts.cardId,
|
|
63
63
|
skillId: opts.skillId,
|
|
64
64
|
params: opts.params ?? {},
|
|
65
|
+
requester: opts.requester,
|
|
65
66
|
escrowReceipt: opts.escrowReceipt,
|
|
66
67
|
timeoutMs: opts.timeoutMs
|
|
67
68
|
});
|