agentbnb 8.2.0 → 8.2.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/{chunk-TBJ3FZKZ.js → chunk-7Q2XUXSA.js} +1 -1
- package/dist/{chunk-LJM7FHPM.js → chunk-BZOJ7HBT.js} +33 -1
- package/dist/{chunk-FTZTEHYG.js → chunk-DEWY7OQK.js} +135 -8
- package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
- package/dist/chunk-EZVOG7QS.js +161 -0
- package/dist/{chunk-E2OKP5CY.js → chunk-GJETGML6.js} +181 -83
- package/dist/{chunk-YHY7OG6S.js → chunk-GWMMYVLL.js} +4 -4
- package/dist/{chunk-D6RKW2XG.js → chunk-JLNHMNES.js} +16 -3
- package/dist/{chunk-5AAFG2V2.js → chunk-KBQNTUTN.js} +239 -24
- package/dist/{chunk-C537SFHV.js → chunk-LOUEJI6X.js} +4 -4
- package/dist/{chunk-ALX4WS3A.js → chunk-NP55V7RQ.js} +1 -1
- package/dist/{chunk-X32NE6V4.js → chunk-RBXTWWUH.js} +1 -1
- package/dist/{chunk-O2OYBAVR.js → chunk-SRBVKO2V.js} +9 -0
- package/dist/{chunk-7EF3HYVZ.js → chunk-STJLWMXH.js} +48 -4
- package/dist/{chunk-5GME4KJZ.js → chunk-UYCD3JBZ.js} +3 -3
- package/dist/{chunk-P4LOYSLA.js → chunk-WKWJWKX7.js} +286 -81
- package/dist/cli/index.js +35 -57
- package/dist/{client-HKV3QWZ3.js → client-66TFS7RS.js} +4 -2
- package/dist/{conduct-W6XF6DJW.js → conduct-A6COHLHY.js} +8 -8
- package/dist/{conduct-YB64OHI6.js → conduct-IUVAXUAV.js} +8 -8
- package/dist/{conductor-mode-TFCVCQHU.js → conductor-mode-D5TFQW5L.js} +2 -2
- package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-L2MB44BW.js} +7 -7
- package/dist/{execute-AYQWORVH.js → execute-5AWLARB5.js} +5 -5
- package/dist/{execute-EPE6MZLT.js → execute-WOS457HW.js} +2 -2
- package/dist/index.js +438 -92
- package/dist/{publish-capability-AH2HDW54.js → publish-capability-JJCBBMSX.js} +2 -2
- package/dist/{request-HCCXSKAY.js → request-6YQLA7K3.js} +13 -8
- package/dist/{serve-skill-SZAQT5T5.js → serve-skill-X7TZSILV.js} +5 -5
- package/dist/{server-LMY2A3GT.js → server-5TSP4DBX.js} +10 -12
- package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-WTUSMPY6.js} +69 -46
- package/dist/skills/agentbnb/bootstrap.js +459 -189
- package/package.json +13 -17
- package/skills/agentbnb/bootstrap.test.ts +8 -6
- package/skills/agentbnb/bootstrap.ts +21 -13
- package/skills/agentbnb/install.sh +0 -0
- package/dist/chunk-64AK4FJM.js +0 -84
- package/dist/chunk-OH7BP5NP.js +0 -96
- package/dist/index.d.ts +0 -5069
|
@@ -3,16 +3,17 @@ import {
|
|
|
3
3
|
} from "./chunk-3MJT4PZG.js";
|
|
4
4
|
import {
|
|
5
5
|
scorePeers
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UYCD3JBZ.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchRemoteCards
|
|
9
9
|
} from "./chunk-KF3TZHA5.js";
|
|
10
10
|
import {
|
|
11
11
|
searchCards
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BZOJ7HBT.js";
|
|
13
13
|
import {
|
|
14
|
-
requestCapability
|
|
15
|
-
|
|
14
|
+
requestCapability,
|
|
15
|
+
requestCapabilityBatch
|
|
16
|
+
} from "./chunk-EZVOG7QS.js";
|
|
16
17
|
|
|
17
18
|
// src/conductor/decomposition-validator.ts
|
|
18
19
|
function validateAndNormalizeSubtasks(raw, context) {
|
|
@@ -410,6 +411,65 @@ function computeWaves(subtasks) {
|
|
|
410
411
|
}
|
|
411
412
|
return waves;
|
|
412
413
|
}
|
|
414
|
+
async function executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl) {
|
|
415
|
+
const { taskId, match: m, interpolatedParams, primary, teamId, capabilityType } = pt;
|
|
416
|
+
try {
|
|
417
|
+
let res;
|
|
418
|
+
if (primary.url.startsWith("relay://") && relayClient) {
|
|
419
|
+
const targetOwner = primary.url.replace("relay://", "");
|
|
420
|
+
res = await relayClient.request({
|
|
421
|
+
targetOwner,
|
|
422
|
+
cardId: primary.cardId,
|
|
423
|
+
params: interpolatedParams,
|
|
424
|
+
requester: requesterOwner,
|
|
425
|
+
timeoutMs
|
|
426
|
+
});
|
|
427
|
+
} else {
|
|
428
|
+
res = await requestCapability({
|
|
429
|
+
gatewayUrl: primary.url,
|
|
430
|
+
token: gatewayToken,
|
|
431
|
+
cardId: primary.cardId,
|
|
432
|
+
params: { ...interpolatedParams, requester: requesterOwner },
|
|
433
|
+
timeoutMs
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: capabilityType };
|
|
437
|
+
} catch (primaryErr) {
|
|
438
|
+
if (m.alternatives.length > 0) {
|
|
439
|
+
const alt = m.alternatives[0];
|
|
440
|
+
const altResolved = resolveAgentUrl ? resolveAgentUrl(alt.agent) : { url: `http://${alt.agent}:7700`, cardId: `card-${alt.agent}` };
|
|
441
|
+
try {
|
|
442
|
+
let altRes;
|
|
443
|
+
if (altResolved.url.startsWith("relay://") && relayClient) {
|
|
444
|
+
const targetOwner = altResolved.url.replace("relay://", "");
|
|
445
|
+
altRes = await relayClient.request({
|
|
446
|
+
targetOwner,
|
|
447
|
+
cardId: altResolved.cardId,
|
|
448
|
+
params: interpolatedParams,
|
|
449
|
+
requester: requesterOwner,
|
|
450
|
+
timeoutMs
|
|
451
|
+
});
|
|
452
|
+
} else {
|
|
453
|
+
altRes = await requestCapability({
|
|
454
|
+
gatewayUrl: altResolved.url,
|
|
455
|
+
token: gatewayToken,
|
|
456
|
+
cardId: altResolved.cardId,
|
|
457
|
+
params: { ...interpolatedParams, requester: requesterOwner },
|
|
458
|
+
timeoutMs
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: capabilityType };
|
|
462
|
+
} catch (altErr) {
|
|
463
|
+
throw new Error(
|
|
464
|
+
`Task ${taskId}: primary (${m.selected_agent}) failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}; alternative (${alt.agent}) failed: ${altErr instanceof Error ? altErr.message : String(altErr)}`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
throw new Error(
|
|
469
|
+
`Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
413
473
|
async function orchestrate(opts) {
|
|
414
474
|
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
|
|
415
475
|
const startTime = Date.now();
|
|
@@ -447,89 +507,127 @@ async function orchestrate(opts) {
|
|
|
447
507
|
}
|
|
448
508
|
executableIds.push(taskId);
|
|
449
509
|
}
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const
|
|
510
|
+
const preparedTasks = [];
|
|
511
|
+
for (const taskId of executableIds) {
|
|
512
|
+
const subtask = subtaskMap.get(taskId);
|
|
513
|
+
const m = matches.get(taskId);
|
|
514
|
+
if (!m) {
|
|
515
|
+
errors.push(`No match found for subtask ${taskId}`);
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
const stepsContext = {};
|
|
519
|
+
for (const [id, val] of results) stepsContext[id] = val;
|
|
520
|
+
const interpContext = { steps: stepsContext, prev: void 0 };
|
|
521
|
+
if (subtask.depends_on.length > 0) {
|
|
522
|
+
const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
|
|
523
|
+
interpContext.prev = results.get(lastDep);
|
|
524
|
+
}
|
|
525
|
+
const interpolatedParams = interpolateObject(
|
|
526
|
+
subtask.params,
|
|
527
|
+
interpContext
|
|
528
|
+
);
|
|
529
|
+
const teamMember = teamMemberMap.get(taskId);
|
|
530
|
+
const agentOwner = teamMember?.agent ?? m.selected_agent;
|
|
531
|
+
const primary = resolveAgentUrl(agentOwner);
|
|
532
|
+
preparedTasks.push({
|
|
533
|
+
taskId,
|
|
534
|
+
subtask,
|
|
535
|
+
match: m,
|
|
536
|
+
interpolatedParams,
|
|
537
|
+
agentOwner,
|
|
538
|
+
primary,
|
|
539
|
+
teamId: opts.team?.team_id ?? null,
|
|
540
|
+
capabilityType: teamMember?.capability_type ?? null
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
const httpGroups = /* @__PURE__ */ new Map();
|
|
544
|
+
const relayTasks = [];
|
|
545
|
+
for (const pt of preparedTasks) {
|
|
546
|
+
if (pt.primary.url.startsWith("relay://") && relayClient) {
|
|
547
|
+
relayTasks.push(pt);
|
|
548
|
+
} else {
|
|
549
|
+
const group = httpGroups.get(pt.primary.url) ?? [];
|
|
550
|
+
group.push(pt);
|
|
551
|
+
httpGroups.set(pt.primary.url, group);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const batchPromises = [];
|
|
555
|
+
for (const [gatewayUrl, group] of httpGroups) {
|
|
556
|
+
if (group.length >= 2) {
|
|
557
|
+
batchPromises.push(
|
|
558
|
+
(async () => {
|
|
559
|
+
const items = group.map((pt) => ({
|
|
560
|
+
id: pt.taskId,
|
|
561
|
+
cardId: pt.primary.cardId,
|
|
562
|
+
params: { ...pt.interpolatedParams, requester: requesterOwner },
|
|
563
|
+
_pt: pt
|
|
564
|
+
}));
|
|
500
565
|
try {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
cardId: altAgent.cardId,
|
|
507
|
-
params: interpolatedParams,
|
|
508
|
-
requester: requesterOwner,
|
|
509
|
-
timeoutMs
|
|
510
|
-
});
|
|
511
|
-
} else {
|
|
512
|
-
altRes = await requestCapability({
|
|
513
|
-
gatewayUrl: altAgent.url,
|
|
514
|
-
token: gatewayToken,
|
|
515
|
-
cardId: altAgent.cardId,
|
|
516
|
-
params: { ...interpolatedParams, requester: requesterOwner },
|
|
517
|
-
timeoutMs
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
521
|
-
} catch (altErr) {
|
|
522
|
-
throw new Error(
|
|
523
|
-
`Task ${taskId}: primary (${m.selected_agent}) failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}; alternative (${alt.agent}) failed: ${altErr instanceof Error ? altErr.message : String(altErr)}`
|
|
566
|
+
const batchResults = await requestCapabilityBatch(
|
|
567
|
+
gatewayUrl,
|
|
568
|
+
gatewayToken,
|
|
569
|
+
items.map(({ _pt, ...item }) => item),
|
|
570
|
+
{ timeoutMs }
|
|
524
571
|
);
|
|
572
|
+
return items.map((item) => {
|
|
573
|
+
const res = batchResults.get(item.id);
|
|
574
|
+
if (res instanceof Error) {
|
|
575
|
+
return {
|
|
576
|
+
status: "rejected",
|
|
577
|
+
reason: new Error(`Task ${item.id}: ${res.message}`)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
status: "fulfilled",
|
|
582
|
+
value: {
|
|
583
|
+
taskId: item.id,
|
|
584
|
+
result: res,
|
|
585
|
+
credits: item._pt.match.credits,
|
|
586
|
+
team_id: item._pt.teamId,
|
|
587
|
+
capability_type: item._pt.capabilityType
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
});
|
|
591
|
+
} catch (batchErr) {
|
|
592
|
+
return Promise.all(group.map(async (pt) => {
|
|
593
|
+
try {
|
|
594
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
595
|
+
return { status: "fulfilled", value: res };
|
|
596
|
+
} catch (err) {
|
|
597
|
+
return { status: "rejected", reason: err };
|
|
598
|
+
}
|
|
599
|
+
}));
|
|
600
|
+
}
|
|
601
|
+
})()
|
|
602
|
+
);
|
|
603
|
+
} else {
|
|
604
|
+
const pt = group[0];
|
|
605
|
+
batchPromises.push(
|
|
606
|
+
(async () => {
|
|
607
|
+
try {
|
|
608
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
609
|
+
return [{ status: "fulfilled", value: res }];
|
|
610
|
+
} catch (err) {
|
|
611
|
+
return [{ status: "rejected", reason: err }];
|
|
525
612
|
}
|
|
613
|
+
})()
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
for (const pt of relayTasks) {
|
|
618
|
+
batchPromises.push(
|
|
619
|
+
(async () => {
|
|
620
|
+
try {
|
|
621
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
622
|
+
return [{ status: "fulfilled", value: res }];
|
|
623
|
+
} catch (err) {
|
|
624
|
+
return [{ status: "rejected", reason: err }];
|
|
526
625
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
);
|
|
626
|
+
})()
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
const allBatchResults = await Promise.all(batchPromises);
|
|
630
|
+
const waveResults = allBatchResults.flat();
|
|
533
631
|
for (const settlement of waveResults) {
|
|
534
632
|
if (settlement.status === "fulfilled") {
|
|
535
633
|
const { taskId, result, credits, team_id, capability_type } = settlement.value;
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
decompose,
|
|
8
8
|
matchSubTasks,
|
|
9
9
|
orchestrate
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GJETGML6.js";
|
|
11
11
|
import {
|
|
12
12
|
BudgetManager
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UYCD3JBZ.js";
|
|
14
14
|
import {
|
|
15
15
|
openCreditDb
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-JLNHMNES.js";
|
|
17
17
|
import {
|
|
18
18
|
loadPeers
|
|
19
19
|
} from "./chunk-5AH3CMOX.js";
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from "./chunk-75OC6E4F.js";
|
|
23
23
|
import {
|
|
24
24
|
openDatabase
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-SRBVKO2V.js";
|
|
26
26
|
|
|
27
27
|
// src/cli/conduct.ts
|
|
28
28
|
async function conductAction(task, opts) {
|
|
@@ -149,10 +149,23 @@ function getBalance(db, owner) {
|
|
|
149
149
|
const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
|
|
150
150
|
return row?.balance ?? 0;
|
|
151
151
|
}
|
|
152
|
-
function getTransactions(db, owner,
|
|
152
|
+
function getTransactions(db, owner, opts = 100) {
|
|
153
|
+
const page = typeof opts === "number" ? { limit: opts } : opts;
|
|
154
|
+
const limit = page.limit ?? 100;
|
|
155
|
+
const conditions = ["owner = ?"];
|
|
156
|
+
const params = [owner];
|
|
157
|
+
if (page.before) {
|
|
158
|
+
conditions.push("created_at < ?");
|
|
159
|
+
params.push(page.before);
|
|
160
|
+
}
|
|
161
|
+
if (page.after) {
|
|
162
|
+
conditions.push("created_at > ?");
|
|
163
|
+
params.push(page.after);
|
|
164
|
+
}
|
|
165
|
+
params.push(limit);
|
|
153
166
|
return db.prepare(
|
|
154
|
-
|
|
155
|
-
).all(
|
|
167
|
+
`SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
|
|
168
|
+
).all(...params);
|
|
156
169
|
}
|
|
157
170
|
function registerProvider(db, owner) {
|
|
158
171
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3,19 +3,154 @@ import {
|
|
|
3
3
|
getBalance,
|
|
4
4
|
getTransactions,
|
|
5
5
|
holdEscrow,
|
|
6
|
+
lookupAgent,
|
|
6
7
|
migrateOwner,
|
|
7
8
|
openCreditDb,
|
|
8
9
|
releaseEscrow,
|
|
9
10
|
settleEscrow
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-JLNHMNES.js";
|
|
11
12
|
import {
|
|
13
|
+
generateKeyPair,
|
|
14
|
+
loadKeyPair,
|
|
15
|
+
saveKeyPair,
|
|
12
16
|
signEscrowReceipt,
|
|
13
17
|
verifyEscrowReceipt
|
|
14
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-EJKW57ZV.js";
|
|
15
19
|
import {
|
|
16
20
|
AgentBnBError
|
|
17
21
|
} from "./chunk-WVY2W7AA.js";
|
|
18
22
|
|
|
23
|
+
// src/identity/identity.ts
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
import { createHash, createPrivateKey, createPublicKey } from "crypto";
|
|
26
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
27
|
+
import { join } from "path";
|
|
28
|
+
var AgentIdentitySchema = z.object({
|
|
29
|
+
/** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
|
|
30
|
+
agent_id: z.string().min(1),
|
|
31
|
+
/** Human-readable owner name (from config or init). */
|
|
32
|
+
owner: z.string().min(1),
|
|
33
|
+
/** Hex-encoded Ed25519 public key. */
|
|
34
|
+
public_key: z.string().min(1),
|
|
35
|
+
/** ISO 8601 timestamp of identity creation. */
|
|
36
|
+
created_at: z.string().datetime(),
|
|
37
|
+
/** Optional guarantor info if linked to a human. */
|
|
38
|
+
guarantor: z.object({
|
|
39
|
+
github_login: z.string().min(1),
|
|
40
|
+
verified_at: z.string().datetime()
|
|
41
|
+
}).optional()
|
|
42
|
+
});
|
|
43
|
+
var AgentCertificateSchema = z.object({
|
|
44
|
+
identity: AgentIdentitySchema,
|
|
45
|
+
/** ISO 8601 timestamp of certificate issuance. */
|
|
46
|
+
issued_at: z.string().datetime(),
|
|
47
|
+
/** ISO 8601 timestamp of certificate expiry. */
|
|
48
|
+
expires_at: z.string().datetime(),
|
|
49
|
+
/** Hex-encoded public key of the issuer (same as identity for self-signed). */
|
|
50
|
+
issuer_public_key: z.string().min(1),
|
|
51
|
+
/** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
|
|
52
|
+
signature: z.string().min(1)
|
|
53
|
+
});
|
|
54
|
+
var IDENTITY_FILENAME = "identity.json";
|
|
55
|
+
var PRIVATE_KEY_FILENAME = "private.key";
|
|
56
|
+
var PUBLIC_KEY_FILENAME = "public.key";
|
|
57
|
+
function derivePublicKeyFromPrivate(privateKey) {
|
|
58
|
+
const privateKeyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
|
|
59
|
+
const publicKeyObject = createPublicKey(privateKeyObject);
|
|
60
|
+
const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
|
|
61
|
+
return Buffer.from(publicKey);
|
|
62
|
+
}
|
|
63
|
+
function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
|
|
64
|
+
const publicKeyHex = publicKey.toString("hex");
|
|
65
|
+
return {
|
|
66
|
+
agent_id: deriveAgentId(publicKeyHex),
|
|
67
|
+
owner,
|
|
68
|
+
public_key: publicKeyHex,
|
|
69
|
+
created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function generateFreshIdentity(configDir, owner) {
|
|
73
|
+
const keys = generateKeyPair();
|
|
74
|
+
saveKeyPair(configDir, keys);
|
|
75
|
+
const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
|
|
76
|
+
saveIdentity(configDir, identity);
|
|
77
|
+
return { identity, keys, status: "generated" };
|
|
78
|
+
}
|
|
79
|
+
function deriveAgentId(publicKeyHex) {
|
|
80
|
+
return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
|
|
81
|
+
}
|
|
82
|
+
function loadIdentity(configDir) {
|
|
83
|
+
const filePath = join(configDir, IDENTITY_FILENAME);
|
|
84
|
+
if (!existsSync(filePath)) return null;
|
|
85
|
+
try {
|
|
86
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
87
|
+
return AgentIdentitySchema.parse(JSON.parse(raw));
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function saveIdentity(configDir, identity) {
|
|
93
|
+
if (!existsSync(configDir)) {
|
|
94
|
+
mkdirSync(configDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
const filePath = join(configDir, IDENTITY_FILENAME);
|
|
97
|
+
writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
|
|
98
|
+
}
|
|
99
|
+
function loadOrRepairIdentity(configDir, ownerHint) {
|
|
100
|
+
if (!existsSync(configDir)) {
|
|
101
|
+
mkdirSync(configDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
const identityPath = join(configDir, IDENTITY_FILENAME);
|
|
104
|
+
const privateKeyPath = join(configDir, PRIVATE_KEY_FILENAME);
|
|
105
|
+
const publicKeyPath = join(configDir, PUBLIC_KEY_FILENAME);
|
|
106
|
+
const hasIdentity = existsSync(identityPath);
|
|
107
|
+
const hasPrivateKey = existsSync(privateKeyPath);
|
|
108
|
+
const hasPublicKey = existsSync(publicKeyPath);
|
|
109
|
+
if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
|
|
110
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
111
|
+
}
|
|
112
|
+
let keys;
|
|
113
|
+
try {
|
|
114
|
+
keys = loadKeyPair(configDir);
|
|
115
|
+
} catch {
|
|
116
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
117
|
+
}
|
|
118
|
+
let derivedPublicKey;
|
|
119
|
+
try {
|
|
120
|
+
derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
|
|
121
|
+
} catch {
|
|
122
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
123
|
+
}
|
|
124
|
+
let keypairRepaired = false;
|
|
125
|
+
if (!keys.publicKey.equals(derivedPublicKey)) {
|
|
126
|
+
keypairRepaired = true;
|
|
127
|
+
keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
|
|
128
|
+
saveKeyPair(configDir, keys);
|
|
129
|
+
}
|
|
130
|
+
const loadedIdentity = loadIdentity(configDir);
|
|
131
|
+
const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
|
|
132
|
+
const expectedPublicKeyHex = derivedPublicKey.toString("hex");
|
|
133
|
+
const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
|
|
134
|
+
if (identityMismatch) {
|
|
135
|
+
const repairedIdentity = buildIdentityFromPublicKey(
|
|
136
|
+
derivedPublicKey,
|
|
137
|
+
loadedIdentity?.owner ?? ownerHint ?? "agent",
|
|
138
|
+
loadedIdentity?.created_at
|
|
139
|
+
);
|
|
140
|
+
saveIdentity(configDir, repairedIdentity);
|
|
141
|
+
return { identity: repairedIdentity, keys, status: "repaired" };
|
|
142
|
+
}
|
|
143
|
+
if (ownerHint && loadedIdentity.owner !== ownerHint) {
|
|
144
|
+
const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
|
|
145
|
+
saveIdentity(configDir, updatedIdentity);
|
|
146
|
+
return { identity: updatedIdentity, keys, status: "repaired" };
|
|
147
|
+
}
|
|
148
|
+
return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
|
|
149
|
+
}
|
|
150
|
+
function ensureIdentity(configDir, owner) {
|
|
151
|
+
return loadOrRepairIdentity(configDir, owner).identity;
|
|
152
|
+
}
|
|
153
|
+
|
|
19
154
|
// src/credit/local-credit-ledger.ts
|
|
20
155
|
var LocalCreditLedger = class {
|
|
21
156
|
constructor(db) {
|
|
@@ -91,11 +226,57 @@ var LocalCreditLedger = class {
|
|
|
91
226
|
|
|
92
227
|
// src/registry/identity-auth.ts
|
|
93
228
|
var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
229
|
+
function normalizeSignedParams(body) {
|
|
230
|
+
return body === void 0 ? null : body;
|
|
231
|
+
}
|
|
232
|
+
function buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, params) {
|
|
233
|
+
return {
|
|
234
|
+
method,
|
|
235
|
+
path,
|
|
236
|
+
timestamp,
|
|
237
|
+
publicKey: publicKeyHex,
|
|
238
|
+
agentId,
|
|
239
|
+
params: normalizeSignedParams(params)
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function extractClaimedRequester(request) {
|
|
243
|
+
const extractFromObject = (obj) => {
|
|
244
|
+
const directOwner = typeof obj.owner === "string" ? obj.owner.trim() : "";
|
|
245
|
+
if (directOwner) return directOwner;
|
|
246
|
+
const directRequester = typeof obj.requester === "string" ? obj.requester.trim() : "";
|
|
247
|
+
if (directRequester) return directRequester;
|
|
248
|
+
const oldOwner = typeof obj.oldOwner === "string" ? obj.oldOwner.trim() : "";
|
|
249
|
+
if (oldOwner) return oldOwner;
|
|
250
|
+
const nestedParams = obj.params;
|
|
251
|
+
if (nestedParams && typeof nestedParams === "object" && !Array.isArray(nestedParams)) {
|
|
252
|
+
const nested = nestedParams;
|
|
253
|
+
const nestedOwner = typeof nested.owner === "string" ? nested.owner.trim() : "";
|
|
254
|
+
if (nestedOwner) return nestedOwner;
|
|
255
|
+
const nestedRequester = typeof nested.requester === "string" ? nested.requester.trim() : "";
|
|
256
|
+
if (nestedRequester) return nestedRequester;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
};
|
|
260
|
+
if (request.body && typeof request.body === "object" && !Array.isArray(request.body)) {
|
|
261
|
+
const claimed = extractFromObject(request.body);
|
|
262
|
+
if (claimed) return claimed;
|
|
263
|
+
}
|
|
264
|
+
if (request.params && typeof request.params === "object" && !Array.isArray(request.params)) {
|
|
265
|
+
const claimed = extractFromObject(request.params);
|
|
266
|
+
if (claimed) return claimed;
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
async function verifyIdentity(request, reply, options) {
|
|
271
|
+
const agentIdHeader = request.headers["x-agent-id"];
|
|
272
|
+
const publicKeyHeader = request.headers["x-agent-publickey"];
|
|
273
|
+
const signatureHeader = request.headers["x-agent-signature"];
|
|
274
|
+
const timestampHeader = request.headers["x-agent-timestamp"];
|
|
275
|
+
const agentId = agentIdHeader?.trim();
|
|
276
|
+
const publicKeyHex = publicKeyHeader?.trim();
|
|
277
|
+
const signature = signatureHeader?.trim();
|
|
278
|
+
const timestamp = timestampHeader?.trim();
|
|
279
|
+
if (!agentId || !publicKeyHex || !signature || !timestamp) {
|
|
99
280
|
await reply.code(401).send({ error: "Missing identity headers" });
|
|
100
281
|
return false;
|
|
101
282
|
}
|
|
@@ -104,12 +285,21 @@ async function verifyIdentity(request, reply) {
|
|
|
104
285
|
await reply.code(401).send({ error: "Request expired" });
|
|
105
286
|
return false;
|
|
106
287
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
288
|
+
if (!/^[0-9a-fA-F]+$/.test(publicKeyHex) || publicKeyHex.length % 2 !== 0) {
|
|
289
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
let expectedAgentId;
|
|
293
|
+
try {
|
|
294
|
+
expectedAgentId = deriveAgentId(publicKeyHex);
|
|
295
|
+
} catch {
|
|
296
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (agentId !== expectedAgentId) {
|
|
300
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
113
303
|
let publicKeyBuffer;
|
|
114
304
|
try {
|
|
115
305
|
publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
|
|
@@ -117,30 +307,52 @@ async function verifyIdentity(request, reply) {
|
|
|
117
307
|
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
118
308
|
return false;
|
|
119
309
|
}
|
|
310
|
+
const knownAgent = options.agentDb ? lookupAgent(options.agentDb, agentId) : null;
|
|
311
|
+
if (knownAgent && knownAgent.public_key.toLowerCase() !== publicKeyHex.toLowerCase()) {
|
|
312
|
+
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const payload = buildIdentityPayload(
|
|
316
|
+
request.method,
|
|
317
|
+
request.url,
|
|
318
|
+
timestamp,
|
|
319
|
+
publicKeyHex,
|
|
320
|
+
agentId,
|
|
321
|
+
request.body
|
|
322
|
+
);
|
|
120
323
|
const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
|
|
121
324
|
if (!valid) {
|
|
122
325
|
await reply.code(401).send({ error: "Invalid identity signature" });
|
|
123
326
|
return false;
|
|
124
327
|
}
|
|
328
|
+
const claimedRequester = extractClaimedRequester(request);
|
|
329
|
+
if (claimedRequester) {
|
|
330
|
+
const matchesAgentId = claimedRequester === agentId;
|
|
331
|
+
const matchesLegacyOwner = knownAgent?.legacy_owner === claimedRequester;
|
|
332
|
+
if (!matchesAgentId && !matchesLegacyOwner) {
|
|
333
|
+
await reply.code(401).send({ error: "Identity does not match requester" });
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
125
337
|
request.agentPublicKey = publicKeyHex;
|
|
338
|
+
request.agentId = agentId;
|
|
126
339
|
return true;
|
|
127
340
|
}
|
|
128
|
-
function identityAuthPlugin(fastify) {
|
|
129
|
-
fastify.addHook("
|
|
130
|
-
await verifyIdentity(request, reply);
|
|
341
|
+
function identityAuthPlugin(fastify, options = {}) {
|
|
342
|
+
fastify.addHook("preHandler", async (request, reply) => {
|
|
343
|
+
const ok = await verifyIdentity(request, reply, options);
|
|
344
|
+
if (!ok) {
|
|
345
|
+
return reply;
|
|
346
|
+
}
|
|
131
347
|
});
|
|
132
348
|
}
|
|
133
|
-
function signRequest(method, path, body, privateKey, publicKeyHex) {
|
|
349
|
+
function signRequest(method, path, body, privateKey, publicKeyHex, agentIdOverride) {
|
|
134
350
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
path,
|
|
138
|
-
timestamp,
|
|
139
|
-
publicKey: publicKeyHex
|
|
140
|
-
};
|
|
141
|
-
void body;
|
|
351
|
+
const agentId = agentIdOverride ?? deriveAgentId(publicKeyHex);
|
|
352
|
+
const payload = buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, body);
|
|
142
353
|
const signature = signEscrowReceipt(payload, privateKey);
|
|
143
354
|
return {
|
|
355
|
+
"X-Agent-Id": agentId,
|
|
144
356
|
"X-Agent-PublicKey": publicKeyHex,
|
|
145
357
|
"X-Agent-Signature": signature,
|
|
146
358
|
"X-Agent-Timestamp": timestamp
|
|
@@ -368,6 +580,9 @@ function createLedger(opts) {
|
|
|
368
580
|
}
|
|
369
581
|
|
|
370
582
|
export {
|
|
583
|
+
deriveAgentId,
|
|
584
|
+
loadOrRepairIdentity,
|
|
585
|
+
ensureIdentity,
|
|
371
586
|
identityAuthPlugin,
|
|
372
587
|
createLedger
|
|
373
588
|
};
|