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.
Files changed (48) hide show
  1. package/dist/{card-RSGDCHCV.js → card-REW7BSWW.js} +1 -1
  2. package/dist/{chunk-EPIWHNB2.js → chunk-2TLZ6G2B.js} +446 -373
  3. package/dist/{chunk-WGZ5AGOX.js → chunk-3CIMVISQ.js} +24 -1
  4. package/dist/{chunk-NH2FIERR.js → chunk-574W3HHE.js} +1 -1
  5. package/dist/{chunk-B5FTAGFN.js → chunk-7XHDSWRD.js} +75 -75
  6. package/dist/{chunk-NLAWT4DT.js → chunk-7YLFLC5C.js} +6 -6
  7. package/dist/chunk-BP3L2TET.js +148 -0
  8. package/dist/{chunk-EGUOAHCW.js → chunk-C2T4BMRW.js} +12 -12
  9. package/dist/{chunk-5KFI5X7B.js → chunk-F53QQIM2.js} +1 -1
  10. package/dist/chunk-JR6TJDIF.js +425 -0
  11. package/dist/{chunk-DFBX3BBD.js → chunk-KA2VIEGM.js} +211 -16
  12. package/dist/chunk-NQTE577Q.js +159 -0
  13. package/dist/{chunk-WTXRY7R2.js → chunk-NYV3NE5Z.js} +157 -9
  14. package/dist/{chunk-UKT6H7YT.js → chunk-OZXCRLP3.js} +1 -1
  15. package/dist/{chunk-QITOPASZ.js → chunk-PSQHUZ7X.js} +1 -1
  16. package/dist/{chunk-EANI2N2V.js → chunk-RVYQSC6L.js} +2 -99
  17. package/dist/{chunk-MLS6IGGG.js → chunk-TQDV254A.js} +1 -1
  18. package/dist/{chunk-QQFBFV4V.js → chunk-TR6UZDNX.js} +57 -18
  19. package/dist/{chunk-ZX5623ER.js → chunk-VMH2YS2I.js} +1 -1
  20. package/dist/{chunk-XND2DWTZ.js → chunk-VPQ44XKE.js} +2 -2
  21. package/dist/{chunk-CSATDXZC.js → chunk-Y7T6IMM3.js} +1 -1
  22. package/dist/{chunk-FLY3WIQR.js → chunk-YRRVFTDR.js} +3 -3
  23. package/dist/cli/index.js +261 -125
  24. package/dist/{client-T5MTY3CS.js → client-HRYRJKSA.js} +3 -3
  25. package/dist/{conduct-WU3VEXB6.js → conduct-LF6FYPLD.js} +11 -11
  26. package/dist/conduct-QAFZIEY6.js +21 -0
  27. package/dist/{conductor-mode-ZMTFZGJP.js → conductor-mode-NUDQLZFM.js} +309 -13
  28. package/dist/conductor-mode-YQ6QSPPT.js +275 -0
  29. package/dist/{execute-4D4ITQCL.js → execute-ITHIYYOX.js} +4 -3
  30. package/dist/execute-PNJFABVJ.js +14 -0
  31. package/dist/index.d.ts +555 -0
  32. package/dist/index.js +592 -83
  33. package/dist/{process-guard-CC7CNRQJ.js → process-guard-QCCBGILS.js} +1 -1
  34. package/dist/publish-capability-TS6CNR5G.js +12 -0
  35. package/dist/{request-VOXBFUOG.js → request-P6QCTCCG.js} +14 -14
  36. package/dist/{serve-skill-IH7UAJNR.js → serve-skill-EZOL7UYN.js} +10 -9
  37. package/dist/{server-JVQW2TID.js → server-3G6ZTASA.js} +16 -16
  38. package/dist/{service-coordinator-EYRDTHL5.js → service-coordinator-CRSE4GWC.js} +174 -242
  39. package/dist/skill-config-4W5W5O6T.js +22 -0
  40. package/dist/skills/agentbnb/bootstrap.js +227 -67
  41. package/package.json +1 -1
  42. package/skills/agentbnb/SKILL.md +35 -0
  43. package/skills/agentbnb/bootstrap.ts +126 -8
  44. package/skills/agentbnb/install.sh +49 -9
  45. package/dist/chunk-CRFCWD6V.js +0 -366
  46. package/dist/conduct-6LKIJJKQ.js +0 -21
  47. package/dist/conductor-mode-Q4IIDY5E.js +0 -123
  48. 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 = skills.flatMap((s) => {
513
- const meta = s["metadata"];
514
- return meta?.["tags"] ?? [];
515
- }).join(" ");
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
- const result = await executeCapabilityRequest({
1200
- registryDb,
1201
- creditDb,
1202
- cardId,
1203
- skillId,
1204
- params,
1205
- requester,
1206
- escrowReceipt: receipt,
1207
- skillExecutor,
1208
- handlerUrl,
1209
- timeoutMs
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 randomUUID6 } from "crypto";
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(() => randomUUID6());
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 randomUUID7 } from "crypto";
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 = randomUUID7();
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 randomUUID8 } from "crypto";
2574
+ import { randomUUID as randomUUID9 } from "crypto";
2203
2575
 
2204
2576
  // src/autonomy/pending-requests.ts
2205
- import { randomUUID as randomUUID9 } from "crypto";
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 primary = resolveAgentUrl(m.selected_agent);
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 subtasks = decompose(task);
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 randomUUID10 } from "crypto";
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: randomUUID10()
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 randomUUID11 } from "crypto";
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: randomUUID11(),
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: randomUUID11()
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 randomUUID14 } from "crypto";
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 randomUUID13 } from "crypto";
4004
+ import { randomUUID as randomUUID15 } from "crypto";
3496
4005
 
3497
4006
  // src/hub-agent/job-queue.ts
3498
- import { randomUUID as randomUUID12 } from "crypto";
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: randomUUID14(),
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 randomUUID15 } from "crypto";
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 = randomUUID15();
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 randomUUID17 } from "crypto";
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 randomUUID16 } from "crypto";
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: randomUUID17(),
4924
+ id: randomUUID19(),
4416
4925
  owner,
4417
4926
  agent_name: agentName ?? owner,
4418
4927
  skills,