agentbnb 5.1.11 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{card-RSGDCHCV.js → card-REW7BSWW.js} +1 -1
- package/dist/{chunk-EPIWHNB2.js → chunk-2TLZ6G2B.js} +446 -373
- package/dist/{chunk-WGZ5AGOX.js → chunk-3CIMVISQ.js} +24 -1
- package/dist/{chunk-NH2FIERR.js → chunk-574W3HHE.js} +1 -1
- package/dist/{chunk-B5FTAGFN.js → chunk-7XHDSWRD.js} +75 -75
- package/dist/{chunk-NLAWT4DT.js → chunk-7YLFLC5C.js} +6 -6
- package/dist/chunk-BP3L2TET.js +148 -0
- package/dist/{chunk-EGUOAHCW.js → chunk-C2T4BMRW.js} +12 -12
- package/dist/{chunk-5KFI5X7B.js → chunk-F53QQIM2.js} +1 -1
- package/dist/chunk-JR6TJDIF.js +425 -0
- package/dist/{chunk-DFBX3BBD.js → chunk-KA2VIEGM.js} +211 -16
- package/dist/chunk-NQTE577Q.js +159 -0
- package/dist/{chunk-WTXRY7R2.js → chunk-NYV3NE5Z.js} +157 -9
- package/dist/{chunk-UKT6H7YT.js → chunk-OZXCRLP3.js} +1 -1
- package/dist/{chunk-QITOPASZ.js → chunk-PSQHUZ7X.js} +1 -1
- package/dist/{chunk-EANI2N2V.js → chunk-RVYQSC6L.js} +2 -99
- package/dist/{chunk-MLS6IGGG.js → chunk-TQDV254A.js} +1 -1
- package/dist/{chunk-QQFBFV4V.js → chunk-TR6UZDNX.js} +57 -18
- package/dist/{chunk-ZX5623ER.js → chunk-VMH2YS2I.js} +1 -1
- package/dist/{chunk-XND2DWTZ.js → chunk-VPQ44XKE.js} +2 -2
- package/dist/{chunk-CSATDXZC.js → chunk-Y7T6IMM3.js} +1 -1
- package/dist/{chunk-FLY3WIQR.js → chunk-YRRVFTDR.js} +3 -3
- package/dist/cli/index.js +261 -125
- package/dist/{client-T5MTY3CS.js → client-HRYRJKSA.js} +3 -3
- package/dist/{conduct-WU3VEXB6.js → conduct-LF6FYPLD.js} +11 -11
- package/dist/conduct-QAFZIEY6.js +21 -0
- package/dist/{conductor-mode-ZMTFZGJP.js → conductor-mode-NUDQLZFM.js} +309 -13
- package/dist/conductor-mode-YQ6QSPPT.js +275 -0
- package/dist/{execute-4D4ITQCL.js → execute-ITHIYYOX.js} +4 -3
- package/dist/execute-PNJFABVJ.js +14 -0
- package/dist/index.d.ts +555 -0
- package/dist/index.js +592 -83
- package/dist/{process-guard-CC7CNRQJ.js → process-guard-QCCBGILS.js} +1 -1
- package/dist/publish-capability-TS6CNR5G.js +12 -0
- package/dist/{request-VOXBFUOG.js → request-P6QCTCCG.js} +14 -14
- package/dist/{serve-skill-IH7UAJNR.js → serve-skill-EZOL7UYN.js} +10 -9
- package/dist/{server-JVQW2TID.js → server-3G6ZTASA.js} +16 -16
- package/dist/{service-coordinator-EYRDTHL5.js → service-coordinator-CRSE4GWC.js} +174 -242
- package/dist/skill-config-4W5W5O6T.js +22 -0
- package/dist/skills/agentbnb/bootstrap.js +227 -67
- package/package.json +1 -1
- package/skills/agentbnb/SKILL.md +35 -0
- package/skills/agentbnb/bootstrap.ts +126 -8
- package/skills/agentbnb/install.sh +49 -9
- package/dist/chunk-CRFCWD6V.js +0 -366
- package/dist/conduct-6LKIJJKQ.js +0 -21
- package/dist/conductor-mode-Q4IIDY5E.js +0 -123
- package/dist/execute-T7Y6RKSW.js +0 -13
package/dist/index.js
CHANGED
|
@@ -48,7 +48,9 @@ var CapabilityCardSchema = z.object({
|
|
|
48
48
|
tags: z.array(z.string()).optional()
|
|
49
49
|
}).optional(),
|
|
50
50
|
created_at: z.string().datetime().optional(),
|
|
51
|
-
updated_at: z.string().datetime().optional()
|
|
51
|
+
updated_at: z.string().datetime().optional(),
|
|
52
|
+
/** Exact-match capability type key for network routing (e.g. 'task_decomposition'). Optional — backward-compatible. */
|
|
53
|
+
capability_type: z.string().optional()
|
|
52
54
|
});
|
|
53
55
|
var SkillSchema = z.object({
|
|
54
56
|
/** Stable skill identifier, e.g. 'tts-elevenlabs'. Used for gateway routing and idle tracking. */
|
|
@@ -58,6 +60,25 @@ var SkillSchema = z.object({
|
|
|
58
60
|
level: z.union([z.literal(1), z.literal(2), z.literal(3)]),
|
|
59
61
|
/** Optional grouping category, e.g. 'tts' | 'video_gen' | 'code_review'. */
|
|
60
62
|
category: z.string().optional(),
|
|
63
|
+
/** Exact-match capability type key for network routing (e.g. 'task_decomposition'). Optional — per-skill routing hint. */
|
|
64
|
+
capability_type: z.string().optional(),
|
|
65
|
+
/**
|
|
66
|
+
* Multi-value capability routing tags — what this skill IS / offers to the outside.
|
|
67
|
+
* Used by Conductor for precise skill-level matching.
|
|
68
|
+
* Example: ["audio_generation", "audio_editing", "content_production"]
|
|
69
|
+
*/
|
|
70
|
+
capability_types: z.array(z.string()).optional(),
|
|
71
|
+
/**
|
|
72
|
+
* Capabilities this skill internally depends on when executing.
|
|
73
|
+
* Used by Conductor for decomposition planning and cost estimation.
|
|
74
|
+
* Example: ["tts", "sound_effects", "audio_mixing"]
|
|
75
|
+
*/
|
|
76
|
+
requires_capabilities: z.array(z.string()).optional(),
|
|
77
|
+
/**
|
|
78
|
+
* Publishing visibility. 'private' skills are excluded from published CapabilityCards.
|
|
79
|
+
* Defaults to 'public' when omitted.
|
|
80
|
+
*/
|
|
81
|
+
visibility: z.enum(["public", "private"]).optional(),
|
|
61
82
|
inputs: z.array(IOSchemaSchema),
|
|
62
83
|
outputs: z.array(IOSchemaSchema),
|
|
63
84
|
pricing: z.object({
|
|
@@ -144,6 +165,8 @@ var CapabilityCardV2Schema = z.object({
|
|
|
144
165
|
_internal: z.record(z.unknown()).optional(),
|
|
145
166
|
/** Public gateway URL where this agent accepts requests. Populated on remote publish. */
|
|
146
167
|
gateway_url: z.string().url().optional(),
|
|
168
|
+
/** Exact-match capability type key for network routing (e.g. 'task_decomposition'). Optional — backward-compatible. */
|
|
169
|
+
capability_type: z.string().optional(),
|
|
147
170
|
created_at: z.string().datetime().optional(),
|
|
148
171
|
updated_at: z.string().datetime().optional()
|
|
149
172
|
});
|
|
@@ -191,11 +214,27 @@ function createRequestLogTable(db) {
|
|
|
191
214
|
db.exec("ALTER TABLE request_log ADD COLUMN tier_invoked INTEGER");
|
|
192
215
|
} catch {
|
|
193
216
|
}
|
|
217
|
+
try {
|
|
218
|
+
db.exec("ALTER TABLE request_log ADD COLUMN failure_reason TEXT");
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
db.exec("ALTER TABLE request_log ADD COLUMN team_id TEXT");
|
|
223
|
+
} catch {
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
db.exec("ALTER TABLE request_log ADD COLUMN role TEXT");
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
db.exec("ALTER TABLE request_log ADD COLUMN capability_type TEXT");
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
194
233
|
}
|
|
195
234
|
function insertRequestLog(db, entry) {
|
|
196
235
|
const stmt = db.prepare(`
|
|
197
|
-
INSERT INTO request_log (id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked)
|
|
198
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
236
|
+
INSERT INTO request_log (id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked, failure_reason, team_id, role, capability_type)
|
|
237
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
199
238
|
`);
|
|
200
239
|
stmt.run(
|
|
201
240
|
entry.id,
|
|
@@ -208,7 +247,11 @@ function insertRequestLog(db, entry) {
|
|
|
208
247
|
entry.created_at,
|
|
209
248
|
entry.skill_id ?? null,
|
|
210
249
|
entry.action_type ?? null,
|
|
211
|
-
entry.tier_invoked ?? null
|
|
250
|
+
entry.tier_invoked ?? null,
|
|
251
|
+
entry.failure_reason ?? null,
|
|
252
|
+
entry.team_id ?? null,
|
|
253
|
+
entry.role ?? null,
|
|
254
|
+
entry.capability_type ?? null
|
|
212
255
|
);
|
|
213
256
|
}
|
|
214
257
|
|
|
@@ -322,6 +365,17 @@ var V2_FTS_TRIGGERS = `
|
|
|
322
365
|
FROM json_each(json_extract(new.data, '$.metadata.tags'))),
|
|
323
366
|
''
|
|
324
367
|
)
|
|
368
|
+
|| ' ' || COALESCE(
|
|
369
|
+
(SELECT group_concat(json_extract(skill.value, '$.capability_type'), ' ')
|
|
370
|
+
FROM json_each(json_extract(new.data, '$.skills')) AS skill),
|
|
371
|
+
''
|
|
372
|
+
)
|
|
373
|
+
|| ' ' || COALESCE(
|
|
374
|
+
(SELECT group_concat(cap_type.value, ' ')
|
|
375
|
+
FROM json_each(json_extract(new.data, '$.skills')) AS skill,
|
|
376
|
+
json_each(json_extract(skill.value, '$.capability_types')) AS cap_type),
|
|
377
|
+
''
|
|
378
|
+
)
|
|
325
379
|
);
|
|
326
380
|
END;
|
|
327
381
|
|
|
@@ -351,6 +405,17 @@ var V2_FTS_TRIGGERS = `
|
|
|
351
405
|
FROM json_each(json_extract(old.data, '$.metadata.tags'))),
|
|
352
406
|
''
|
|
353
407
|
)
|
|
408
|
+
|| ' ' || COALESCE(
|
|
409
|
+
(SELECT group_concat(json_extract(skill.value, '$.capability_type'), ' ')
|
|
410
|
+
FROM json_each(json_extract(old.data, '$.skills')) AS skill),
|
|
411
|
+
''
|
|
412
|
+
)
|
|
413
|
+
|| ' ' || COALESCE(
|
|
414
|
+
(SELECT group_concat(cap_type.value, ' ')
|
|
415
|
+
FROM json_each(json_extract(old.data, '$.skills')) AS skill,
|
|
416
|
+
json_each(json_extract(skill.value, '$.capability_types')) AS cap_type),
|
|
417
|
+
''
|
|
418
|
+
)
|
|
354
419
|
);
|
|
355
420
|
INSERT INTO cards_fts(rowid, id, owner, name, description, tags)
|
|
356
421
|
VALUES (
|
|
@@ -376,6 +441,17 @@ var V2_FTS_TRIGGERS = `
|
|
|
376
441
|
FROM json_each(json_extract(new.data, '$.metadata.tags'))),
|
|
377
442
|
''
|
|
378
443
|
)
|
|
444
|
+
|| ' ' || COALESCE(
|
|
445
|
+
(SELECT group_concat(json_extract(skill.value, '$.capability_type'), ' ')
|
|
446
|
+
FROM json_each(json_extract(new.data, '$.skills')) AS skill),
|
|
447
|
+
''
|
|
448
|
+
)
|
|
449
|
+
|| ' ' || COALESCE(
|
|
450
|
+
(SELECT group_concat(cap_type.value, ' ')
|
|
451
|
+
FROM json_each(json_extract(new.data, '$.skills')) AS skill,
|
|
452
|
+
json_each(json_extract(skill.value, '$.capability_types')) AS cap_type),
|
|
453
|
+
''
|
|
454
|
+
)
|
|
379
455
|
);
|
|
380
456
|
END;
|
|
381
457
|
|
|
@@ -405,6 +481,17 @@ var V2_FTS_TRIGGERS = `
|
|
|
405
481
|
FROM json_each(json_extract(old.data, '$.metadata.tags'))),
|
|
406
482
|
''
|
|
407
483
|
)
|
|
484
|
+
|| ' ' || COALESCE(
|
|
485
|
+
(SELECT group_concat(json_extract(skill.value, '$.capability_type'), ' ')
|
|
486
|
+
FROM json_each(json_extract(old.data, '$.skills')) AS skill),
|
|
487
|
+
''
|
|
488
|
+
)
|
|
489
|
+
|| ' ' || COALESCE(
|
|
490
|
+
(SELECT group_concat(cap_type.value, ' ')
|
|
491
|
+
FROM json_each(json_extract(old.data, '$.skills')) AS skill,
|
|
492
|
+
json_each(json_extract(skill.value, '$.capability_types')) AS cap_type),
|
|
493
|
+
''
|
|
494
|
+
)
|
|
408
495
|
);
|
|
409
496
|
END;
|
|
410
497
|
`;
|
|
@@ -509,10 +596,17 @@ function migrateV1toV2(db) {
|
|
|
509
596
|
if (skills.length > 0) {
|
|
510
597
|
name = skills.map((s) => String(s["name"] ?? "")).join(" ");
|
|
511
598
|
description = skills.map((s) => String(s["description"] ?? "")).join(" ");
|
|
512
|
-
tags =
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
599
|
+
tags = [
|
|
600
|
+
// tags from metadata.tags[]
|
|
601
|
+
...skills.flatMap((s) => {
|
|
602
|
+
const meta = s["metadata"];
|
|
603
|
+
return meta?.["tags"] ?? [];
|
|
604
|
+
}),
|
|
605
|
+
// capability_type (singular)
|
|
606
|
+
...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
|
|
607
|
+
// capability_types[] (plural)
|
|
608
|
+
...skills.flatMap((s) => s["capability_types"] ?? [])
|
|
609
|
+
].join(" ");
|
|
516
610
|
} else {
|
|
517
611
|
name = String(data["name"] ?? "");
|
|
518
612
|
description = String(data["description"] ?? "");
|
|
@@ -589,6 +683,24 @@ function listCards(db, owner) {
|
|
|
589
683
|
}
|
|
590
684
|
return rows.map((row) => JSON.parse(row.data));
|
|
591
685
|
}
|
|
686
|
+
function getCardsByCapabilityType(db, capabilityType) {
|
|
687
|
+
const rows = db.prepare(
|
|
688
|
+
"SELECT data FROM capability_cards WHERE json_extract(data, '$.capability_type') = ?"
|
|
689
|
+
).all(capabilityType);
|
|
690
|
+
return rows.map((row) => JSON.parse(row.data));
|
|
691
|
+
}
|
|
692
|
+
function getCardsBySkillCapability(db, capabilityType) {
|
|
693
|
+
const rows = db.prepare("SELECT data FROM capability_cards").all();
|
|
694
|
+
return rows.map((row) => JSON.parse(row.data)).filter((card) => {
|
|
695
|
+
const skills = card["skills"];
|
|
696
|
+
if (!skills) return false;
|
|
697
|
+
return skills.some((skill) => {
|
|
698
|
+
if (skill["capability_type"] === capabilityType) return true;
|
|
699
|
+
const types = skill["capability_types"];
|
|
700
|
+
return Array.isArray(types) && types.includes(capabilityType);
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
}
|
|
592
704
|
|
|
593
705
|
// src/feedback/reputation.ts
|
|
594
706
|
var QUALITY_SCORES = {
|
|
@@ -753,6 +865,7 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
|
|
|
753
865
|
|
|
754
866
|
// src/gateway/server.ts
|
|
755
867
|
import Fastify from "fastify";
|
|
868
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
756
869
|
|
|
757
870
|
// src/gateway/execute.ts
|
|
758
871
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -926,7 +1039,50 @@ function releaseRequesterEscrow(requesterDb, escrowId) {
|
|
|
926
1039
|
releaseEscrow(requesterDb, escrowId);
|
|
927
1040
|
}
|
|
928
1041
|
|
|
1042
|
+
// src/cli/config.ts
|
|
1043
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
1044
|
+
import { homedir } from "os";
|
|
1045
|
+
import { join as join2 } from "path";
|
|
1046
|
+
function getConfigDir() {
|
|
1047
|
+
return process.env["AGENTBNB_DIR"] ?? join2(homedir(), ".agentbnb");
|
|
1048
|
+
}
|
|
1049
|
+
function getConfigPath() {
|
|
1050
|
+
return join2(getConfigDir(), "config.json");
|
|
1051
|
+
}
|
|
1052
|
+
function loadConfig() {
|
|
1053
|
+
const configPath = getConfigPath();
|
|
1054
|
+
if (!existsSync2(configPath)) return null;
|
|
1055
|
+
try {
|
|
1056
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
1057
|
+
return JSON.parse(raw);
|
|
1058
|
+
} catch {
|
|
1059
|
+
return null;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
929
1063
|
// src/gateway/execute.ts
|
|
1064
|
+
async function notifyTelegramSkillExecuted(opts) {
|
|
1065
|
+
const cfg = loadConfig();
|
|
1066
|
+
if (!cfg?.telegram_notifications) return;
|
|
1067
|
+
const token = cfg.telegram_bot_token ?? process.env["TELEGRAM_BOT_TOKEN"];
|
|
1068
|
+
const chatId = cfg.telegram_chat_id ?? process.env["TELEGRAM_CHAT_ID"];
|
|
1069
|
+
if (!token || !chatId) return;
|
|
1070
|
+
const balance = getBalance(opts.creditDb, opts.owner);
|
|
1071
|
+
const skillLabel = opts.skillId ? `${opts.skillName} (${opts.skillId})` : opts.skillName;
|
|
1072
|
+
const text = [
|
|
1073
|
+
"[AgentBnB] Skill executed",
|
|
1074
|
+
`Skill: ${skillLabel}`,
|
|
1075
|
+
`Requester: ${opts.requester}`,
|
|
1076
|
+
`Earned: +${opts.creditsEarned} credits`,
|
|
1077
|
+
`Balance: ${balance} credits`,
|
|
1078
|
+
`Latency: ${opts.latencyMs}ms`
|
|
1079
|
+
].join("\n");
|
|
1080
|
+
await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
|
|
1081
|
+
method: "POST",
|
|
1082
|
+
headers: { "Content-Type": "application/json" },
|
|
1083
|
+
body: JSON.stringify({ chat_id: chatId, text })
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
930
1086
|
async function executeCapabilityRequest(opts) {
|
|
931
1087
|
const {
|
|
932
1088
|
registryDb,
|
|
@@ -958,7 +1114,8 @@ async function executeCapabilityRequest(opts) {
|
|
|
958
1114
|
status: "failure",
|
|
959
1115
|
latency_ms: 0,
|
|
960
1116
|
credits_charged: 0,
|
|
961
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1117
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1118
|
+
failure_reason: "auth_error"
|
|
962
1119
|
});
|
|
963
1120
|
} catch {
|
|
964
1121
|
}
|
|
@@ -1013,7 +1170,7 @@ async function executeCapabilityRequest(opts) {
|
|
|
1013
1170
|
}
|
|
1014
1171
|
const startMs = Date.now();
|
|
1015
1172
|
const receiptData = isRemoteEscrow ? { receipt_released: true } : void 0;
|
|
1016
|
-
const handleFailure = (status, latencyMs, message) => {
|
|
1173
|
+
const handleFailure = (status, latencyMs, message, failureReason = "bad_execution") => {
|
|
1017
1174
|
if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
|
|
1018
1175
|
updateReputation(registryDb, cardId, false, latencyMs);
|
|
1019
1176
|
try {
|
|
@@ -1026,7 +1183,8 @@ async function executeCapabilityRequest(opts) {
|
|
|
1026
1183
|
status,
|
|
1027
1184
|
latency_ms: latencyMs,
|
|
1028
1185
|
credits_charged: 0,
|
|
1029
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1186
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1187
|
+
failure_reason: failureReason
|
|
1030
1188
|
});
|
|
1031
1189
|
} catch {
|
|
1032
1190
|
}
|
|
@@ -1056,6 +1214,16 @@ async function executeCapabilityRequest(opts) {
|
|
|
1056
1214
|
});
|
|
1057
1215
|
} catch {
|
|
1058
1216
|
}
|
|
1217
|
+
notifyTelegramSkillExecuted({
|
|
1218
|
+
creditDb,
|
|
1219
|
+
owner: card.owner,
|
|
1220
|
+
skillName: cardName,
|
|
1221
|
+
skillId: resolvedSkillId ?? null,
|
|
1222
|
+
requester,
|
|
1223
|
+
creditsEarned: creditsNeeded,
|
|
1224
|
+
latencyMs
|
|
1225
|
+
}).catch(() => {
|
|
1226
|
+
});
|
|
1059
1227
|
const successResult = isRemoteEscrow ? {
|
|
1060
1228
|
...typeof result === "object" && result !== null ? result : { data: result },
|
|
1061
1229
|
receipt_settled: true,
|
|
@@ -1073,23 +1241,24 @@ async function executeCapabilityRequest(opts) {
|
|
|
1073
1241
|
return handleFailure(
|
|
1074
1242
|
"failure",
|
|
1075
1243
|
Date.now() - startMs,
|
|
1076
|
-
"No skill_id specified and no skills registered on this provider."
|
|
1244
|
+
"No skill_id specified and no skills registered on this provider.",
|
|
1245
|
+
"not_found"
|
|
1077
1246
|
);
|
|
1078
1247
|
}
|
|
1079
1248
|
}
|
|
1080
1249
|
try {
|
|
1081
1250
|
const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
|
|
1082
1251
|
if (!execResult.success) {
|
|
1083
|
-
return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed");
|
|
1252
|
+
return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed", "bad_execution");
|
|
1084
1253
|
}
|
|
1085
1254
|
return handleSuccess(execResult.result, execResult.latency_ms);
|
|
1086
1255
|
} catch (err) {
|
|
1087
1256
|
const message = err instanceof Error ? err.message : "Execution error";
|
|
1088
|
-
return handleFailure("failure", Date.now() - startMs, message);
|
|
1257
|
+
return handleFailure("failure", Date.now() - startMs, message, "bad_execution");
|
|
1089
1258
|
}
|
|
1090
1259
|
}
|
|
1091
1260
|
if (!handlerUrl) {
|
|
1092
|
-
return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured");
|
|
1261
|
+
return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured", "bad_execution");
|
|
1093
1262
|
}
|
|
1094
1263
|
const controller = new AbortController();
|
|
1095
1264
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -1102,7 +1271,7 @@ async function executeCapabilityRequest(opts) {
|
|
|
1102
1271
|
});
|
|
1103
1272
|
clearTimeout(timer);
|
|
1104
1273
|
if (!response.ok) {
|
|
1105
|
-
return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}
|
|
1274
|
+
return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`, "bad_execution");
|
|
1106
1275
|
}
|
|
1107
1276
|
const result = await response.json();
|
|
1108
1277
|
return handleSuccess(result, Date.now() - startMs);
|
|
@@ -1112,7 +1281,8 @@ async function executeCapabilityRequest(opts) {
|
|
|
1112
1281
|
return handleFailure(
|
|
1113
1282
|
isTimeout ? "timeout" : "failure",
|
|
1114
1283
|
Date.now() - startMs,
|
|
1115
|
-
isTimeout ? "Execution timeout" : "Handler error"
|
|
1284
|
+
isTimeout ? "Execution timeout" : "Handler error",
|
|
1285
|
+
isTimeout ? "timeout" : "bad_execution"
|
|
1116
1286
|
);
|
|
1117
1287
|
}
|
|
1118
1288
|
}
|
|
@@ -1131,6 +1301,8 @@ function createGatewayServer(opts) {
|
|
|
1131
1301
|
} = opts;
|
|
1132
1302
|
const fastify = Fastify({ logger: !silent });
|
|
1133
1303
|
const tokenSet = new Set(tokens);
|
|
1304
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
1305
|
+
const OVERLOAD_RETRY_MS = 5e3;
|
|
1134
1306
|
fastify.addHook("onRequest", async (request) => {
|
|
1135
1307
|
if (request.method === "GET" && request.url === "/health") return;
|
|
1136
1308
|
const auth = request.headers.authorization;
|
|
@@ -1196,18 +1368,63 @@ function createGatewayServer(opts) {
|
|
|
1196
1368
|
}
|
|
1197
1369
|
const requester = params.requester ?? "unknown";
|
|
1198
1370
|
const receipt = params.escrow_receipt;
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1371
|
+
if (skillExecutor && skillId && typeof skillExecutor.getSkillConfig === "function") {
|
|
1372
|
+
const skillConfig = skillExecutor.getSkillConfig(skillId);
|
|
1373
|
+
const maxConcurrent = skillConfig?.capacity?.max_concurrent;
|
|
1374
|
+
if (maxConcurrent !== void 0) {
|
|
1375
|
+
const current = inFlight.get(skillId) ?? 0;
|
|
1376
|
+
if (current >= maxConcurrent) {
|
|
1377
|
+
try {
|
|
1378
|
+
insertRequestLog(registryDb, {
|
|
1379
|
+
id: randomUUID6(),
|
|
1380
|
+
card_id: cardId,
|
|
1381
|
+
card_name: "<overload>",
|
|
1382
|
+
requester,
|
|
1383
|
+
status: "failure",
|
|
1384
|
+
latency_ms: 0,
|
|
1385
|
+
credits_charged: 0,
|
|
1386
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1387
|
+
skill_id: skillId,
|
|
1388
|
+
failure_reason: "overload"
|
|
1389
|
+
});
|
|
1390
|
+
} catch {
|
|
1391
|
+
}
|
|
1392
|
+
return reply.status(200).send({
|
|
1393
|
+
jsonrpc: "2.0",
|
|
1394
|
+
id,
|
|
1395
|
+
error: {
|
|
1396
|
+
code: -32e3,
|
|
1397
|
+
message: "overload",
|
|
1398
|
+
data: { error: "overload", retry_after_ms: OVERLOAD_RETRY_MS }
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
const trackKey = skillId ?? cardId;
|
|
1405
|
+
inFlight.set(trackKey, (inFlight.get(trackKey) ?? 0) + 1);
|
|
1406
|
+
let result;
|
|
1407
|
+
try {
|
|
1408
|
+
result = await executeCapabilityRequest({
|
|
1409
|
+
registryDb,
|
|
1410
|
+
creditDb,
|
|
1411
|
+
cardId,
|
|
1412
|
+
skillId,
|
|
1413
|
+
params,
|
|
1414
|
+
requester,
|
|
1415
|
+
escrowReceipt: receipt,
|
|
1416
|
+
skillExecutor,
|
|
1417
|
+
handlerUrl,
|
|
1418
|
+
timeoutMs
|
|
1419
|
+
});
|
|
1420
|
+
} finally {
|
|
1421
|
+
const next = (inFlight.get(trackKey) ?? 1) - 1;
|
|
1422
|
+
if (next <= 0) {
|
|
1423
|
+
inFlight.delete(trackKey);
|
|
1424
|
+
} else {
|
|
1425
|
+
inFlight.set(trackKey, next);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1211
1428
|
if (result.success) {
|
|
1212
1429
|
return reply.send({ jsonrpc: "2.0", id, result: result.result });
|
|
1213
1430
|
} else {
|
|
@@ -1300,6 +1517,9 @@ function createSkillExecutor(configs, modes) {
|
|
|
1300
1517
|
// src/skills/skill-config.ts
|
|
1301
1518
|
import { z as z2 } from "zod";
|
|
1302
1519
|
import yaml from "js-yaml";
|
|
1520
|
+
var CapacitySchema = z2.object({
|
|
1521
|
+
max_concurrent: z2.number().positive().int().optional()
|
|
1522
|
+
}).optional();
|
|
1303
1523
|
var PricingSchema = z2.object({
|
|
1304
1524
|
credits_per_call: z2.number().nonnegative(),
|
|
1305
1525
|
credits_per_minute: z2.number().nonnegative().optional(),
|
|
@@ -1321,6 +1541,12 @@ var ApiAuthSchema = z2.discriminatedUnion("type", [
|
|
|
1321
1541
|
password: z2.string()
|
|
1322
1542
|
})
|
|
1323
1543
|
]);
|
|
1544
|
+
var CapabilityDeclarationSchema = {
|
|
1545
|
+
description: z2.string().optional(),
|
|
1546
|
+
capability_types: z2.array(z2.string()).optional(),
|
|
1547
|
+
requires_capabilities: z2.array(z2.string()).optional(),
|
|
1548
|
+
visibility: z2.enum(["public", "private"]).optional()
|
|
1549
|
+
};
|
|
1324
1550
|
var ApiSkillConfigSchema = z2.object({
|
|
1325
1551
|
id: z2.string().min(1),
|
|
1326
1552
|
type: z2.literal("api"),
|
|
@@ -1333,7 +1559,9 @@ var ApiSkillConfigSchema = z2.object({
|
|
|
1333
1559
|
pricing: PricingSchema,
|
|
1334
1560
|
timeout_ms: z2.number().positive().default(3e4),
|
|
1335
1561
|
retries: z2.number().nonnegative().int().default(0),
|
|
1336
|
-
provider: z2.string().optional()
|
|
1562
|
+
provider: z2.string().optional(),
|
|
1563
|
+
capacity: CapacitySchema,
|
|
1564
|
+
...CapabilityDeclarationSchema
|
|
1337
1565
|
});
|
|
1338
1566
|
var PipelineStepSchema = z2.union([
|
|
1339
1567
|
z2.object({
|
|
@@ -1351,7 +1579,9 @@ var PipelineSkillConfigSchema = z2.object({
|
|
|
1351
1579
|
name: z2.string().min(1),
|
|
1352
1580
|
steps: z2.array(PipelineStepSchema).min(1),
|
|
1353
1581
|
pricing: PricingSchema,
|
|
1354
|
-
timeout_ms: z2.number().positive().optional()
|
|
1582
|
+
timeout_ms: z2.number().positive().optional(),
|
|
1583
|
+
capacity: CapacitySchema,
|
|
1584
|
+
...CapabilityDeclarationSchema
|
|
1355
1585
|
});
|
|
1356
1586
|
var OpenClawSkillConfigSchema = z2.object({
|
|
1357
1587
|
id: z2.string().min(1),
|
|
@@ -1360,7 +1590,9 @@ var OpenClawSkillConfigSchema = z2.object({
|
|
|
1360
1590
|
agent_name: z2.string().min(1),
|
|
1361
1591
|
channel: z2.enum(["telegram", "webhook", "process"]),
|
|
1362
1592
|
pricing: PricingSchema,
|
|
1363
|
-
timeout_ms: z2.number().positive().optional()
|
|
1593
|
+
timeout_ms: z2.number().positive().optional(),
|
|
1594
|
+
capacity: CapacitySchema,
|
|
1595
|
+
...CapabilityDeclarationSchema
|
|
1364
1596
|
});
|
|
1365
1597
|
var CommandSkillConfigSchema = z2.object({
|
|
1366
1598
|
id: z2.string().min(1),
|
|
@@ -1371,7 +1603,9 @@ var CommandSkillConfigSchema = z2.object({
|
|
|
1371
1603
|
allowed_commands: z2.array(z2.string()).optional(),
|
|
1372
1604
|
working_dir: z2.string().optional(),
|
|
1373
1605
|
timeout_ms: z2.number().positive().default(3e4),
|
|
1374
|
-
pricing: PricingSchema
|
|
1606
|
+
pricing: PricingSchema,
|
|
1607
|
+
capacity: CapacitySchema,
|
|
1608
|
+
...CapabilityDeclarationSchema
|
|
1375
1609
|
});
|
|
1376
1610
|
var ConductorSkillConfigSchema = z2.object({
|
|
1377
1611
|
id: z2.string().min(1),
|
|
@@ -1379,7 +1613,9 @@ var ConductorSkillConfigSchema = z2.object({
|
|
|
1379
1613
|
name: z2.string().min(1),
|
|
1380
1614
|
conductor_skill: z2.enum(["orchestrate", "plan"]),
|
|
1381
1615
|
pricing: PricingSchema,
|
|
1382
|
-
timeout_ms: z2.number().positive().optional()
|
|
1616
|
+
timeout_ms: z2.number().positive().optional(),
|
|
1617
|
+
capacity: CapacitySchema,
|
|
1618
|
+
...CapabilityDeclarationSchema
|
|
1383
1619
|
});
|
|
1384
1620
|
var SkillConfigSchema = z2.discriminatedUnion("type", [
|
|
1385
1621
|
ApiSkillConfigSchema,
|
|
@@ -2017,7 +2253,143 @@ var CommandExecutor = class {
|
|
|
2017
2253
|
};
|
|
2018
2254
|
|
|
2019
2255
|
// src/conductor/task-decomposer.ts
|
|
2020
|
-
import { randomUUID as
|
|
2256
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
2257
|
+
|
|
2258
|
+
// src/conductor/decomposition-validator.ts
|
|
2259
|
+
function validateAndNormalizeSubtasks(raw, context) {
|
|
2260
|
+
try {
|
|
2261
|
+
return _validate(raw, context);
|
|
2262
|
+
} catch {
|
|
2263
|
+
return { valid: [], errors: ["internal validation error"] };
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
function _validate(raw, context) {
|
|
2267
|
+
if (!Array.isArray(raw)) {
|
|
2268
|
+
return { valid: [], errors: ["decomposition output must be an array"] };
|
|
2269
|
+
}
|
|
2270
|
+
if (raw.length === 0) {
|
|
2271
|
+
return { valid: [], errors: [] };
|
|
2272
|
+
}
|
|
2273
|
+
const errors = [];
|
|
2274
|
+
const validItems = [];
|
|
2275
|
+
const validIds = [];
|
|
2276
|
+
for (let i = 0; i < raw.length; i++) {
|
|
2277
|
+
const item = raw[i];
|
|
2278
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) {
|
|
2279
|
+
errors.push(`subtask[${i}]: must be an object`);
|
|
2280
|
+
continue;
|
|
2281
|
+
}
|
|
2282
|
+
const obj = item;
|
|
2283
|
+
let itemValid = true;
|
|
2284
|
+
const id = obj["id"];
|
|
2285
|
+
if (typeof id !== "string" || id.length === 0) {
|
|
2286
|
+
errors.push(`subtask[${i}]: id must be a non-empty string`);
|
|
2287
|
+
itemValid = false;
|
|
2288
|
+
}
|
|
2289
|
+
const description = obj["description"];
|
|
2290
|
+
if (typeof description !== "string" || description.length === 0) {
|
|
2291
|
+
errors.push(`subtask[${i}]: description must be a non-empty string`);
|
|
2292
|
+
itemValid = false;
|
|
2293
|
+
}
|
|
2294
|
+
const required_capability = obj["required_capability"];
|
|
2295
|
+
if (typeof required_capability !== "string" || required_capability.length === 0) {
|
|
2296
|
+
errors.push(`subtask[${i}]: required_capability must be a non-empty string`);
|
|
2297
|
+
itemValid = false;
|
|
2298
|
+
}
|
|
2299
|
+
const estimated_credits = obj["estimated_credits"];
|
|
2300
|
+
if (estimated_credits !== void 0) {
|
|
2301
|
+
if (typeof estimated_credits !== "number" || estimated_credits <= 0) {
|
|
2302
|
+
errors.push(`subtask[${i}]: estimated_credits must be a positive number`);
|
|
2303
|
+
itemValid = false;
|
|
2304
|
+
} else if (estimated_credits > context.max_credits) {
|
|
2305
|
+
errors.push(
|
|
2306
|
+
`subtask[${i}]: estimated_credits ${estimated_credits} exceeds max_credits ${context.max_credits}`
|
|
2307
|
+
);
|
|
2308
|
+
itemValid = false;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
if (itemValid) {
|
|
2312
|
+
validItems.push(obj);
|
|
2313
|
+
validIds.push(id);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
const idSet = /* @__PURE__ */ new Set();
|
|
2317
|
+
for (const id of validIds) {
|
|
2318
|
+
if (idSet.has(id)) {
|
|
2319
|
+
errors.push(`duplicate subtask id: ${id}`);
|
|
2320
|
+
} else {
|
|
2321
|
+
idSet.add(id);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
for (let i = 0; i < validItems.length; i++) {
|
|
2325
|
+
const item = validItems[i];
|
|
2326
|
+
const depends_on = item["depends_on"];
|
|
2327
|
+
if (!Array.isArray(depends_on)) continue;
|
|
2328
|
+
for (const dep of depends_on) {
|
|
2329
|
+
if (typeof dep === "string" && !idSet.has(dep)) {
|
|
2330
|
+
errors.push(`subtask[${i}]: depends_on references unknown id '${dep}'`);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
if (errors.length === 0 && validItems.length > 0) {
|
|
2335
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
2336
|
+
const adjList = /* @__PURE__ */ new Map();
|
|
2337
|
+
for (const id of validIds) {
|
|
2338
|
+
inDegree.set(id, 0);
|
|
2339
|
+
adjList.set(id, []);
|
|
2340
|
+
}
|
|
2341
|
+
for (const item of validItems) {
|
|
2342
|
+
const depends_on = item["depends_on"];
|
|
2343
|
+
if (!Array.isArray(depends_on)) continue;
|
|
2344
|
+
for (const dep of depends_on) {
|
|
2345
|
+
if (typeof dep !== "string" || !idSet.has(dep)) continue;
|
|
2346
|
+
adjList.get(dep)?.push(item["id"]);
|
|
2347
|
+
inDegree.set(item["id"], (inDegree.get(item["id"]) ?? 0) + 1);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
const queue = [];
|
|
2351
|
+
for (const [id, deg] of inDegree) {
|
|
2352
|
+
if (deg === 0) queue.push(id);
|
|
2353
|
+
}
|
|
2354
|
+
let processed = 0;
|
|
2355
|
+
while (queue.length > 0) {
|
|
2356
|
+
const current = queue.shift();
|
|
2357
|
+
processed++;
|
|
2358
|
+
for (const neighbor of adjList.get(current) ?? []) {
|
|
2359
|
+
const newDeg = (inDegree.get(neighbor) ?? 0) - 1;
|
|
2360
|
+
inDegree.set(neighbor, newDeg);
|
|
2361
|
+
if (newDeg === 0) queue.push(neighbor);
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
if (processed < validItems.length) {
|
|
2365
|
+
for (const [id, deg] of inDegree) {
|
|
2366
|
+
if (deg > 0) {
|
|
2367
|
+
errors.push(`circular dependency detected involving subtask id: ${id}`);
|
|
2368
|
+
break;
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
if (errors.length > 0) {
|
|
2374
|
+
return { valid: [], errors };
|
|
2375
|
+
}
|
|
2376
|
+
const normalized = validItems.map((item) => {
|
|
2377
|
+
const depends_on = Array.isArray(item["depends_on"]) ? item["depends_on"].filter((x) => typeof x === "string") : [];
|
|
2378
|
+
const params = typeof item["params"] === "object" && item["params"] !== null && !Array.isArray(item["params"]) ? item["params"] : {};
|
|
2379
|
+
const estimated_credits = typeof item["estimated_credits"] === "number" ? item["estimated_credits"] : 0;
|
|
2380
|
+
return {
|
|
2381
|
+
id: item["id"],
|
|
2382
|
+
description: item["description"],
|
|
2383
|
+
required_capability: item["required_capability"],
|
|
2384
|
+
params,
|
|
2385
|
+
depends_on,
|
|
2386
|
+
estimated_credits
|
|
2387
|
+
};
|
|
2388
|
+
});
|
|
2389
|
+
return { valid: normalized, errors: [] };
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
// src/conductor/task-decomposer.ts
|
|
2021
2393
|
var TEMPLATES = {
|
|
2022
2394
|
"video-production": {
|
|
2023
2395
|
keywords: ["video", "demo", "clip", "animation"],
|
|
@@ -2112,7 +2484,7 @@ function decompose(task, _availableCapabilities) {
|
|
|
2112
2484
|
for (const template of Object.values(TEMPLATES)) {
|
|
2113
2485
|
const matched = template.keywords.some((kw) => lower.includes(kw));
|
|
2114
2486
|
if (!matched) continue;
|
|
2115
|
-
const ids = template.steps.map(() =>
|
|
2487
|
+
const ids = template.steps.map(() => randomUUID7());
|
|
2116
2488
|
return template.steps.map((step, i) => ({
|
|
2117
2489
|
id: ids[i],
|
|
2118
2490
|
description: step.description,
|
|
@@ -2126,10 +2498,10 @@ function decompose(task, _availableCapabilities) {
|
|
|
2126
2498
|
}
|
|
2127
2499
|
|
|
2128
2500
|
// src/gateway/client.ts
|
|
2129
|
-
import { randomUUID as
|
|
2501
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
2130
2502
|
async function requestCapability(opts) {
|
|
2131
2503
|
const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
|
|
2132
|
-
const id =
|
|
2504
|
+
const id = randomUUID8();
|
|
2133
2505
|
const payload = {
|
|
2134
2506
|
jsonrpc: "2.0",
|
|
2135
2507
|
id,
|
|
@@ -2199,36 +2571,15 @@ async function requestViaRelay(relay, opts) {
|
|
|
2199
2571
|
}
|
|
2200
2572
|
|
|
2201
2573
|
// src/autonomy/tiers.ts
|
|
2202
|
-
import { randomUUID as
|
|
2574
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
2203
2575
|
|
|
2204
2576
|
// src/autonomy/pending-requests.ts
|
|
2205
|
-
import { randomUUID as
|
|
2577
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
2206
2578
|
|
|
2207
2579
|
// src/cli/peers.ts
|
|
2208
2580
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
2209
2581
|
import { join as join3 } from "path";
|
|
2210
2582
|
|
|
2211
|
-
// src/cli/config.ts
|
|
2212
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
2213
|
-
import { homedir } from "os";
|
|
2214
|
-
import { join as join2 } from "path";
|
|
2215
|
-
function getConfigDir() {
|
|
2216
|
-
return process.env["AGENTBNB_DIR"] ?? join2(homedir(), ".agentbnb");
|
|
2217
|
-
}
|
|
2218
|
-
function getConfigPath() {
|
|
2219
|
-
return join2(getConfigDir(), "config.json");
|
|
2220
|
-
}
|
|
2221
|
-
function loadConfig() {
|
|
2222
|
-
const configPath = getConfigPath();
|
|
2223
|
-
if (!existsSync2(configPath)) return null;
|
|
2224
|
-
try {
|
|
2225
|
-
const raw = readFileSync2(configPath, "utf-8");
|
|
2226
|
-
return JSON.parse(raw);
|
|
2227
|
-
} catch {
|
|
2228
|
-
return null;
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
2583
|
// src/cli/remote-registry.ts
|
|
2233
2584
|
var RegistryTimeoutError = class extends AgentBnBError {
|
|
2234
2585
|
constructor(url) {
|
|
@@ -2573,6 +2924,12 @@ function computeWaves(subtasks) {
|
|
|
2573
2924
|
async function orchestrate(opts) {
|
|
2574
2925
|
const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
|
|
2575
2926
|
const startTime = Date.now();
|
|
2927
|
+
const teamMemberMap = /* @__PURE__ */ new Map();
|
|
2928
|
+
if (opts.team) {
|
|
2929
|
+
for (const member of opts.team.matched) {
|
|
2930
|
+
teamMemberMap.set(member.subtask.id, member);
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2576
2933
|
if (subtasks.length === 0) {
|
|
2577
2934
|
return {
|
|
2578
2935
|
success: true,
|
|
@@ -2584,6 +2941,7 @@ async function orchestrate(opts) {
|
|
|
2584
2941
|
const results = /* @__PURE__ */ new Map();
|
|
2585
2942
|
const errors = [];
|
|
2586
2943
|
let totalCredits = 0;
|
|
2944
|
+
const traceContext = /* @__PURE__ */ new Map();
|
|
2587
2945
|
const waves = computeWaves(subtasks);
|
|
2588
2946
|
const subtaskMap = new Map(subtasks.map((s) => [s.id, s]));
|
|
2589
2947
|
for (const wave of waves) {
|
|
@@ -2620,7 +2978,11 @@ async function orchestrate(opts) {
|
|
|
2620
2978
|
subtask.params,
|
|
2621
2979
|
interpContext
|
|
2622
2980
|
);
|
|
2623
|
-
const
|
|
2981
|
+
const teamMember = teamMemberMap.get(taskId);
|
|
2982
|
+
const teamId = opts.team?.team_id ?? null;
|
|
2983
|
+
const taskCapabilityType = teamMember?.capability_type ?? null;
|
|
2984
|
+
const agentOwner = teamMember?.agent ?? m.selected_agent;
|
|
2985
|
+
const primary = resolveAgentUrl(agentOwner);
|
|
2624
2986
|
try {
|
|
2625
2987
|
let res;
|
|
2626
2988
|
if (primary.url.startsWith("relay://") && relayClient) {
|
|
@@ -2641,7 +3003,7 @@ async function orchestrate(opts) {
|
|
|
2641
3003
|
timeoutMs
|
|
2642
3004
|
});
|
|
2643
3005
|
}
|
|
2644
|
-
return { taskId, result: res, credits: m.credits };
|
|
3006
|
+
return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
2645
3007
|
} catch (primaryErr) {
|
|
2646
3008
|
if (m.alternatives.length > 0) {
|
|
2647
3009
|
const alt = m.alternatives[0];
|
|
@@ -2666,7 +3028,7 @@ async function orchestrate(opts) {
|
|
|
2666
3028
|
timeoutMs
|
|
2667
3029
|
});
|
|
2668
3030
|
}
|
|
2669
|
-
return { taskId, result: altRes, credits: alt.credits };
|
|
3031
|
+
return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
|
|
2670
3032
|
} catch (altErr) {
|
|
2671
3033
|
throw new Error(
|
|
2672
3034
|
`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)}`
|
|
@@ -2681,9 +3043,10 @@ async function orchestrate(opts) {
|
|
|
2681
3043
|
);
|
|
2682
3044
|
for (const settlement of waveResults) {
|
|
2683
3045
|
if (settlement.status === "fulfilled") {
|
|
2684
|
-
const { taskId, result, credits } = settlement.value;
|
|
3046
|
+
const { taskId, result, credits, team_id, capability_type } = settlement.value;
|
|
2685
3047
|
results.set(taskId, result);
|
|
2686
3048
|
totalCredits += credits;
|
|
3049
|
+
traceContext.set(taskId, { team_id: team_id ?? null, capability_type: capability_type ?? null });
|
|
2687
3050
|
} else {
|
|
2688
3051
|
errors.push(settlement.reason instanceof Error ? settlement.reason.message : String(settlement.reason));
|
|
2689
3052
|
}
|
|
@@ -2694,7 +3057,8 @@ async function orchestrate(opts) {
|
|
|
2694
3057
|
results,
|
|
2695
3058
|
total_credits: totalCredits,
|
|
2696
3059
|
latency_ms: Date.now() - startTime,
|
|
2697
|
-
errors: errors.length > 0 ? errors : void 0
|
|
3060
|
+
errors: errors.length > 0 ? errors : void 0,
|
|
3061
|
+
trace: traceContext.size > 0 ? traceContext : void 0
|
|
2698
3062
|
};
|
|
2699
3063
|
}
|
|
2700
3064
|
|
|
@@ -2743,6 +3107,96 @@ var BudgetManager = class {
|
|
|
2743
3107
|
}
|
|
2744
3108
|
};
|
|
2745
3109
|
|
|
3110
|
+
// src/conductor/team-formation.ts
|
|
3111
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
3112
|
+
function selectByStrategy(matches, strategy) {
|
|
3113
|
+
if (matches.length === 0) return void 0;
|
|
3114
|
+
if (strategy === "balanced") {
|
|
3115
|
+
return matches[0];
|
|
3116
|
+
}
|
|
3117
|
+
if (strategy === "quality_optimized") {
|
|
3118
|
+
return matches.reduce((best, m) => m.score > best.score ? m : best, matches[0]);
|
|
3119
|
+
}
|
|
3120
|
+
return matches.reduce((best, m) => {
|
|
3121
|
+
if (m.credits < best.credits) return m;
|
|
3122
|
+
if (m.credits === best.credits && m.score > best.score) return m;
|
|
3123
|
+
return best;
|
|
3124
|
+
}, matches[0]);
|
|
3125
|
+
}
|
|
3126
|
+
async function formTeam(opts) {
|
|
3127
|
+
const { subtasks, strategy, db, conductorOwner, registryUrl } = opts;
|
|
3128
|
+
const team_id = randomUUID11();
|
|
3129
|
+
if (subtasks.length === 0) {
|
|
3130
|
+
return { team_id, strategy, matched: [], unrouted: [] };
|
|
3131
|
+
}
|
|
3132
|
+
const matched = [];
|
|
3133
|
+
const unrouted = [];
|
|
3134
|
+
for (const subtask of subtasks) {
|
|
3135
|
+
const skillCards = getCardsBySkillCapability(db, subtask.required_capability).filter((c) => c.owner !== conductorOwner);
|
|
3136
|
+
if (skillCards.length > 0) {
|
|
3137
|
+
const candidates = skillCards.map((card) => {
|
|
3138
|
+
const skills = card.skills ?? [];
|
|
3139
|
+
const matchingSkill = skills.find(
|
|
3140
|
+
(s) => s.capability_type === subtask.required_capability || (s.capability_types ?? []).includes(subtask.required_capability)
|
|
3141
|
+
);
|
|
3142
|
+
return {
|
|
3143
|
+
subtask_id: subtask.id,
|
|
3144
|
+
selected_agent: card.owner,
|
|
3145
|
+
selected_skill: matchingSkill?.id ?? "",
|
|
3146
|
+
selected_card_id: card.id,
|
|
3147
|
+
score: 1,
|
|
3148
|
+
credits: matchingSkill?.pricing.credits_per_call ?? 0,
|
|
3149
|
+
alternatives: []
|
|
3150
|
+
};
|
|
3151
|
+
});
|
|
3152
|
+
const selected2 = selectByStrategy(candidates, strategy);
|
|
3153
|
+
matched.push({
|
|
3154
|
+
subtask,
|
|
3155
|
+
capability_type: subtask.required_capability,
|
|
3156
|
+
agent: selected2.selected_agent,
|
|
3157
|
+
skill: selected2.selected_skill,
|
|
3158
|
+
card_id: selected2.selected_card_id,
|
|
3159
|
+
credits: selected2.credits,
|
|
3160
|
+
score: selected2.score
|
|
3161
|
+
});
|
|
3162
|
+
continue;
|
|
3163
|
+
}
|
|
3164
|
+
const matchResults = await matchSubTasks({
|
|
3165
|
+
db,
|
|
3166
|
+
subtasks: [subtask],
|
|
3167
|
+
conductorOwner,
|
|
3168
|
+
registryUrl
|
|
3169
|
+
});
|
|
3170
|
+
const m = matchResults[0];
|
|
3171
|
+
if (!m || m.selected_agent === "") {
|
|
3172
|
+
unrouted.push(subtask);
|
|
3173
|
+
continue;
|
|
3174
|
+
}
|
|
3175
|
+
const allCandidates = [
|
|
3176
|
+
m,
|
|
3177
|
+
...m.alternatives.map((alt) => ({
|
|
3178
|
+
subtask_id: m.subtask_id,
|
|
3179
|
+
selected_agent: alt.agent,
|
|
3180
|
+
selected_skill: alt.skill,
|
|
3181
|
+
score: alt.score,
|
|
3182
|
+
credits: alt.credits,
|
|
3183
|
+
alternatives: []
|
|
3184
|
+
}))
|
|
3185
|
+
];
|
|
3186
|
+
const selected = selectByStrategy(allCandidates, strategy);
|
|
3187
|
+
matched.push({
|
|
3188
|
+
subtask,
|
|
3189
|
+
capability_type: subtask.required_capability,
|
|
3190
|
+
agent: selected.selected_agent,
|
|
3191
|
+
skill: selected.selected_skill,
|
|
3192
|
+
card_id: selected === m ? m.selected_card_id : void 0,
|
|
3193
|
+
credits: selected.credits,
|
|
3194
|
+
score: selected.score
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
3197
|
+
return { team_id, strategy, matched, unrouted };
|
|
3198
|
+
}
|
|
3199
|
+
|
|
2746
3200
|
// src/conductor/conductor-mode.ts
|
|
2747
3201
|
var ConductorMode = class {
|
|
2748
3202
|
db;
|
|
@@ -2781,7 +3235,48 @@ var ConductorMode = class {
|
|
|
2781
3235
|
error: 'Missing or empty "task" parameter'
|
|
2782
3236
|
};
|
|
2783
3237
|
}
|
|
2784
|
-
const
|
|
3238
|
+
const orchestrationDepth = typeof params.orchestration_depth === "number" ? params.orchestration_depth : 0;
|
|
3239
|
+
const decompositionDepth = typeof params.decomposition_depth === "number" ? params.decomposition_depth : 0;
|
|
3240
|
+
if (orchestrationDepth >= 2) {
|
|
3241
|
+
return {
|
|
3242
|
+
success: false,
|
|
3243
|
+
error: "orchestration_depth limit exceeded: max 1 nested orchestration"
|
|
3244
|
+
};
|
|
3245
|
+
}
|
|
3246
|
+
let subtasks = [];
|
|
3247
|
+
if (decompositionDepth === 0) {
|
|
3248
|
+
const allDecomposers = getCardsByCapabilityType(this.db, "task_decomposition");
|
|
3249
|
+
const externalDecomposers = allDecomposers.filter((c) => c.owner !== this.conductorOwner);
|
|
3250
|
+
if (externalDecomposers.length > 0) {
|
|
3251
|
+
const provider = externalDecomposers[0];
|
|
3252
|
+
try {
|
|
3253
|
+
const providerUrl = this.resolveAgentUrl(provider.owner);
|
|
3254
|
+
const response = await requestCapability({
|
|
3255
|
+
gatewayUrl: providerUrl.url,
|
|
3256
|
+
token: this.gatewayToken,
|
|
3257
|
+
cardId: provider.id,
|
|
3258
|
+
params: {
|
|
3259
|
+
task,
|
|
3260
|
+
decomposition_depth: decompositionDepth + 1,
|
|
3261
|
+
orchestration_depth: orchestrationDepth + 1
|
|
3262
|
+
},
|
|
3263
|
+
timeoutMs: 3e4
|
|
3264
|
+
});
|
|
3265
|
+
if (Array.isArray(response)) {
|
|
3266
|
+
const validation = validateAndNormalizeSubtasks(response, {
|
|
3267
|
+
max_credits: this.maxBudget
|
|
3268
|
+
});
|
|
3269
|
+
if (validation.errors.length === 0) {
|
|
3270
|
+
subtasks = validation.valid;
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
} catch {
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
if (subtasks.length === 0) {
|
|
3278
|
+
subtasks = decompose(task);
|
|
3279
|
+
}
|
|
2785
3280
|
if (subtasks.length === 0) {
|
|
2786
3281
|
return {
|
|
2787
3282
|
success: false,
|
|
@@ -2795,6 +3290,17 @@ var ConductorMode = class {
|
|
|
2795
3290
|
conductorOwner: this.conductorOwner
|
|
2796
3291
|
});
|
|
2797
3292
|
onProgress?.({ step: 2, total: 5, message: `Matched ${matchResults.length} sub-tasks to agents` });
|
|
3293
|
+
let team;
|
|
3294
|
+
if (conductorSkill === "orchestrate") {
|
|
3295
|
+
const strategy = typeof params.formation_strategy === "string" && ["cost_optimized", "quality_optimized", "balanced"].includes(params.formation_strategy) ? params.formation_strategy : "balanced";
|
|
3296
|
+
team = await formTeam({
|
|
3297
|
+
subtasks,
|
|
3298
|
+
strategy,
|
|
3299
|
+
db: this.db,
|
|
3300
|
+
conductorOwner: this.conductorOwner
|
|
3301
|
+
});
|
|
3302
|
+
onProgress?.({ step: 2, total: 5, message: `Formed team: ${team.matched.length} members, ${team.unrouted.length} unrouted` });
|
|
3303
|
+
}
|
|
2798
3304
|
const budgetManager = new BudgetManager(this.creditDb, this.conductorOwner);
|
|
2799
3305
|
const budgetController = new BudgetController(budgetManager, this.maxBudget);
|
|
2800
3306
|
const executionBudget = budgetController.calculateBudget(matchResults);
|
|
@@ -2811,7 +3317,9 @@ var ConductorMode = class {
|
|
|
2811
3317
|
result: {
|
|
2812
3318
|
subtasks,
|
|
2813
3319
|
matches: matchResults,
|
|
2814
|
-
budget: executionBudget
|
|
3320
|
+
budget: executionBudget,
|
|
3321
|
+
team
|
|
3322
|
+
// undefined when no role hints
|
|
2815
3323
|
}
|
|
2816
3324
|
};
|
|
2817
3325
|
}
|
|
@@ -2823,7 +3331,8 @@ var ConductorMode = class {
|
|
|
2823
3331
|
matches: matchMap,
|
|
2824
3332
|
gatewayToken: this.gatewayToken,
|
|
2825
3333
|
resolveAgentUrl: this.resolveAgentUrl,
|
|
2826
|
-
maxBudget: this.maxBudget
|
|
3334
|
+
maxBudget: this.maxBudget,
|
|
3335
|
+
team
|
|
2827
3336
|
});
|
|
2828
3337
|
onProgress?.({ step: 4, total: 5, message: "Pipeline execution complete" });
|
|
2829
3338
|
const resultObj = {};
|
|
@@ -2846,7 +3355,7 @@ var ConductorMode = class {
|
|
|
2846
3355
|
|
|
2847
3356
|
// src/credit/escrow-receipt.ts
|
|
2848
3357
|
import { z as z3 } from "zod";
|
|
2849
|
-
import { randomUUID as
|
|
3358
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
2850
3359
|
var EscrowReceiptSchema = z3.object({
|
|
2851
3360
|
requester_owner: z3.string().min(1),
|
|
2852
3361
|
requester_public_key: z3.string().min(1),
|
|
@@ -2866,7 +3375,7 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
2866
3375
|
card_id: opts.cardId,
|
|
2867
3376
|
...opts.skillId ? { skill_id: opts.skillId } : {},
|
|
2868
3377
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2869
|
-
nonce:
|
|
3378
|
+
nonce: randomUUID12()
|
|
2870
3379
|
};
|
|
2871
3380
|
const signature = signEscrowReceipt(receiptData, privateKey);
|
|
2872
3381
|
const receipt = {
|
|
@@ -3237,7 +3746,7 @@ var AgentBnBProvider = class {
|
|
|
3237
3746
|
|
|
3238
3747
|
// src/identity/guarantor.ts
|
|
3239
3748
|
import { z as z5 } from "zod";
|
|
3240
|
-
import { randomUUID as
|
|
3749
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
3241
3750
|
var MAX_AGENTS_PER_GUARANTOR = 10;
|
|
3242
3751
|
var GUARANTOR_CREDIT_POOL = 50;
|
|
3243
3752
|
var GuarantorRecordSchema = z5.object({
|
|
@@ -3276,7 +3785,7 @@ function registerGuarantor(db, githubLogin) {
|
|
|
3276
3785
|
);
|
|
3277
3786
|
}
|
|
3278
3787
|
const record = {
|
|
3279
|
-
id:
|
|
3788
|
+
id: randomUUID13(),
|
|
3280
3789
|
github_login: githubLogin,
|
|
3281
3790
|
agent_count: 0,
|
|
3282
3791
|
credit_pool: GUARANTOR_CREDIT_POOL,
|
|
@@ -3350,7 +3859,7 @@ function getAgentGuarantor(db, agentId) {
|
|
|
3350
3859
|
function initiateGithubAuth() {
|
|
3351
3860
|
return {
|
|
3352
3861
|
auth_url: "https://github.com/login/oauth/authorize?client_id=PLACEHOLDER&scope=read:user",
|
|
3353
|
-
state:
|
|
3862
|
+
state: randomUUID13()
|
|
3354
3863
|
};
|
|
3355
3864
|
}
|
|
3356
3865
|
|
|
@@ -3434,7 +3943,7 @@ var RelayMessageSchema = z6.discriminatedUnion("type", [
|
|
|
3434
3943
|
]);
|
|
3435
3944
|
|
|
3436
3945
|
// src/relay/websocket-relay.ts
|
|
3437
|
-
import { randomUUID as
|
|
3946
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
3438
3947
|
|
|
3439
3948
|
// src/relay/relay-credit.ts
|
|
3440
3949
|
function lookupCardPrice(registryDb, cardId, skillId) {
|
|
@@ -3492,10 +4001,10 @@ function releaseForRelay(creditDb, escrowId) {
|
|
|
3492
4001
|
}
|
|
3493
4002
|
|
|
3494
4003
|
// src/hub-agent/relay-bridge.ts
|
|
3495
|
-
import { randomUUID as
|
|
4004
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
3496
4005
|
|
|
3497
4006
|
// src/hub-agent/job-queue.ts
|
|
3498
|
-
import { randomUUID as
|
|
4007
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
3499
4008
|
function updateJobStatus(db, jobId, status, result) {
|
|
3500
4009
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3501
4010
|
if (result !== void 0) {
|
|
@@ -3616,7 +4125,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3616
4125
|
function logAgentJoined(owner, cardName, cardId) {
|
|
3617
4126
|
try {
|
|
3618
4127
|
insertRequestLog(db, {
|
|
3619
|
-
id:
|
|
4128
|
+
id: randomUUID16(),
|
|
3620
4129
|
card_id: cardId,
|
|
3621
4130
|
card_name: cardName,
|
|
3622
4131
|
requester: owner,
|
|
@@ -3964,7 +4473,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3964
4473
|
|
|
3965
4474
|
// src/relay/websocket-client.ts
|
|
3966
4475
|
import WebSocket from "ws";
|
|
3967
|
-
import { randomUUID as
|
|
4476
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
3968
4477
|
var RelayClient = class {
|
|
3969
4478
|
ws = null;
|
|
3970
4479
|
opts;
|
|
@@ -4061,7 +4570,7 @@ var RelayClient = class {
|
|
|
4061
4570
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.registered) {
|
|
4062
4571
|
throw new Error("Not connected to registry relay");
|
|
4063
4572
|
}
|
|
4064
|
-
const id =
|
|
4573
|
+
const id = randomUUID17();
|
|
4065
4574
|
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
4066
4575
|
return new Promise((resolve, reject) => {
|
|
4067
4576
|
const timeout = setTimeout(() => {
|
|
@@ -4265,12 +4774,12 @@ var RelayClient = class {
|
|
|
4265
4774
|
};
|
|
4266
4775
|
|
|
4267
4776
|
// src/onboarding/index.ts
|
|
4268
|
-
import { randomUUID as
|
|
4777
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
4269
4778
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
4270
4779
|
import { join as join5 } from "path";
|
|
4271
4780
|
|
|
4272
4781
|
// src/cli/onboarding.ts
|
|
4273
|
-
import { randomUUID as
|
|
4782
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
4274
4783
|
import { createConnection } from "net";
|
|
4275
4784
|
var KNOWN_API_KEYS = [
|
|
4276
4785
|
"OPENAI_API_KEY",
|
|
@@ -4412,7 +4921,7 @@ function capabilitiesToV2Card(capabilities, owner, agentName) {
|
|
|
4412
4921
|
}));
|
|
4413
4922
|
const card = {
|
|
4414
4923
|
spec_version: "2.0",
|
|
4415
|
-
id:
|
|
4924
|
+
id: randomUUID19(),
|
|
4416
4925
|
owner,
|
|
4417
4926
|
agent_name: agentName ?? owner,
|
|
4418
4927
|
skills,
|