agentbnb 8.2.0 → 8.2.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/dist/{chunk-TBJ3FZKZ.js → chunk-4IPJJRTP.js} +1 -1
- package/dist/chunk-CKOOVZOI.js +158 -0
- package/dist/chunk-CQFBNTGT.js +145 -0
- package/dist/{chunk-P4LOYSLA.js → chunk-DYQOFGGI.js} +331 -416
- package/dist/{chunk-ALX4WS3A.js → chunk-EG6RS4JC.js} +70 -46
- package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
- package/dist/{chunk-5AAFG2V2.js → chunk-LKLKYXLV.js} +239 -24
- package/dist/{chunk-7EF3HYVZ.js → chunk-MCED4GDW.js} +499 -86
- package/dist/{chunk-YHY7OG6S.js → chunk-MWOXW7JQ.js} +7 -7
- package/dist/{chunk-E2OKP5CY.js → chunk-QCGIG7WW.js} +182 -86
- package/dist/{chunk-5GME4KJZ.js → chunk-QHZGOG3O.js} +148 -46
- package/dist/{chunk-D6RKW2XG.js → chunk-RYISHSHB.js} +302 -4
- package/dist/{chunk-O2OYBAVR.js → chunk-S3V6R3EN.js} +75 -39
- package/dist/{chunk-X32NE6V4.js → chunk-WNXXLCV5.js} +1 -1
- package/dist/{chunk-C537SFHV.js → chunk-XBGVQMQJ.js} +72 -48
- package/dist/{chunk-FTZTEHYG.js → chunk-Z2GEFFDO.js} +135 -8
- package/dist/cli/index.js +42 -67
- package/dist/{client-HKV3QWZ3.js → client-XOLP5IUZ.js} +4 -2
- package/dist/{conduct-W6XF6DJW.js → conduct-AZFLNUX3.js} +10 -11
- package/dist/{conduct-YB64OHI6.js → conduct-VPUYTNEA.js} +10 -11
- package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-PLTB6MS3.js} +7 -8
- package/dist/{conductor-mode-TFCVCQHU.js → conductor-mode-WKB42PYM.js} +6 -3
- package/dist/{execute-EPE6MZLT.js → execute-NNDCXTN4.js} +3 -2
- package/dist/{execute-AYQWORVH.js → execute-RIRHTIBU.js} +6 -5
- package/dist/index.d.ts +8 -8
- package/dist/index.js +637 -693
- package/dist/{publish-capability-AH2HDW54.js → publish-capability-QDR2QIZ2.js} +2 -2
- package/dist/{request-HCCXSKAY.js → request-NX7GSPIG.js} +31 -36
- package/dist/{serve-skill-SZAQT5T5.js → serve-skill-E6EJQYAK.js} +10 -9
- package/dist/{server-LMY2A3GT.js → server-VBCT32FC.js} +12 -18
- package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-KMSA6BST.js} +137 -69
- package/dist/skills/agentbnb/bootstrap.js +561 -247
- 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-KF3TZHA5.js +0 -91
- package/dist/chunk-LJM7FHPM.js +0 -138
- package/dist/chunk-OH7BP5NP.js +0 -96
package/dist/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RelayClient,
|
|
3
|
+
RelayMessageSchema
|
|
4
|
+
} from "./chunk-3LWBH7P3.js";
|
|
5
|
+
|
|
1
6
|
// src/types/index.ts
|
|
2
7
|
import { z } from "zod";
|
|
3
8
|
var IOSchemaSchema = z.object({
|
|
@@ -351,7 +356,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
351
356
|
new.id,
|
|
352
357
|
new.owner,
|
|
353
358
|
COALESCE(
|
|
354
|
-
(SELECT group_concat(
|
|
359
|
+
(SELECT group_concat(
|
|
360
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
361
|
+
' '
|
|
362
|
+
)
|
|
355
363
|
FROM json_each(json_extract(new.data, '$.skills'))),
|
|
356
364
|
json_extract(new.data, '$.name'),
|
|
357
365
|
''
|
|
@@ -391,7 +399,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
391
399
|
old.id,
|
|
392
400
|
old.owner,
|
|
393
401
|
COALESCE(
|
|
394
|
-
(SELECT group_concat(
|
|
402
|
+
(SELECT group_concat(
|
|
403
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
404
|
+
' '
|
|
405
|
+
)
|
|
395
406
|
FROM json_each(json_extract(old.data, '$.skills'))),
|
|
396
407
|
json_extract(old.data, '$.name'),
|
|
397
408
|
''
|
|
@@ -427,7 +438,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
427
438
|
new.id,
|
|
428
439
|
new.owner,
|
|
429
440
|
COALESCE(
|
|
430
|
-
(SELECT group_concat(
|
|
441
|
+
(SELECT group_concat(
|
|
442
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
443
|
+
' '
|
|
444
|
+
)
|
|
431
445
|
FROM json_each(json_extract(new.data, '$.skills'))),
|
|
432
446
|
json_extract(new.data, '$.name'),
|
|
433
447
|
''
|
|
@@ -467,7 +481,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
467
481
|
old.id,
|
|
468
482
|
old.owner,
|
|
469
483
|
COALESCE(
|
|
470
|
-
(SELECT group_concat(
|
|
484
|
+
(SELECT group_concat(
|
|
485
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
486
|
+
' '
|
|
487
|
+
)
|
|
471
488
|
FROM json_each(json_extract(old.data, '$.skills'))),
|
|
472
489
|
json_extract(old.data, '$.name'),
|
|
473
490
|
''
|
|
@@ -534,6 +551,15 @@ function openDatabase(path = ":memory:") {
|
|
|
534
551
|
tags,
|
|
535
552
|
content=""
|
|
536
553
|
);
|
|
554
|
+
|
|
555
|
+
-- Expression index for capability_type lookups (used by Conductor routing).
|
|
556
|
+
-- Turns json_extract full-table-scan into O(log n) B-tree lookup.
|
|
557
|
+
CREATE INDEX IF NOT EXISTS idx_cards_capability_type
|
|
558
|
+
ON capability_cards(json_extract(data, '$.capability_type'));
|
|
559
|
+
|
|
560
|
+
-- Owner index for listCards(owner) and other owner-scoped queries.
|
|
561
|
+
CREATE INDEX IF NOT EXISTS idx_cards_owner
|
|
562
|
+
ON capability_cards(owner);
|
|
537
563
|
`);
|
|
538
564
|
createRequestLogTable(db);
|
|
539
565
|
initFeedbackTable(db);
|
|
@@ -545,6 +571,10 @@ function runMigrations(db) {
|
|
|
545
571
|
const version = db.pragma("user_version")[0]?.user_version ?? 0;
|
|
546
572
|
if (version < 2) {
|
|
547
573
|
migrateV1toV2(db);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (version < 3) {
|
|
577
|
+
migrateV2toV3(db);
|
|
548
578
|
}
|
|
549
579
|
}
|
|
550
580
|
function migrateV1toV2(db) {
|
|
@@ -586,44 +616,55 @@ function migrateV1toV2(db) {
|
|
|
586
616
|
);
|
|
587
617
|
}
|
|
588
618
|
db.exec(V2_FTS_TRIGGERS);
|
|
589
|
-
db
|
|
590
|
-
|
|
591
|
-
const ftsInsert = db.prepare(
|
|
592
|
-
"INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
|
|
593
|
-
);
|
|
594
|
-
for (const row of allRows) {
|
|
595
|
-
const data = JSON.parse(row.data);
|
|
596
|
-
const skills = data["skills"] ?? [];
|
|
597
|
-
let name;
|
|
598
|
-
let description;
|
|
599
|
-
let tags;
|
|
600
|
-
if (skills.length > 0) {
|
|
601
|
-
name = skills.map((s) => String(s["name"] ?? "")).join(" ");
|
|
602
|
-
description = skills.map((s) => String(s["description"] ?? "")).join(" ");
|
|
603
|
-
tags = [
|
|
604
|
-
// tags from metadata.tags[]
|
|
605
|
-
...skills.flatMap((s) => {
|
|
606
|
-
const meta = s["metadata"];
|
|
607
|
-
return meta?.["tags"] ?? [];
|
|
608
|
-
}),
|
|
609
|
-
// capability_type (singular)
|
|
610
|
-
...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
|
|
611
|
-
// capability_types[] (plural)
|
|
612
|
-
...skills.flatMap((s) => s["capability_types"] ?? [])
|
|
613
|
-
].join(" ");
|
|
614
|
-
} else {
|
|
615
|
-
name = String(data["name"] ?? "");
|
|
616
|
-
description = String(data["description"] ?? "");
|
|
617
|
-
const meta = data["metadata"];
|
|
618
|
-
const rawTags = meta?.["tags"] ?? [];
|
|
619
|
-
tags = rawTags.join(" ");
|
|
620
|
-
}
|
|
621
|
-
ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
|
|
622
|
-
}
|
|
623
|
-
db.pragma("user_version = 2");
|
|
619
|
+
rebuildCardsFts(db);
|
|
620
|
+
db.pragma("user_version = 3");
|
|
624
621
|
});
|
|
625
622
|
migrate();
|
|
626
623
|
}
|
|
624
|
+
function migrateV2toV3(db) {
|
|
625
|
+
const migrate = db.transaction(() => {
|
|
626
|
+
db.exec(V2_FTS_TRIGGERS);
|
|
627
|
+
rebuildCardsFts(db);
|
|
628
|
+
db.pragma("user_version = 3");
|
|
629
|
+
});
|
|
630
|
+
migrate();
|
|
631
|
+
}
|
|
632
|
+
function rebuildCardsFts(db) {
|
|
633
|
+
db.exec(`INSERT INTO cards_fts(cards_fts) VALUES('delete-all')`);
|
|
634
|
+
const allRows = db.prepare("SELECT rowid, id, owner, data FROM capability_cards").all();
|
|
635
|
+
const ftsInsert = db.prepare(
|
|
636
|
+
"INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
|
|
637
|
+
);
|
|
638
|
+
for (const row of allRows) {
|
|
639
|
+
const data = JSON.parse(row.data);
|
|
640
|
+
const skills = data["skills"] ?? [];
|
|
641
|
+
let name;
|
|
642
|
+
let description;
|
|
643
|
+
let tags;
|
|
644
|
+
if (skills.length > 0) {
|
|
645
|
+
name = skills.map((s) => `${String(s["id"] ?? "")} ${String(s["name"] ?? "")}`.trim()).join(" ");
|
|
646
|
+
description = skills.map((s) => String(s["description"] ?? "")).join(" ");
|
|
647
|
+
tags = [
|
|
648
|
+
// tags from metadata.tags[]
|
|
649
|
+
...skills.flatMap((s) => {
|
|
650
|
+
const meta = s["metadata"];
|
|
651
|
+
return meta?.["tags"] ?? [];
|
|
652
|
+
}),
|
|
653
|
+
// capability_type (singular)
|
|
654
|
+
...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
|
|
655
|
+
// capability_types[] (plural)
|
|
656
|
+
...skills.flatMap((s) => s["capability_types"] ?? [])
|
|
657
|
+
].join(" ");
|
|
658
|
+
} else {
|
|
659
|
+
name = String(data["name"] ?? "");
|
|
660
|
+
description = String(data["description"] ?? "");
|
|
661
|
+
const meta = data["metadata"];
|
|
662
|
+
const rawTags = meta?.["tags"] ?? [];
|
|
663
|
+
tags = rawTags.join(" ");
|
|
664
|
+
}
|
|
665
|
+
ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
627
668
|
function insertCard(db, card) {
|
|
628
669
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
629
670
|
const withTimestamps = { ...card, created_at: card.created_at ?? now, updated_at: now };
|
|
@@ -753,9 +794,43 @@ function getReputationScore(db, agentId) {
|
|
|
753
794
|
}
|
|
754
795
|
|
|
755
796
|
// src/registry/matcher.ts
|
|
797
|
+
var CACHE_MAX_ENTRIES = 100;
|
|
798
|
+
var CACHE_TTL_MS = 3e4;
|
|
799
|
+
var dbCaches = /* @__PURE__ */ new WeakMap();
|
|
800
|
+
function getDbCache(db) {
|
|
801
|
+
let cache = dbCaches.get(db);
|
|
802
|
+
if (!cache) {
|
|
803
|
+
cache = /* @__PURE__ */ new Map();
|
|
804
|
+
dbCaches.set(db, cache);
|
|
805
|
+
}
|
|
806
|
+
return cache;
|
|
807
|
+
}
|
|
808
|
+
function cacheKey(query, filters) {
|
|
809
|
+
return `${query}|${filters.level ?? ""}|${filters.online ?? ""}|${(filters.apis_used ?? []).join(",")}|${filters.min_reputation ?? ""}`;
|
|
810
|
+
}
|
|
811
|
+
function evictCache(cache) {
|
|
812
|
+
const now = Date.now();
|
|
813
|
+
for (const [key, entry] of cache) {
|
|
814
|
+
if (entry.expiresAt <= now) cache.delete(key);
|
|
815
|
+
}
|
|
816
|
+
while (cache.size > CACHE_MAX_ENTRIES) {
|
|
817
|
+
const firstKey = cache.keys().next().value;
|
|
818
|
+
cache.delete(firstKey);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
756
821
|
function searchCards(db, query, filters = {}) {
|
|
822
|
+
const cache = getDbCache(db);
|
|
823
|
+
const key = cacheKey(query, filters);
|
|
824
|
+
const cached = cache.get(key);
|
|
825
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
826
|
+
return cached.results;
|
|
827
|
+
}
|
|
828
|
+
const trimmedQuery = query.trim();
|
|
829
|
+
const exactSkillMatches = findCardsByExactSkillId(db, trimmedQuery, filters);
|
|
757
830
|
const words = query.trim().split(/\s+/).map((w) => w.replace(/["*^{}():]/g, "")).filter((w) => w.length > 0);
|
|
758
|
-
if (words.length === 0)
|
|
831
|
+
if (words.length === 0) {
|
|
832
|
+
return exactSkillMatches;
|
|
833
|
+
}
|
|
759
834
|
const ftsQuery = words.map((w) => `"${w}"`).join(" OR ");
|
|
760
835
|
const conditions = [];
|
|
761
836
|
const params = [ftsQuery];
|
|
@@ -780,7 +855,8 @@ function searchCards(db, query, filters = {}) {
|
|
|
780
855
|
const stmt = db.prepare(sql);
|
|
781
856
|
const rows = stmt.all(...params);
|
|
782
857
|
const results = rows.map((row) => JSON.parse(row.data));
|
|
783
|
-
|
|
858
|
+
const mergedResults = mergeByCardId(exactSkillMatches, results);
|
|
859
|
+
let filtered = mergedResults;
|
|
784
860
|
if (filters.apis_used && filters.apis_used.length > 0) {
|
|
785
861
|
const requiredApis = filters.apis_used;
|
|
786
862
|
filtered = filtered.filter((card) => {
|
|
@@ -791,8 +867,38 @@ function searchCards(db, query, filters = {}) {
|
|
|
791
867
|
if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
|
|
792
868
|
filtered = applyReputationFilter(db, filtered, filters.min_reputation);
|
|
793
869
|
}
|
|
870
|
+
evictCache(cache);
|
|
871
|
+
cache.set(key, { results: filtered, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
794
872
|
return filtered;
|
|
795
873
|
}
|
|
874
|
+
function mergeByCardId(primary, secondary) {
|
|
875
|
+
const seen = /* @__PURE__ */ new Set();
|
|
876
|
+
const merged = [];
|
|
877
|
+
for (const card of primary) {
|
|
878
|
+
if (seen.has(card.id)) continue;
|
|
879
|
+
seen.add(card.id);
|
|
880
|
+
merged.push(card);
|
|
881
|
+
}
|
|
882
|
+
for (const card of secondary) {
|
|
883
|
+
if (seen.has(card.id)) continue;
|
|
884
|
+
seen.add(card.id);
|
|
885
|
+
merged.push(card);
|
|
886
|
+
}
|
|
887
|
+
return merged;
|
|
888
|
+
}
|
|
889
|
+
function findCardsByExactSkillId(db, query, filters) {
|
|
890
|
+
if (query.length === 0) return [];
|
|
891
|
+
const rows = db.prepare("SELECT data FROM capability_cards").all();
|
|
892
|
+
const cards = rows.map((row) => JSON.parse(row.data));
|
|
893
|
+
return cards.filter((card) => {
|
|
894
|
+
if (filters.level !== void 0 && card.level !== filters.level) return false;
|
|
895
|
+
if (filters.online !== void 0 && card.availability?.online !== filters.online) return false;
|
|
896
|
+
const asRecord = card;
|
|
897
|
+
const skills = asRecord["skills"];
|
|
898
|
+
if (!Array.isArray(skills)) return false;
|
|
899
|
+
return skills.some((skill) => String(skill["id"] ?? "") === query);
|
|
900
|
+
});
|
|
901
|
+
}
|
|
796
902
|
function applyReputationFilter(db, cards, minReputation) {
|
|
797
903
|
const owners = [...new Set(cards.map((c) => c.owner))];
|
|
798
904
|
const reputationMap = /* @__PURE__ */ new Map();
|
|
@@ -1178,7 +1284,25 @@ function loadKeyPair(configDir) {
|
|
|
1178
1284
|
};
|
|
1179
1285
|
}
|
|
1180
1286
|
function canonicalJson(data) {
|
|
1181
|
-
return JSON.stringify(
|
|
1287
|
+
return JSON.stringify(sortForCanonicalJson(data));
|
|
1288
|
+
}
|
|
1289
|
+
function sortForCanonicalJson(value) {
|
|
1290
|
+
if (Array.isArray(value)) {
|
|
1291
|
+
return value.map((item) => sortForCanonicalJson(item));
|
|
1292
|
+
}
|
|
1293
|
+
if (value !== null && typeof value === "object") {
|
|
1294
|
+
const proto = Object.getPrototypeOf(value);
|
|
1295
|
+
if (proto === Object.prototype || proto === null) {
|
|
1296
|
+
const input = value;
|
|
1297
|
+
const output = {};
|
|
1298
|
+
const sortedKeys = Object.keys(input).sort();
|
|
1299
|
+
for (const key of sortedKeys) {
|
|
1300
|
+
output[key] = sortForCanonicalJson(input[key]);
|
|
1301
|
+
}
|
|
1302
|
+
return output;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
return value;
|
|
1182
1306
|
}
|
|
1183
1307
|
function signEscrowReceipt(data, privateKey) {
|
|
1184
1308
|
const message = Buffer.from(canonicalJson(data), "utf-8");
|
|
@@ -1238,6 +1362,73 @@ function loadConfig() {
|
|
|
1238
1362
|
}
|
|
1239
1363
|
}
|
|
1240
1364
|
|
|
1365
|
+
// src/cli/remote-registry.ts
|
|
1366
|
+
var RegistryTimeoutError = class extends AgentBnBError {
|
|
1367
|
+
constructor(url) {
|
|
1368
|
+
super(
|
|
1369
|
+
`Registry at ${url} did not respond within 5s. Showing local results only.`,
|
|
1370
|
+
"REGISTRY_TIMEOUT"
|
|
1371
|
+
);
|
|
1372
|
+
this.name = "RegistryTimeoutError";
|
|
1373
|
+
}
|
|
1374
|
+
};
|
|
1375
|
+
var RegistryConnectionError = class extends AgentBnBError {
|
|
1376
|
+
constructor(url) {
|
|
1377
|
+
super(
|
|
1378
|
+
`Cannot reach ${url}. Is the registry running? Showing local results only.`,
|
|
1379
|
+
"REGISTRY_CONNECTION"
|
|
1380
|
+
);
|
|
1381
|
+
this.name = "RegistryConnectionError";
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
var RegistryAuthError = class extends AgentBnBError {
|
|
1385
|
+
constructor(url) {
|
|
1386
|
+
super(
|
|
1387
|
+
`Authentication failed for ${url}. Run \`agentbnb config set token <your-token>\`.`,
|
|
1388
|
+
"REGISTRY_AUTH"
|
|
1389
|
+
);
|
|
1390
|
+
this.name = "RegistryAuthError";
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
async function fetchRemoteCards(registryUrl, params, timeoutMs = 5e3) {
|
|
1394
|
+
let cardsUrl;
|
|
1395
|
+
try {
|
|
1396
|
+
cardsUrl = new URL("/cards", registryUrl);
|
|
1397
|
+
} catch {
|
|
1398
|
+
throw new AgentBnBError(`Invalid registry URL: ${registryUrl}`, "INVALID_REGISTRY_URL");
|
|
1399
|
+
}
|
|
1400
|
+
const searchParams = new URLSearchParams();
|
|
1401
|
+
if (params.q !== void 0) searchParams.set("q", params.q);
|
|
1402
|
+
if (params.level !== void 0) searchParams.set("level", String(params.level));
|
|
1403
|
+
if (params.online !== void 0) searchParams.set("online", String(params.online));
|
|
1404
|
+
if (params.tag !== void 0) searchParams.set("tag", params.tag);
|
|
1405
|
+
searchParams.set("limit", "100");
|
|
1406
|
+
cardsUrl.search = searchParams.toString();
|
|
1407
|
+
const controller = new AbortController();
|
|
1408
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1409
|
+
let response;
|
|
1410
|
+
try {
|
|
1411
|
+
response = await fetch(cardsUrl.toString(), { signal: controller.signal });
|
|
1412
|
+
} catch (err) {
|
|
1413
|
+
clearTimeout(timer);
|
|
1414
|
+
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
1415
|
+
if (isTimeout) {
|
|
1416
|
+
throw new RegistryTimeoutError(registryUrl);
|
|
1417
|
+
}
|
|
1418
|
+
throw new RegistryConnectionError(registryUrl);
|
|
1419
|
+
} finally {
|
|
1420
|
+
clearTimeout(timer);
|
|
1421
|
+
}
|
|
1422
|
+
if (response.status === 401 || response.status === 403) {
|
|
1423
|
+
throw new RegistryAuthError(registryUrl);
|
|
1424
|
+
}
|
|
1425
|
+
if (!response.ok) {
|
|
1426
|
+
throw new RegistryConnectionError(registryUrl);
|
|
1427
|
+
}
|
|
1428
|
+
const body = await response.json();
|
|
1429
|
+
return body.items;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1241
1432
|
// src/gateway/execute.ts
|
|
1242
1433
|
async function notifyTelegramSkillExecuted(opts) {
|
|
1243
1434
|
const cfg = loadConfig();
|
|
@@ -1520,7 +1711,54 @@ function createGatewayServer(opts) {
|
|
|
1520
1711
|
return { status: "ok", version: VERSION, uptime: process.uptime() };
|
|
1521
1712
|
});
|
|
1522
1713
|
fastify.post("/rpc", async (request, reply) => {
|
|
1523
|
-
const
|
|
1714
|
+
const rawBody = request.body;
|
|
1715
|
+
if (Array.isArray(rawBody)) {
|
|
1716
|
+
const responses = await Promise.all(
|
|
1717
|
+
rawBody.map(async (single) => {
|
|
1718
|
+
if (single.jsonrpc !== "2.0" || !single.method) {
|
|
1719
|
+
return { jsonrpc: "2.0", id: single.id ?? null, error: { code: -32600, message: "Invalid Request" } };
|
|
1720
|
+
}
|
|
1721
|
+
if (single.method !== "capability.execute") {
|
|
1722
|
+
return { jsonrpc: "2.0", id: single.id ?? null, error: { code: -32601, message: "Method not found" } };
|
|
1723
|
+
}
|
|
1724
|
+
const params2 = single.params ?? {};
|
|
1725
|
+
const cardId2 = params2.card_id;
|
|
1726
|
+
if (!cardId2) {
|
|
1727
|
+
return { jsonrpc: "2.0", id: single.id ?? null, error: { code: -32602, message: "Invalid params: card_id required" } };
|
|
1728
|
+
}
|
|
1729
|
+
const requester2 = params2.requester ?? "unknown";
|
|
1730
|
+
const receipt2 = params2.escrow_receipt;
|
|
1731
|
+
const batchSkillId = params2.skill_id;
|
|
1732
|
+
const trackKey2 = batchSkillId ?? cardId2;
|
|
1733
|
+
inFlight.set(trackKey2, (inFlight.get(trackKey2) ?? 0) + 1);
|
|
1734
|
+
try {
|
|
1735
|
+
const result2 = await executeCapabilityRequest({
|
|
1736
|
+
registryDb,
|
|
1737
|
+
creditDb,
|
|
1738
|
+
cardId: cardId2,
|
|
1739
|
+
skillId: batchSkillId,
|
|
1740
|
+
params: params2,
|
|
1741
|
+
requester: requester2,
|
|
1742
|
+
escrowReceipt: receipt2,
|
|
1743
|
+
skillExecutor,
|
|
1744
|
+
handlerUrl,
|
|
1745
|
+
timeoutMs
|
|
1746
|
+
});
|
|
1747
|
+
if (result2.success) {
|
|
1748
|
+
return { jsonrpc: "2.0", id: single.id ?? null, result: result2.result };
|
|
1749
|
+
} else {
|
|
1750
|
+
return { jsonrpc: "2.0", id: single.id ?? null, error: result2.error };
|
|
1751
|
+
}
|
|
1752
|
+
} finally {
|
|
1753
|
+
const next = (inFlight.get(trackKey2) ?? 1) - 1;
|
|
1754
|
+
if (next <= 0) inFlight.delete(trackKey2);
|
|
1755
|
+
else inFlight.set(trackKey2, next);
|
|
1756
|
+
}
|
|
1757
|
+
})
|
|
1758
|
+
);
|
|
1759
|
+
return reply.send(responses);
|
|
1760
|
+
}
|
|
1761
|
+
const body = rawBody;
|
|
1524
1762
|
if (body.jsonrpc !== "2.0" || !body.method) {
|
|
1525
1763
|
return reply.status(400).send({
|
|
1526
1764
|
jsonrpc: "2.0",
|
|
@@ -2839,8 +3077,31 @@ function decompose(task, _availableCapabilities) {
|
|
|
2839
3077
|
return [];
|
|
2840
3078
|
}
|
|
2841
3079
|
|
|
3080
|
+
// src/autonomy/auto-request.ts
|
|
3081
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
3082
|
+
|
|
2842
3083
|
// src/gateway/client.ts
|
|
2843
3084
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
3085
|
+
import { Agent } from "undici";
|
|
3086
|
+
var gatewayAgent = new Agent({
|
|
3087
|
+
keepAliveTimeout: 3e4,
|
|
3088
|
+
keepAliveMaxTimeout: 6e4,
|
|
3089
|
+
connections: 10,
|
|
3090
|
+
pipelining: 1
|
|
3091
|
+
});
|
|
3092
|
+
function buildGatewayAuthHeaders(payload, token, identity) {
|
|
3093
|
+
const headers = { "Content-Type": "application/json" };
|
|
3094
|
+
if (identity) {
|
|
3095
|
+
const signature = signEscrowReceipt(payload, identity.privateKey);
|
|
3096
|
+
headers["X-Agent-Id"] = identity.agentId;
|
|
3097
|
+
headers["X-Agent-Public-Key"] = identity.publicKey;
|
|
3098
|
+
headers["X-Agent-Signature"] = signature;
|
|
3099
|
+
}
|
|
3100
|
+
if (token) {
|
|
3101
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
3102
|
+
}
|
|
3103
|
+
return headers;
|
|
3104
|
+
}
|
|
2844
3105
|
async function requestCapability(opts) {
|
|
2845
3106
|
const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
|
|
2846
3107
|
const id = randomUUID8();
|
|
@@ -2854,15 +3115,7 @@ async function requestCapability(opts) {
|
|
|
2854
3115
|
...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
|
|
2855
3116
|
}
|
|
2856
3117
|
};
|
|
2857
|
-
const headers =
|
|
2858
|
-
if (identity) {
|
|
2859
|
-
const signature = signEscrowReceipt(payload, identity.privateKey);
|
|
2860
|
-
headers["X-Agent-Id"] = identity.agentId;
|
|
2861
|
-
headers["X-Agent-Public-Key"] = identity.publicKey;
|
|
2862
|
-
headers["X-Agent-Signature"] = signature;
|
|
2863
|
-
} else if (token) {
|
|
2864
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
2865
|
-
}
|
|
3118
|
+
const headers = buildGatewayAuthHeaders(payload, token, identity);
|
|
2866
3119
|
const controller = new AbortController();
|
|
2867
3120
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2868
3121
|
let response;
|
|
@@ -2871,7 +3124,9 @@ async function requestCapability(opts) {
|
|
|
2871
3124
|
method: "POST",
|
|
2872
3125
|
headers,
|
|
2873
3126
|
body: JSON.stringify(payload),
|
|
2874
|
-
signal: controller.signal
|
|
3127
|
+
signal: controller.signal,
|
|
3128
|
+
// undici dispatcher for connection pooling (Node.js 20+)
|
|
3129
|
+
dispatcher: gatewayAgent
|
|
2875
3130
|
});
|
|
2876
3131
|
} catch (err) {
|
|
2877
3132
|
clearTimeout(timer);
|
|
@@ -2889,6 +3144,65 @@ async function requestCapability(opts) {
|
|
|
2889
3144
|
}
|
|
2890
3145
|
return body.result;
|
|
2891
3146
|
}
|
|
3147
|
+
async function requestCapabilityBatch(gatewayUrl, token, items, opts = {}) {
|
|
3148
|
+
if (items.length === 0) return /* @__PURE__ */ new Map();
|
|
3149
|
+
if (items.length === 1) {
|
|
3150
|
+
const item = items[0];
|
|
3151
|
+
const result = await requestCapability({
|
|
3152
|
+
gatewayUrl,
|
|
3153
|
+
token,
|
|
3154
|
+
cardId: item.cardId,
|
|
3155
|
+
params: item.params,
|
|
3156
|
+
escrowReceipt: item.escrowReceipt,
|
|
3157
|
+
timeoutMs: opts.timeoutMs,
|
|
3158
|
+
identity: opts.identity
|
|
3159
|
+
});
|
|
3160
|
+
return /* @__PURE__ */ new Map([[item.id, result]]);
|
|
3161
|
+
}
|
|
3162
|
+
const { timeoutMs = 3e5, identity } = opts;
|
|
3163
|
+
const batchPayload = items.map((item) => ({
|
|
3164
|
+
jsonrpc: "2.0",
|
|
3165
|
+
id: item.id,
|
|
3166
|
+
method: "capability.execute",
|
|
3167
|
+
params: {
|
|
3168
|
+
card_id: item.cardId,
|
|
3169
|
+
...item.params,
|
|
3170
|
+
...item.escrowReceipt ? { escrow_receipt: item.escrowReceipt } : {}
|
|
3171
|
+
}
|
|
3172
|
+
}));
|
|
3173
|
+
const headers = buildGatewayAuthHeaders(batchPayload, token, identity);
|
|
3174
|
+
const controller = new AbortController();
|
|
3175
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3176
|
+
let response;
|
|
3177
|
+
try {
|
|
3178
|
+
response = await fetch(`${gatewayUrl}/rpc`, {
|
|
3179
|
+
method: "POST",
|
|
3180
|
+
headers,
|
|
3181
|
+
body: JSON.stringify(batchPayload),
|
|
3182
|
+
signal: controller.signal,
|
|
3183
|
+
dispatcher: gatewayAgent
|
|
3184
|
+
});
|
|
3185
|
+
} catch (err) {
|
|
3186
|
+
clearTimeout(timer);
|
|
3187
|
+
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
3188
|
+
throw new AgentBnBError(
|
|
3189
|
+
isTimeout ? "Batch request timed out" : `Network error: ${String(err)}`,
|
|
3190
|
+
isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
|
|
3191
|
+
);
|
|
3192
|
+
} finally {
|
|
3193
|
+
clearTimeout(timer);
|
|
3194
|
+
}
|
|
3195
|
+
const body = await response.json();
|
|
3196
|
+
const results = /* @__PURE__ */ new Map();
|
|
3197
|
+
for (const resp of body) {
|
|
3198
|
+
if (resp.error) {
|
|
3199
|
+
results.set(resp.id, new AgentBnBError(resp.error.message, `RPC_ERROR_${resp.error.code}`));
|
|
3200
|
+
} else {
|
|
3201
|
+
results.set(resp.id, resp.result);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
return results;
|
|
3205
|
+
}
|
|
2892
3206
|
async function requestViaRelay(relay, opts) {
|
|
2893
3207
|
try {
|
|
2894
3208
|
return await relay.request({
|
|
@@ -2922,73 +3236,6 @@ import { randomUUID as randomUUID10 } from "crypto";
|
|
|
2922
3236
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
2923
3237
|
import { join as join3 } from "path";
|
|
2924
3238
|
|
|
2925
|
-
// src/cli/remote-registry.ts
|
|
2926
|
-
var RegistryTimeoutError = class extends AgentBnBError {
|
|
2927
|
-
constructor(url) {
|
|
2928
|
-
super(
|
|
2929
|
-
`Registry at ${url} did not respond within 5s. Showing local results only.`,
|
|
2930
|
-
"REGISTRY_TIMEOUT"
|
|
2931
|
-
);
|
|
2932
|
-
this.name = "RegistryTimeoutError";
|
|
2933
|
-
}
|
|
2934
|
-
};
|
|
2935
|
-
var RegistryConnectionError = class extends AgentBnBError {
|
|
2936
|
-
constructor(url) {
|
|
2937
|
-
super(
|
|
2938
|
-
`Cannot reach ${url}. Is the registry running? Showing local results only.`,
|
|
2939
|
-
"REGISTRY_CONNECTION"
|
|
2940
|
-
);
|
|
2941
|
-
this.name = "RegistryConnectionError";
|
|
2942
|
-
}
|
|
2943
|
-
};
|
|
2944
|
-
var RegistryAuthError = class extends AgentBnBError {
|
|
2945
|
-
constructor(url) {
|
|
2946
|
-
super(
|
|
2947
|
-
`Authentication failed for ${url}. Run \`agentbnb config set token <your-token>\`.`,
|
|
2948
|
-
"REGISTRY_AUTH"
|
|
2949
|
-
);
|
|
2950
|
-
this.name = "RegistryAuthError";
|
|
2951
|
-
}
|
|
2952
|
-
};
|
|
2953
|
-
async function fetchRemoteCards(registryUrl, params, timeoutMs = 5e3) {
|
|
2954
|
-
let cardsUrl;
|
|
2955
|
-
try {
|
|
2956
|
-
cardsUrl = new URL("/cards", registryUrl);
|
|
2957
|
-
} catch {
|
|
2958
|
-
throw new AgentBnBError(`Invalid registry URL: ${registryUrl}`, "INVALID_REGISTRY_URL");
|
|
2959
|
-
}
|
|
2960
|
-
const searchParams = new URLSearchParams();
|
|
2961
|
-
if (params.q !== void 0) searchParams.set("q", params.q);
|
|
2962
|
-
if (params.level !== void 0) searchParams.set("level", String(params.level));
|
|
2963
|
-
if (params.online !== void 0) searchParams.set("online", String(params.online));
|
|
2964
|
-
if (params.tag !== void 0) searchParams.set("tag", params.tag);
|
|
2965
|
-
searchParams.set("limit", "100");
|
|
2966
|
-
cardsUrl.search = searchParams.toString();
|
|
2967
|
-
const controller = new AbortController();
|
|
2968
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2969
|
-
let response;
|
|
2970
|
-
try {
|
|
2971
|
-
response = await fetch(cardsUrl.toString(), { signal: controller.signal });
|
|
2972
|
-
} catch (err) {
|
|
2973
|
-
clearTimeout(timer);
|
|
2974
|
-
const isTimeout = err instanceof Error && err.name === "AbortError";
|
|
2975
|
-
if (isTimeout) {
|
|
2976
|
-
throw new RegistryTimeoutError(registryUrl);
|
|
2977
|
-
}
|
|
2978
|
-
throw new RegistryConnectionError(registryUrl);
|
|
2979
|
-
} finally {
|
|
2980
|
-
clearTimeout(timer);
|
|
2981
|
-
}
|
|
2982
|
-
if (response.status === 401 || response.status === 403) {
|
|
2983
|
-
throw new RegistryAuthError(registryUrl);
|
|
2984
|
-
}
|
|
2985
|
-
if (!response.ok) {
|
|
2986
|
-
throw new RegistryConnectionError(registryUrl);
|
|
2987
|
-
}
|
|
2988
|
-
const body = await response.json();
|
|
2989
|
-
return body.items;
|
|
2990
|
-
}
|
|
2991
|
-
|
|
2992
3239
|
// src/autonomy/auto-request.ts
|
|
2993
3240
|
function minMaxNormalize(values) {
|
|
2994
3241
|
if (values.length === 0) return [];
|
|
@@ -3265,6 +3512,65 @@ function computeWaves(subtasks) {
|
|
|
3265
3512
|
}
|
|
3266
3513
|
return waves;
|
|
3267
3514
|
}
|
|
3515
|
+
async function executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl) {
|
|
3516
|
+
const { taskId, match: m, interpolatedParams, primary, teamId, capabilityType } = pt;
|
|
3517
|
+
try {
|
|
3518
|
+
let res;
|
|
3519
|
+
if (primary.url.startsWith("relay://") && relayClient) {
|
|
3520
|
+
const targetOwner = primary.url.replace("relay://", "");
|
|
3521
|
+
res = await relayClient.request({
|
|
3522
|
+
targetOwner,
|
|
3523
|
+
cardId: primary.cardId,
|
|
3524
|
+
params: interpolatedParams,
|
|
3525
|
+
requester: requesterOwner,
|
|
3526
|
+
timeoutMs
|
|
3527
|
+
});
|
|
3528
|
+
} else {
|
|
3529
|
+
res = await requestCapability({
|
|
3530
|
+
gatewayUrl: primary.url,
|
|
3531
|
+
token: gatewayToken,
|
|
3532
|
+
cardId: primary.cardId,
|
|
3533
|
+
params: { ...interpolatedParams, requester: requesterOwner },
|
|
3534
|
+
timeoutMs
|
|
3535
|
+
});
|
|
3536
|
+
}
|
|
3537
|
+
return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: capabilityType };
|
|
3538
|
+
} catch (primaryErr) {
|
|
3539
|
+
if (m.alternatives.length > 0) {
|
|
3540
|
+
const alt = m.alternatives[0];
|
|
3541
|
+
const altResolved = resolveAgentUrl ? resolveAgentUrl(alt.agent) : { url: `http://${alt.agent}:7700`, cardId: `card-${alt.agent}` };
|
|
3542
|
+
try {
|
|
3543
|
+
let altRes;
|
|
3544
|
+
if (altResolved.url.startsWith("relay://") && relayClient) {
|
|
3545
|
+
const targetOwner = altResolved.url.replace("relay://", "");
|
|
3546
|
+
altRes = await relayClient.request({
|
|
3547
|
+
targetOwner,
|
|
3548
|
+
cardId: altResolved.cardId,
|
|
3549
|
+
params: interpolatedParams,
|
|
3550
|
+
requester: requesterOwner,
|
|
3551
|
+
timeoutMs
|
|
3552
|
+
});
|
|
3553
|
+
} else {
|
|
3554
|
+
altRes = await requestCapability({
|
|
3555
|
+
gatewayUrl: altResolved.url,
|
|
3556
|
+
token: gatewayToken,
|
|
3557
|
+
cardId: altResolved.cardId,
|
|
3558
|
+
params: { ...interpolatedParams, requester: requesterOwner },
|
|
3559
|
+
timeoutMs
|
|
3560
|
+
});
|
|
3561
|
+
}
|
|
3562
|
+
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: capabilityType };
|
|
3563
|
+
} catch (altErr) {
|
|
3564
|
+
throw new Error(
|
|
3565
|
+
`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)}`
|
|
3566
|
+
);
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
throw new Error(
|
|
3570
|
+
`Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
|
|
3571
|
+
);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3268
3574
|
async function orchestrate(opts) {
|
|
3269
3575
|
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
|
|
3270
3576
|
const startTime = Date.now();
|
|
@@ -3302,89 +3608,127 @@ async function orchestrate(opts) {
|
|
|
3302
3608
|
}
|
|
3303
3609
|
executableIds.push(taskId);
|
|
3304
3610
|
}
|
|
3305
|
-
const
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
const
|
|
3611
|
+
const preparedTasks = [];
|
|
3612
|
+
for (const taskId of executableIds) {
|
|
3613
|
+
const subtask = subtaskMap.get(taskId);
|
|
3614
|
+
const m = matches.get(taskId);
|
|
3615
|
+
if (!m) {
|
|
3616
|
+
errors.push(`No match found for subtask ${taskId}`);
|
|
3617
|
+
continue;
|
|
3618
|
+
}
|
|
3619
|
+
const stepsContext = {};
|
|
3620
|
+
for (const [id, val] of results) stepsContext[id] = val;
|
|
3621
|
+
const interpContext = { steps: stepsContext, prev: void 0 };
|
|
3622
|
+
if (subtask.depends_on.length > 0) {
|
|
3623
|
+
const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
|
|
3624
|
+
interpContext.prev = results.get(lastDep);
|
|
3625
|
+
}
|
|
3626
|
+
const interpolatedParams = interpolateObject(
|
|
3627
|
+
subtask.params,
|
|
3628
|
+
interpContext
|
|
3629
|
+
);
|
|
3630
|
+
const teamMember = teamMemberMap.get(taskId);
|
|
3631
|
+
const agentOwner = teamMember?.agent ?? m.selected_agent;
|
|
3632
|
+
const primary = resolveAgentUrl(agentOwner);
|
|
3633
|
+
preparedTasks.push({
|
|
3634
|
+
taskId,
|
|
3635
|
+
subtask,
|
|
3636
|
+
match: m,
|
|
3637
|
+
interpolatedParams,
|
|
3638
|
+
agentOwner,
|
|
3639
|
+
primary,
|
|
3640
|
+
teamId: opts.team?.team_id ?? null,
|
|
3641
|
+
capabilityType: teamMember?.capability_type ?? null
|
|
3642
|
+
});
|
|
3643
|
+
}
|
|
3644
|
+
const httpGroups = /* @__PURE__ */ new Map();
|
|
3645
|
+
const relayTasks = [];
|
|
3646
|
+
for (const pt of preparedTasks) {
|
|
3647
|
+
if (pt.primary.url.startsWith("relay://") && relayClient) {
|
|
3648
|
+
relayTasks.push(pt);
|
|
3649
|
+
} else {
|
|
3650
|
+
const group = httpGroups.get(pt.primary.url) ?? [];
|
|
3651
|
+
group.push(pt);
|
|
3652
|
+
httpGroups.set(pt.primary.url, group);
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
const batchPromises = [];
|
|
3656
|
+
for (const [gatewayUrl, group] of httpGroups) {
|
|
3657
|
+
if (group.length >= 2) {
|
|
3658
|
+
batchPromises.push(
|
|
3659
|
+
(async () => {
|
|
3660
|
+
const items = group.map((pt) => ({
|
|
3661
|
+
id: pt.taskId,
|
|
3662
|
+
cardId: pt.primary.cardId,
|
|
3663
|
+
params: { ...pt.interpolatedParams, requester: requesterOwner },
|
|
3664
|
+
_pt: pt
|
|
3665
|
+
}));
|
|
3355
3666
|
try {
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
cardId: altAgent.cardId,
|
|
3362
|
-
params: interpolatedParams,
|
|
3363
|
-
requester: requesterOwner,
|
|
3364
|
-
timeoutMs
|
|
3365
|
-
});
|
|
3366
|
-
} else {
|
|
3367
|
-
altRes = await requestCapability({
|
|
3368
|
-
gatewayUrl: altAgent.url,
|
|
3369
|
-
token: gatewayToken,
|
|
3370
|
-
cardId: altAgent.cardId,
|
|
3371
|
-
params: { ...interpolatedParams, requester: requesterOwner },
|
|
3372
|
-
timeoutMs
|
|
3373
|
-
});
|
|
3374
|
-
}
|
|
3375
|
-
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
3376
|
-
} catch (altErr) {
|
|
3377
|
-
throw new Error(
|
|
3378
|
-
`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)}`
|
|
3667
|
+
const batchResults = await requestCapabilityBatch(
|
|
3668
|
+
gatewayUrl,
|
|
3669
|
+
gatewayToken,
|
|
3670
|
+
items.map(({ _pt, ...item }) => item),
|
|
3671
|
+
{ timeoutMs }
|
|
3379
3672
|
);
|
|
3673
|
+
return items.map((item) => {
|
|
3674
|
+
const res = batchResults.get(item.id);
|
|
3675
|
+
if (res instanceof Error) {
|
|
3676
|
+
return {
|
|
3677
|
+
status: "rejected",
|
|
3678
|
+
reason: new Error(`Task ${item.id}: ${res.message}`)
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
return {
|
|
3682
|
+
status: "fulfilled",
|
|
3683
|
+
value: {
|
|
3684
|
+
taskId: item.id,
|
|
3685
|
+
result: res,
|
|
3686
|
+
credits: item._pt.match.credits,
|
|
3687
|
+
team_id: item._pt.teamId,
|
|
3688
|
+
capability_type: item._pt.capabilityType
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3691
|
+
});
|
|
3692
|
+
} catch (batchErr) {
|
|
3693
|
+
return Promise.all(group.map(async (pt) => {
|
|
3694
|
+
try {
|
|
3695
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
3696
|
+
return { status: "fulfilled", value: res };
|
|
3697
|
+
} catch (err) {
|
|
3698
|
+
return { status: "rejected", reason: err };
|
|
3699
|
+
}
|
|
3700
|
+
}));
|
|
3380
3701
|
}
|
|
3702
|
+
})()
|
|
3703
|
+
);
|
|
3704
|
+
} else {
|
|
3705
|
+
const pt = group[0];
|
|
3706
|
+
batchPromises.push(
|
|
3707
|
+
(async () => {
|
|
3708
|
+
try {
|
|
3709
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
3710
|
+
return [{ status: "fulfilled", value: res }];
|
|
3711
|
+
} catch (err) {
|
|
3712
|
+
return [{ status: "rejected", reason: err }];
|
|
3713
|
+
}
|
|
3714
|
+
})()
|
|
3715
|
+
);
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
for (const pt of relayTasks) {
|
|
3719
|
+
batchPromises.push(
|
|
3720
|
+
(async () => {
|
|
3721
|
+
try {
|
|
3722
|
+
const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
|
|
3723
|
+
return [{ status: "fulfilled", value: res }];
|
|
3724
|
+
} catch (err) {
|
|
3725
|
+
return [{ status: "rejected", reason: err }];
|
|
3381
3726
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
);
|
|
3727
|
+
})()
|
|
3728
|
+
);
|
|
3729
|
+
}
|
|
3730
|
+
const allBatchResults = await Promise.all(batchPromises);
|
|
3731
|
+
const waveResults = allBatchResults.flat();
|
|
3388
3732
|
for (const settlement of waveResults) {
|
|
3389
3733
|
if (settlement.status === "fulfilled") {
|
|
3390
3734
|
const { taskId, result, credits, team_id, capability_type } = settlement.value;
|
|
@@ -3452,7 +3796,7 @@ var BudgetManager = class {
|
|
|
3452
3796
|
};
|
|
3453
3797
|
|
|
3454
3798
|
// src/conductor/team-formation.ts
|
|
3455
|
-
import { randomUUID as
|
|
3799
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
3456
3800
|
function selectByStrategy(matches, strategy) {
|
|
3457
3801
|
if (matches.length === 0) return void 0;
|
|
3458
3802
|
if (strategy === "balanced") {
|
|
@@ -3469,7 +3813,7 @@ function selectByStrategy(matches, strategy) {
|
|
|
3469
3813
|
}
|
|
3470
3814
|
async function formTeam(opts) {
|
|
3471
3815
|
const { subtasks, strategy, db, conductorOwner, registryUrl } = opts;
|
|
3472
|
-
const team_id =
|
|
3816
|
+
const team_id = randomUUID12();
|
|
3473
3817
|
if (subtasks.length === 0) {
|
|
3474
3818
|
return { team_id, strategy, matched: [], unrouted: [] };
|
|
3475
3819
|
}
|
|
@@ -3699,7 +4043,7 @@ var ConductorMode = class {
|
|
|
3699
4043
|
|
|
3700
4044
|
// src/credit/escrow-receipt.ts
|
|
3701
4045
|
import { z as z3 } from "zod";
|
|
3702
|
-
import { randomUUID as
|
|
4046
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
3703
4047
|
var EscrowReceiptSchema = z3.object({
|
|
3704
4048
|
requester_owner: z3.string().min(1),
|
|
3705
4049
|
requester_agent_id: z3.string().optional(),
|
|
@@ -3721,7 +4065,7 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
3721
4065
|
card_id: opts.cardId,
|
|
3722
4066
|
...opts.skillId ? { skill_id: opts.skillId } : {},
|
|
3723
4067
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3724
|
-
nonce:
|
|
4068
|
+
nonce: randomUUID13()
|
|
3725
4069
|
};
|
|
3726
4070
|
const signature = signEscrowReceipt(receiptData, privateKey);
|
|
3727
4071
|
const receipt = {
|
|
@@ -3733,7 +4077,7 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
3733
4077
|
|
|
3734
4078
|
// src/identity/identity.ts
|
|
3735
4079
|
import { z as z4 } from "zod";
|
|
3736
|
-
import { createHash as createHash2 } from "crypto";
|
|
4080
|
+
import { createHash as createHash2, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
|
|
3737
4081
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
3738
4082
|
import { join as join4 } from "path";
|
|
3739
4083
|
var AgentIdentitySchema = z4.object({
|
|
@@ -3763,6 +4107,30 @@ var AgentCertificateSchema = z4.object({
|
|
|
3763
4107
|
signature: z4.string().min(1)
|
|
3764
4108
|
});
|
|
3765
4109
|
var IDENTITY_FILENAME = "identity.json";
|
|
4110
|
+
var PRIVATE_KEY_FILENAME = "private.key";
|
|
4111
|
+
var PUBLIC_KEY_FILENAME = "public.key";
|
|
4112
|
+
function derivePublicKeyFromPrivate(privateKey) {
|
|
4113
|
+
const privateKeyObject = createPrivateKey2({ key: privateKey, format: "der", type: "pkcs8" });
|
|
4114
|
+
const publicKeyObject = createPublicKey2(privateKeyObject);
|
|
4115
|
+
const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
|
|
4116
|
+
return Buffer.from(publicKey);
|
|
4117
|
+
}
|
|
4118
|
+
function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
|
|
4119
|
+
const publicKeyHex = publicKey.toString("hex");
|
|
4120
|
+
return {
|
|
4121
|
+
agent_id: deriveAgentId(publicKeyHex),
|
|
4122
|
+
owner,
|
|
4123
|
+
public_key: publicKeyHex,
|
|
4124
|
+
created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
4125
|
+
};
|
|
4126
|
+
}
|
|
4127
|
+
function generateFreshIdentity(configDir, owner) {
|
|
4128
|
+
const keys = generateKeyPair();
|
|
4129
|
+
saveKeyPair(configDir, keys);
|
|
4130
|
+
const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
|
|
4131
|
+
saveIdentity(configDir, identity);
|
|
4132
|
+
return { identity, keys, status: "generated" };
|
|
4133
|
+
}
|
|
3766
4134
|
function deriveAgentId(publicKeyHex) {
|
|
3767
4135
|
return createHash2("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
|
|
3768
4136
|
}
|
|
@@ -3805,6 +4173,57 @@ function saveIdentity(configDir, identity) {
|
|
|
3805
4173
|
const filePath = join4(configDir, IDENTITY_FILENAME);
|
|
3806
4174
|
writeFileSync4(filePath, JSON.stringify(identity, null, 2), "utf-8");
|
|
3807
4175
|
}
|
|
4176
|
+
function loadOrRepairIdentity(configDir, ownerHint) {
|
|
4177
|
+
if (!existsSync4(configDir)) {
|
|
4178
|
+
mkdirSync3(configDir, { recursive: true });
|
|
4179
|
+
}
|
|
4180
|
+
const identityPath = join4(configDir, IDENTITY_FILENAME);
|
|
4181
|
+
const privateKeyPath = join4(configDir, PRIVATE_KEY_FILENAME);
|
|
4182
|
+
const publicKeyPath = join4(configDir, PUBLIC_KEY_FILENAME);
|
|
4183
|
+
const hasIdentity = existsSync4(identityPath);
|
|
4184
|
+
const hasPrivateKey = existsSync4(privateKeyPath);
|
|
4185
|
+
const hasPublicKey = existsSync4(publicKeyPath);
|
|
4186
|
+
if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
|
|
4187
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
4188
|
+
}
|
|
4189
|
+
let keys;
|
|
4190
|
+
try {
|
|
4191
|
+
keys = loadKeyPair(configDir);
|
|
4192
|
+
} catch {
|
|
4193
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
4194
|
+
}
|
|
4195
|
+
let derivedPublicKey;
|
|
4196
|
+
try {
|
|
4197
|
+
derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
|
|
4198
|
+
} catch {
|
|
4199
|
+
return generateFreshIdentity(configDir, ownerHint ?? "agent");
|
|
4200
|
+
}
|
|
4201
|
+
let keypairRepaired = false;
|
|
4202
|
+
if (!keys.publicKey.equals(derivedPublicKey)) {
|
|
4203
|
+
keypairRepaired = true;
|
|
4204
|
+
keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
|
|
4205
|
+
saveKeyPair(configDir, keys);
|
|
4206
|
+
}
|
|
4207
|
+
const loadedIdentity = loadIdentity(configDir);
|
|
4208
|
+
const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
|
|
4209
|
+
const expectedPublicKeyHex = derivedPublicKey.toString("hex");
|
|
4210
|
+
const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
|
|
4211
|
+
if (identityMismatch) {
|
|
4212
|
+
const repairedIdentity = buildIdentityFromPublicKey(
|
|
4213
|
+
derivedPublicKey,
|
|
4214
|
+
loadedIdentity?.owner ?? ownerHint ?? "agent",
|
|
4215
|
+
loadedIdentity?.created_at
|
|
4216
|
+
);
|
|
4217
|
+
saveIdentity(configDir, repairedIdentity);
|
|
4218
|
+
return { identity: repairedIdentity, keys, status: "repaired" };
|
|
4219
|
+
}
|
|
4220
|
+
if (ownerHint && loadedIdentity.owner !== ownerHint) {
|
|
4221
|
+
const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
|
|
4222
|
+
saveIdentity(configDir, updatedIdentity);
|
|
4223
|
+
return { identity: updatedIdentity, keys, status: "repaired" };
|
|
4224
|
+
}
|
|
4225
|
+
return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
|
|
4226
|
+
}
|
|
3808
4227
|
function issueAgentCertificate(identity, privateKey) {
|
|
3809
4228
|
const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3810
4229
|
const expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toISOString();
|
|
@@ -3838,15 +4257,7 @@ function verifyAgentCertificate(cert) {
|
|
|
3838
4257
|
return verifyEscrowReceipt(payload, cert.signature, publicKeyBuf);
|
|
3839
4258
|
}
|
|
3840
4259
|
function ensureIdentity(configDir, owner) {
|
|
3841
|
-
|
|
3842
|
-
if (existing) {
|
|
3843
|
-
if (existing.owner !== owner) {
|
|
3844
|
-
existing.owner = owner;
|
|
3845
|
-
saveIdentity(configDir, existing);
|
|
3846
|
-
}
|
|
3847
|
-
return existing;
|
|
3848
|
-
}
|
|
3849
|
-
return createIdentity(configDir, owner);
|
|
4260
|
+
return loadOrRepairIdentity(configDir, owner).identity;
|
|
3850
4261
|
}
|
|
3851
4262
|
|
|
3852
4263
|
// src/sdk/consumer.ts
|
|
@@ -3916,7 +4327,12 @@ var AgentBnBConsumer = class {
|
|
|
3916
4327
|
cardId: opts.cardId,
|
|
3917
4328
|
params: opts.params,
|
|
3918
4329
|
timeoutMs: opts.timeoutMs,
|
|
3919
|
-
escrowReceipt: receipt
|
|
4330
|
+
escrowReceipt: receipt,
|
|
4331
|
+
identity: {
|
|
4332
|
+
agentId: identity.agent_id,
|
|
4333
|
+
publicKey: identity.public_key,
|
|
4334
|
+
privateKey: this.keys.privateKey
|
|
4335
|
+
}
|
|
3920
4336
|
});
|
|
3921
4337
|
settleRequesterEscrow(db, escrowId);
|
|
3922
4338
|
return result;
|
|
@@ -4092,7 +4508,7 @@ var AgentBnBProvider = class {
|
|
|
4092
4508
|
|
|
4093
4509
|
// src/identity/guarantor.ts
|
|
4094
4510
|
import { z as z5 } from "zod";
|
|
4095
|
-
import { randomUUID as
|
|
4511
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
4096
4512
|
var MAX_AGENTS_PER_GUARANTOR = 10;
|
|
4097
4513
|
var GUARANTOR_CREDIT_POOL = 50;
|
|
4098
4514
|
var GuarantorRecordSchema = z5.object({
|
|
@@ -4131,7 +4547,7 @@ function registerGuarantor(db, githubLogin) {
|
|
|
4131
4547
|
);
|
|
4132
4548
|
}
|
|
4133
4549
|
const record = {
|
|
4134
|
-
id:
|
|
4550
|
+
id: randomUUID14(),
|
|
4135
4551
|
github_login: githubLogin,
|
|
4136
4552
|
agent_count: 0,
|
|
4137
4553
|
credit_pool: GUARANTOR_CREDIT_POOL,
|
|
@@ -4205,178 +4621,12 @@ function getAgentGuarantor(db, agentId) {
|
|
|
4205
4621
|
function initiateGithubAuth() {
|
|
4206
4622
|
return {
|
|
4207
4623
|
auth_url: "https://github.com/login/oauth/authorize?client_id=PLACEHOLDER&scope=read:user",
|
|
4208
|
-
state:
|
|
4624
|
+
state: randomUUID14()
|
|
4209
4625
|
};
|
|
4210
4626
|
}
|
|
4211
4627
|
|
|
4212
|
-
// src/relay/types.ts
|
|
4213
|
-
import { z as z6 } from "zod";
|
|
4214
|
-
var RegisterMessageSchema = z6.object({
|
|
4215
|
-
type: z6.literal("register"),
|
|
4216
|
-
owner: z6.string().min(1),
|
|
4217
|
-
/** V8: Cryptographic agent identity. When present, used as the canonical key. */
|
|
4218
|
-
agent_id: z6.string().optional(),
|
|
4219
|
-
/** V8 Phase 3: Server identifier for multi-agent delegation. */
|
|
4220
|
-
server_id: z6.string().optional(),
|
|
4221
|
-
token: z6.string().min(1),
|
|
4222
|
-
card: z6.record(z6.unknown()),
|
|
4223
|
-
// CapabilityCard (validated separately)
|
|
4224
|
-
cards: z6.array(z6.record(z6.unknown())).optional(),
|
|
4225
|
-
// Additional cards (e.g., conductor card)
|
|
4226
|
-
/** V8 Phase 3: Additional agents served by this server (multi-agent registration). */
|
|
4227
|
-
agents: z6.array(z6.object({
|
|
4228
|
-
agent_id: z6.string().min(1),
|
|
4229
|
-
display_name: z6.string().min(1),
|
|
4230
|
-
cards: z6.array(z6.record(z6.unknown())),
|
|
4231
|
-
delegation_token: z6.record(z6.unknown()).optional()
|
|
4232
|
-
})).optional()
|
|
4233
|
-
});
|
|
4234
|
-
var RegisteredMessageSchema = z6.object({
|
|
4235
|
-
type: z6.literal("registered"),
|
|
4236
|
-
agent_id: z6.string()
|
|
4237
|
-
});
|
|
4238
|
-
var RelayRequestMessageSchema = z6.object({
|
|
4239
|
-
type: z6.literal("relay_request"),
|
|
4240
|
-
id: z6.string().uuid(),
|
|
4241
|
-
target_owner: z6.string().min(1),
|
|
4242
|
-
/** V8: Target agent's cryptographic identity. Preferred over target_owner. */
|
|
4243
|
-
target_agent_id: z6.string().optional(),
|
|
4244
|
-
card_id: z6.string(),
|
|
4245
|
-
skill_id: z6.string().optional(),
|
|
4246
|
-
params: z6.record(z6.unknown()).default({}),
|
|
4247
|
-
requester: z6.string().optional(),
|
|
4248
|
-
escrow_receipt: z6.record(z6.unknown()).optional()
|
|
4249
|
-
});
|
|
4250
|
-
var IncomingRequestMessageSchema = z6.object({
|
|
4251
|
-
type: z6.literal("incoming_request"),
|
|
4252
|
-
id: z6.string().uuid(),
|
|
4253
|
-
from_owner: z6.string().min(1),
|
|
4254
|
-
card_id: z6.string(),
|
|
4255
|
-
skill_id: z6.string().optional(),
|
|
4256
|
-
params: z6.record(z6.unknown()).default({}),
|
|
4257
|
-
requester: z6.string().optional(),
|
|
4258
|
-
escrow_receipt: z6.record(z6.unknown()).optional()
|
|
4259
|
-
});
|
|
4260
|
-
var RelayResponseMessageSchema = z6.object({
|
|
4261
|
-
type: z6.literal("relay_response"),
|
|
4262
|
-
id: z6.string().uuid(),
|
|
4263
|
-
result: z6.unknown().optional(),
|
|
4264
|
-
error: z6.object({
|
|
4265
|
-
code: z6.number(),
|
|
4266
|
-
message: z6.string()
|
|
4267
|
-
}).optional()
|
|
4268
|
-
});
|
|
4269
|
-
var ResponseMessageSchema = z6.object({
|
|
4270
|
-
type: z6.literal("response"),
|
|
4271
|
-
id: z6.string().uuid(),
|
|
4272
|
-
result: z6.unknown().optional(),
|
|
4273
|
-
error: z6.object({
|
|
4274
|
-
code: z6.number(),
|
|
4275
|
-
message: z6.string()
|
|
4276
|
-
}).optional()
|
|
4277
|
-
});
|
|
4278
|
-
var ErrorMessageSchema = z6.object({
|
|
4279
|
-
type: z6.literal("error"),
|
|
4280
|
-
code: z6.string(),
|
|
4281
|
-
message: z6.string(),
|
|
4282
|
-
request_id: z6.string().optional()
|
|
4283
|
-
});
|
|
4284
|
-
var RelayProgressMessageSchema = z6.object({
|
|
4285
|
-
type: z6.literal("relay_progress"),
|
|
4286
|
-
id: z6.string().uuid(),
|
|
4287
|
-
// request ID this progress relates to
|
|
4288
|
-
progress: z6.number().min(0).max(100).optional(),
|
|
4289
|
-
// optional percentage
|
|
4290
|
-
message: z6.string().optional()
|
|
4291
|
-
// optional status message
|
|
4292
|
-
});
|
|
4293
|
-
var HeartbeatMessageSchema = z6.object({
|
|
4294
|
-
type: z6.literal("heartbeat"),
|
|
4295
|
-
owner: z6.string().min(1),
|
|
4296
|
-
capacity: z6.object({
|
|
4297
|
-
current_load: z6.number(),
|
|
4298
|
-
max_concurrent: z6.number(),
|
|
4299
|
-
queue_depth: z6.number()
|
|
4300
|
-
}),
|
|
4301
|
-
self_summary: z6.object({
|
|
4302
|
-
capabilities: z6.array(z6.string()),
|
|
4303
|
-
success_rate: z6.number(),
|
|
4304
|
-
credit_balance: z6.number(),
|
|
4305
|
-
total_completed: z6.number(),
|
|
4306
|
-
provider_number: z6.number(),
|
|
4307
|
-
reliability: z6.object({
|
|
4308
|
-
current_streak: z6.number(),
|
|
4309
|
-
repeat_hire_rate: z6.number(),
|
|
4310
|
-
avg_feedback: z6.number()
|
|
4311
|
-
})
|
|
4312
|
-
})
|
|
4313
|
-
});
|
|
4314
|
-
var EscrowHoldMessageSchema = z6.object({
|
|
4315
|
-
type: z6.literal("escrow_hold"),
|
|
4316
|
-
consumer_agent_id: z6.string().min(1),
|
|
4317
|
-
provider_agent_id: z6.string().min(1),
|
|
4318
|
-
skill_id: z6.string().min(1),
|
|
4319
|
-
amount: z6.number().positive(),
|
|
4320
|
-
request_id: z6.string().uuid(),
|
|
4321
|
-
signature: z6.string().optional(),
|
|
4322
|
-
public_key: z6.string().optional()
|
|
4323
|
-
});
|
|
4324
|
-
var EscrowHoldConfirmedMessageSchema = z6.object({
|
|
4325
|
-
type: z6.literal("escrow_hold_confirmed"),
|
|
4326
|
-
request_id: z6.string(),
|
|
4327
|
-
escrow_id: z6.string(),
|
|
4328
|
-
hold_amount: z6.number(),
|
|
4329
|
-
consumer_remaining: z6.number()
|
|
4330
|
-
});
|
|
4331
|
-
var EscrowSettleMessageSchema = z6.object({
|
|
4332
|
-
type: z6.literal("escrow_settle"),
|
|
4333
|
-
escrow_id: z6.string().min(1),
|
|
4334
|
-
request_id: z6.string().uuid(),
|
|
4335
|
-
success: z6.boolean(),
|
|
4336
|
-
failure_reason: z6.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
|
|
4337
|
-
result_hash: z6.string().optional(),
|
|
4338
|
-
signature: z6.string().optional(),
|
|
4339
|
-
public_key: z6.string().optional(),
|
|
4340
|
-
consumer_agent_id: z6.string().optional()
|
|
4341
|
-
});
|
|
4342
|
-
var EscrowSettledMessageSchema = z6.object({
|
|
4343
|
-
type: z6.literal("escrow_settled"),
|
|
4344
|
-
escrow_id: z6.string(),
|
|
4345
|
-
request_id: z6.string(),
|
|
4346
|
-
provider_earned: z6.number(),
|
|
4347
|
-
network_fee: z6.number(),
|
|
4348
|
-
consumer_remaining: z6.number(),
|
|
4349
|
-
provider_balance: z6.number()
|
|
4350
|
-
});
|
|
4351
|
-
var BalanceSyncMessageSchema = z6.object({
|
|
4352
|
-
type: z6.literal("balance_sync"),
|
|
4353
|
-
agent_id: z6.string().min(1)
|
|
4354
|
-
});
|
|
4355
|
-
var BalanceSyncResponseMessageSchema = z6.object({
|
|
4356
|
-
type: z6.literal("balance_sync_response"),
|
|
4357
|
-
agent_id: z6.string(),
|
|
4358
|
-
balance: z6.number()
|
|
4359
|
-
});
|
|
4360
|
-
var RelayMessageSchema = z6.discriminatedUnion("type", [
|
|
4361
|
-
RegisterMessageSchema,
|
|
4362
|
-
RegisteredMessageSchema,
|
|
4363
|
-
RelayRequestMessageSchema,
|
|
4364
|
-
IncomingRequestMessageSchema,
|
|
4365
|
-
RelayResponseMessageSchema,
|
|
4366
|
-
ResponseMessageSchema,
|
|
4367
|
-
ErrorMessageSchema,
|
|
4368
|
-
RelayProgressMessageSchema,
|
|
4369
|
-
HeartbeatMessageSchema,
|
|
4370
|
-
EscrowHoldMessageSchema,
|
|
4371
|
-
EscrowHoldConfirmedMessageSchema,
|
|
4372
|
-
EscrowSettleMessageSchema,
|
|
4373
|
-
EscrowSettledMessageSchema,
|
|
4374
|
-
BalanceSyncMessageSchema,
|
|
4375
|
-
BalanceSyncResponseMessageSchema
|
|
4376
|
-
]);
|
|
4377
|
-
|
|
4378
4628
|
// src/relay/websocket-relay.ts
|
|
4379
|
-
import { randomUUID as
|
|
4629
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
4380
4630
|
|
|
4381
4631
|
// src/relay/relay-credit.ts
|
|
4382
4632
|
function lookupCardPrice(registryDb, cardId, skillId) {
|
|
@@ -4506,10 +4756,10 @@ function settleWithNetworkFee(creditDb, escrowId, providerOwner) {
|
|
|
4506
4756
|
}
|
|
4507
4757
|
|
|
4508
4758
|
// src/hub-agent/relay-bridge.ts
|
|
4509
|
-
import { randomUUID as
|
|
4759
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
4510
4760
|
|
|
4511
4761
|
// src/hub-agent/job-queue.ts
|
|
4512
|
-
import { randomUUID as
|
|
4762
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
4513
4763
|
function updateJobStatus(db, jobId, status, result) {
|
|
4514
4764
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4515
4765
|
if (result !== void 0) {
|
|
@@ -4638,7 +4888,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
4638
4888
|
function logAgentJoined(owner, cardName, cardId) {
|
|
4639
4889
|
try {
|
|
4640
4890
|
insertRequestLog(db, {
|
|
4641
|
-
id:
|
|
4891
|
+
id: randomUUID17(),
|
|
4642
4892
|
card_id: cardId,
|
|
4643
4893
|
card_name: cardName,
|
|
4644
4894
|
requester: owner,
|
|
@@ -5120,312 +5370,6 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
5120
5370
|
};
|
|
5121
5371
|
}
|
|
5122
5372
|
|
|
5123
|
-
// src/relay/websocket-client.ts
|
|
5124
|
-
import WebSocket from "ws";
|
|
5125
|
-
import { randomUUID as randomUUID17 } from "crypto";
|
|
5126
|
-
var RelayClient = class {
|
|
5127
|
-
ws = null;
|
|
5128
|
-
opts;
|
|
5129
|
-
pendingRequests = /* @__PURE__ */ new Map();
|
|
5130
|
-
reconnectAttempts = 0;
|
|
5131
|
-
reconnectTimer = null;
|
|
5132
|
-
intentionalClose = false;
|
|
5133
|
-
registered = false;
|
|
5134
|
-
pongTimeout = null;
|
|
5135
|
-
pingInterval = null;
|
|
5136
|
-
constructor(opts) {
|
|
5137
|
-
this.opts = opts;
|
|
5138
|
-
}
|
|
5139
|
-
/**
|
|
5140
|
-
* Connect to the registry relay and register.
|
|
5141
|
-
* Resolves when registration is acknowledged.
|
|
5142
|
-
*/
|
|
5143
|
-
async connect() {
|
|
5144
|
-
return new Promise((resolve, reject) => {
|
|
5145
|
-
this.intentionalClose = false;
|
|
5146
|
-
this.registered = false;
|
|
5147
|
-
const wsUrl = this.buildWsUrl();
|
|
5148
|
-
this.ws = new WebSocket(wsUrl);
|
|
5149
|
-
let resolved = false;
|
|
5150
|
-
this.ws.on("open", () => {
|
|
5151
|
-
this.reconnectAttempts = 0;
|
|
5152
|
-
this.startPingInterval();
|
|
5153
|
-
this.send({
|
|
5154
|
-
type: "register",
|
|
5155
|
-
owner: this.opts.owner,
|
|
5156
|
-
...this.opts.agent_id ? { agent_id: this.opts.agent_id } : {},
|
|
5157
|
-
...this.opts.server_id ? { server_id: this.opts.server_id } : {},
|
|
5158
|
-
token: this.opts.token,
|
|
5159
|
-
card: this.opts.card,
|
|
5160
|
-
...this.opts.cards && this.opts.cards.length > 0 ? { cards: this.opts.cards } : {},
|
|
5161
|
-
...this.opts.agents && this.opts.agents.length > 0 ? { agents: this.opts.agents } : {}
|
|
5162
|
-
});
|
|
5163
|
-
});
|
|
5164
|
-
this.ws.on("message", (raw) => {
|
|
5165
|
-
this.handleMessage(raw, (err) => {
|
|
5166
|
-
if (!resolved) {
|
|
5167
|
-
resolved = true;
|
|
5168
|
-
if (err) reject(err);
|
|
5169
|
-
else resolve();
|
|
5170
|
-
}
|
|
5171
|
-
});
|
|
5172
|
-
});
|
|
5173
|
-
this.ws.on("close", () => {
|
|
5174
|
-
this.cleanup();
|
|
5175
|
-
if (!this.intentionalClose) {
|
|
5176
|
-
if (!resolved) {
|
|
5177
|
-
resolved = true;
|
|
5178
|
-
reject(new Error("WebSocket closed before registration"));
|
|
5179
|
-
}
|
|
5180
|
-
this.scheduleReconnect();
|
|
5181
|
-
}
|
|
5182
|
-
});
|
|
5183
|
-
this.ws.on("error", (err) => {
|
|
5184
|
-
if (!resolved) {
|
|
5185
|
-
resolved = true;
|
|
5186
|
-
reject(err);
|
|
5187
|
-
}
|
|
5188
|
-
});
|
|
5189
|
-
setTimeout(() => {
|
|
5190
|
-
if (!resolved) {
|
|
5191
|
-
resolved = true;
|
|
5192
|
-
reject(new Error("Connection timeout"));
|
|
5193
|
-
this.ws?.close();
|
|
5194
|
-
}
|
|
5195
|
-
}, 1e4);
|
|
5196
|
-
});
|
|
5197
|
-
}
|
|
5198
|
-
/**
|
|
5199
|
-
* Disconnect from the registry relay.
|
|
5200
|
-
*/
|
|
5201
|
-
disconnect() {
|
|
5202
|
-
this.intentionalClose = true;
|
|
5203
|
-
this.cleanup();
|
|
5204
|
-
if (this.ws) {
|
|
5205
|
-
try {
|
|
5206
|
-
this.ws.close(1e3, "Client disconnect");
|
|
5207
|
-
} catch {
|
|
5208
|
-
}
|
|
5209
|
-
this.ws = null;
|
|
5210
|
-
}
|
|
5211
|
-
for (const [id, pending] of this.pendingRequests) {
|
|
5212
|
-
clearTimeout(pending.timeout);
|
|
5213
|
-
pending.reject(new Error("Client disconnected"));
|
|
5214
|
-
this.pendingRequests.delete(id);
|
|
5215
|
-
}
|
|
5216
|
-
}
|
|
5217
|
-
/**
|
|
5218
|
-
* Send a relay request to another agent via the registry.
|
|
5219
|
-
* @returns The result from the target agent.
|
|
5220
|
-
*/
|
|
5221
|
-
async request(opts) {
|
|
5222
|
-
if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.registered) {
|
|
5223
|
-
throw new Error("Not connected to registry relay");
|
|
5224
|
-
}
|
|
5225
|
-
const id = randomUUID17();
|
|
5226
|
-
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
5227
|
-
return new Promise((resolve, reject) => {
|
|
5228
|
-
const timeout = setTimeout(() => {
|
|
5229
|
-
this.pendingRequests.delete(id);
|
|
5230
|
-
reject(new Error("Relay request timeout"));
|
|
5231
|
-
}, timeoutMs);
|
|
5232
|
-
this.pendingRequests.set(id, { resolve, reject, timeout, timeoutMs, onProgress: opts.onProgress });
|
|
5233
|
-
this.send({
|
|
5234
|
-
type: "relay_request",
|
|
5235
|
-
id,
|
|
5236
|
-
target_owner: opts.targetOwner,
|
|
5237
|
-
...opts.targetAgentId ? { target_agent_id: opts.targetAgentId } : {},
|
|
5238
|
-
card_id: opts.cardId,
|
|
5239
|
-
skill_id: opts.skillId,
|
|
5240
|
-
params: opts.params,
|
|
5241
|
-
requester: opts.requester ?? this.opts.owner,
|
|
5242
|
-
escrow_receipt: opts.escrowReceipt
|
|
5243
|
-
});
|
|
5244
|
-
});
|
|
5245
|
-
}
|
|
5246
|
-
/**
|
|
5247
|
-
* Send a relay_progress message to the relay server for a given request.
|
|
5248
|
-
* Used by the onRequest handler to forward SkillExecutor progress updates
|
|
5249
|
-
* to the requesting agent so it can reset its timeout window.
|
|
5250
|
-
*
|
|
5251
|
-
* @param requestId - The relay request ID to associate progress with.
|
|
5252
|
-
* @param info - Progress details (step, total, message).
|
|
5253
|
-
*/
|
|
5254
|
-
sendProgress(requestId, info) {
|
|
5255
|
-
this.send({
|
|
5256
|
-
type: "relay_progress",
|
|
5257
|
-
id: requestId,
|
|
5258
|
-
progress: Math.round(info.step / info.total * 100),
|
|
5259
|
-
message: info.message
|
|
5260
|
-
});
|
|
5261
|
-
}
|
|
5262
|
-
/** Whether the client is connected and registered */
|
|
5263
|
-
get isConnected() {
|
|
5264
|
-
return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
|
|
5265
|
-
}
|
|
5266
|
-
// ── Private methods ─────────────────────────────────────────────────────────
|
|
5267
|
-
buildWsUrl() {
|
|
5268
|
-
let url = this.opts.registryUrl;
|
|
5269
|
-
if (url.startsWith("http://")) {
|
|
5270
|
-
url = "ws://" + url.slice(7);
|
|
5271
|
-
} else if (url.startsWith("https://")) {
|
|
5272
|
-
url = "wss://" + url.slice(8);
|
|
5273
|
-
} else if (!url.startsWith("ws://") && !url.startsWith("wss://")) {
|
|
5274
|
-
url = "wss://" + url;
|
|
5275
|
-
}
|
|
5276
|
-
if (!url.endsWith("/ws")) {
|
|
5277
|
-
url = url.replace(/\/$/, "") + "/ws";
|
|
5278
|
-
}
|
|
5279
|
-
return url;
|
|
5280
|
-
}
|
|
5281
|
-
handleMessage(raw, onRegistered) {
|
|
5282
|
-
let data;
|
|
5283
|
-
try {
|
|
5284
|
-
data = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf-8"));
|
|
5285
|
-
} catch {
|
|
5286
|
-
return;
|
|
5287
|
-
}
|
|
5288
|
-
const parsed = RelayMessageSchema.safeParse(data);
|
|
5289
|
-
if (!parsed.success) return;
|
|
5290
|
-
const msg = parsed.data;
|
|
5291
|
-
switch (msg.type) {
|
|
5292
|
-
case "registered":
|
|
5293
|
-
this.registered = true;
|
|
5294
|
-
if (!this.opts.silent) {
|
|
5295
|
-
console.log(` \u2713 Registered with registry (agent_id: ${msg.agent_id})`);
|
|
5296
|
-
}
|
|
5297
|
-
onRegistered?.();
|
|
5298
|
-
break;
|
|
5299
|
-
case "incoming_request":
|
|
5300
|
-
this.handleIncomingRequest(msg);
|
|
5301
|
-
break;
|
|
5302
|
-
case "response":
|
|
5303
|
-
this.handleResponse(msg);
|
|
5304
|
-
break;
|
|
5305
|
-
case "error":
|
|
5306
|
-
this.handleError(msg);
|
|
5307
|
-
break;
|
|
5308
|
-
case "relay_progress":
|
|
5309
|
-
this.handleProgress(msg);
|
|
5310
|
-
break;
|
|
5311
|
-
default:
|
|
5312
|
-
break;
|
|
5313
|
-
}
|
|
5314
|
-
}
|
|
5315
|
-
async handleIncomingRequest(msg) {
|
|
5316
|
-
try {
|
|
5317
|
-
const result = await this.opts.onRequest(msg);
|
|
5318
|
-
this.send({
|
|
5319
|
-
type: "relay_response",
|
|
5320
|
-
id: msg.id,
|
|
5321
|
-
result: result.result,
|
|
5322
|
-
error: result.error
|
|
5323
|
-
});
|
|
5324
|
-
} catch (err) {
|
|
5325
|
-
this.send({
|
|
5326
|
-
type: "relay_response",
|
|
5327
|
-
id: msg.id,
|
|
5328
|
-
error: {
|
|
5329
|
-
code: -32603,
|
|
5330
|
-
message: err instanceof Error ? err.message : "Internal error"
|
|
5331
|
-
}
|
|
5332
|
-
});
|
|
5333
|
-
}
|
|
5334
|
-
}
|
|
5335
|
-
handleResponse(msg) {
|
|
5336
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
5337
|
-
if (!pending) return;
|
|
5338
|
-
clearTimeout(pending.timeout);
|
|
5339
|
-
this.pendingRequests.delete(msg.id);
|
|
5340
|
-
if (msg.error) {
|
|
5341
|
-
pending.reject(new Error(msg.error.message));
|
|
5342
|
-
} else {
|
|
5343
|
-
pending.resolve(msg.result);
|
|
5344
|
-
}
|
|
5345
|
-
}
|
|
5346
|
-
handleError(msg) {
|
|
5347
|
-
if (msg.request_id) {
|
|
5348
|
-
const pending = this.pendingRequests.get(msg.request_id);
|
|
5349
|
-
if (pending) {
|
|
5350
|
-
clearTimeout(pending.timeout);
|
|
5351
|
-
this.pendingRequests.delete(msg.request_id);
|
|
5352
|
-
pending.reject(new Error(`${msg.code}: ${msg.message}`));
|
|
5353
|
-
}
|
|
5354
|
-
}
|
|
5355
|
-
}
|
|
5356
|
-
handleProgress(msg) {
|
|
5357
|
-
const pending = this.pendingRequests.get(msg.id);
|
|
5358
|
-
if (!pending) return;
|
|
5359
|
-
clearTimeout(pending.timeout);
|
|
5360
|
-
const newTimeout = setTimeout(() => {
|
|
5361
|
-
this.pendingRequests.delete(msg.id);
|
|
5362
|
-
pending.reject(new Error("Relay request timeout"));
|
|
5363
|
-
}, pending.timeoutMs);
|
|
5364
|
-
pending.timeout = newTimeout;
|
|
5365
|
-
if (pending.onProgress) {
|
|
5366
|
-
pending.onProgress({ id: msg.id, progress: msg.progress, message: msg.message });
|
|
5367
|
-
}
|
|
5368
|
-
}
|
|
5369
|
-
send(msg) {
|
|
5370
|
-
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
5371
|
-
this.ws.send(JSON.stringify(msg));
|
|
5372
|
-
}
|
|
5373
|
-
}
|
|
5374
|
-
startPingInterval() {
|
|
5375
|
-
this.stopPingInterval();
|
|
5376
|
-
this.pingInterval = setInterval(() => {
|
|
5377
|
-
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
5378
|
-
this.ws.ping();
|
|
5379
|
-
this.pongTimeout = setTimeout(() => {
|
|
5380
|
-
if (!this.opts.silent) {
|
|
5381
|
-
console.log(" \u26A0 Registry pong timeout, reconnecting...");
|
|
5382
|
-
}
|
|
5383
|
-
this.ws?.terminate();
|
|
5384
|
-
}, 15e3);
|
|
5385
|
-
}
|
|
5386
|
-
}, 3e4);
|
|
5387
|
-
this.ws?.on("pong", () => {
|
|
5388
|
-
if (this.pongTimeout) {
|
|
5389
|
-
clearTimeout(this.pongTimeout);
|
|
5390
|
-
this.pongTimeout = null;
|
|
5391
|
-
}
|
|
5392
|
-
});
|
|
5393
|
-
}
|
|
5394
|
-
stopPingInterval() {
|
|
5395
|
-
if (this.pingInterval) {
|
|
5396
|
-
clearInterval(this.pingInterval);
|
|
5397
|
-
this.pingInterval = null;
|
|
5398
|
-
}
|
|
5399
|
-
if (this.pongTimeout) {
|
|
5400
|
-
clearTimeout(this.pongTimeout);
|
|
5401
|
-
this.pongTimeout = null;
|
|
5402
|
-
}
|
|
5403
|
-
}
|
|
5404
|
-
cleanup() {
|
|
5405
|
-
this.stopPingInterval();
|
|
5406
|
-
this.registered = false;
|
|
5407
|
-
}
|
|
5408
|
-
scheduleReconnect() {
|
|
5409
|
-
if (this.intentionalClose) return;
|
|
5410
|
-
if (this.reconnectTimer) return;
|
|
5411
|
-
const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4);
|
|
5412
|
-
this.reconnectAttempts++;
|
|
5413
|
-
if (!this.opts.silent) {
|
|
5414
|
-
console.log(` \u21BB Reconnecting to registry in ${delay / 1e3}s...`);
|
|
5415
|
-
}
|
|
5416
|
-
this.reconnectTimer = setTimeout(async () => {
|
|
5417
|
-
this.reconnectTimer = null;
|
|
5418
|
-
try {
|
|
5419
|
-
await this.connect();
|
|
5420
|
-
if (!this.opts.silent) {
|
|
5421
|
-
console.log(" \u2713 Reconnected to registry");
|
|
5422
|
-
}
|
|
5423
|
-
} catch {
|
|
5424
|
-
}
|
|
5425
|
-
}, delay);
|
|
5426
|
-
}
|
|
5427
|
-
};
|
|
5428
|
-
|
|
5429
5373
|
// src/onboarding/index.ts
|
|
5430
5374
|
import { randomUUID as randomUUID19 } from "crypto";
|
|
5431
5375
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|