agentbnb 8.2.0 → 8.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{chunk-TBJ3FZKZ.js → chunk-7Q2XUXSA.js} +1 -1
  2. package/dist/{chunk-LJM7FHPM.js → chunk-BZOJ7HBT.js} +33 -1
  3. package/dist/{chunk-FTZTEHYG.js → chunk-DEWY7OQK.js} +135 -8
  4. package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
  5. package/dist/chunk-EZVOG7QS.js +161 -0
  6. package/dist/{chunk-E2OKP5CY.js → chunk-GJETGML6.js} +181 -83
  7. package/dist/{chunk-YHY7OG6S.js → chunk-GWMMYVLL.js} +4 -4
  8. package/dist/{chunk-D6RKW2XG.js → chunk-JLNHMNES.js} +16 -3
  9. package/dist/{chunk-5AAFG2V2.js → chunk-KBQNTUTN.js} +239 -24
  10. package/dist/{chunk-C537SFHV.js → chunk-LOUEJI6X.js} +4 -4
  11. package/dist/{chunk-ALX4WS3A.js → chunk-NP55V7RQ.js} +1 -1
  12. package/dist/{chunk-X32NE6V4.js → chunk-RBXTWWUH.js} +1 -1
  13. package/dist/{chunk-O2OYBAVR.js → chunk-SRBVKO2V.js} +9 -0
  14. package/dist/{chunk-7EF3HYVZ.js → chunk-STJLWMXH.js} +48 -4
  15. package/dist/{chunk-5GME4KJZ.js → chunk-UYCD3JBZ.js} +3 -3
  16. package/dist/{chunk-P4LOYSLA.js → chunk-WKWJWKX7.js} +286 -81
  17. package/dist/cli/index.js +35 -57
  18. package/dist/{client-HKV3QWZ3.js → client-66TFS7RS.js} +4 -2
  19. package/dist/{conduct-W6XF6DJW.js → conduct-A6COHLHY.js} +8 -8
  20. package/dist/{conduct-YB64OHI6.js → conduct-IUVAXUAV.js} +8 -8
  21. package/dist/{conductor-mode-TFCVCQHU.js → conductor-mode-D5TFQW5L.js} +2 -2
  22. package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-L2MB44BW.js} +7 -7
  23. package/dist/{execute-AYQWORVH.js → execute-5AWLARB5.js} +5 -5
  24. package/dist/{execute-EPE6MZLT.js → execute-WOS457HW.js} +2 -2
  25. package/dist/index.js +438 -92
  26. package/dist/{publish-capability-AH2HDW54.js → publish-capability-JJCBBMSX.js} +2 -2
  27. package/dist/{request-HCCXSKAY.js → request-6YQLA7K3.js} +13 -8
  28. package/dist/{serve-skill-SZAQT5T5.js → serve-skill-X7TZSILV.js} +5 -5
  29. package/dist/{server-LMY2A3GT.js → server-5TSP4DBX.js} +10 -12
  30. package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-WTUSMPY6.js} +69 -46
  31. package/dist/skills/agentbnb/bootstrap.js +459 -189
  32. package/package.json +13 -17
  33. package/skills/agentbnb/bootstrap.test.ts +8 -6
  34. package/skills/agentbnb/bootstrap.ts +21 -13
  35. package/skills/agentbnb/install.sh +0 -0
  36. package/dist/chunk-64AK4FJM.js +0 -84
  37. package/dist/chunk-OH7BP5NP.js +0 -96
  38. package/dist/index.d.ts +0 -5069
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  settleProviderEarning
3
- } from "./chunk-X32NE6V4.js";
3
+ } from "./chunk-RBXTWWUH.js";
4
4
  import {
5
5
  getBalance,
6
6
  holdEscrow,
7
7
  releaseEscrow,
8
8
  settleEscrow
9
- } from "./chunk-D6RKW2XG.js";
9
+ } from "./chunk-JLNHMNES.js";
10
10
  import {
11
11
  verifyEscrowReceipt
12
- } from "./chunk-CUONY5TO.js";
12
+ } from "./chunk-EJKW57ZV.js";
13
13
  import {
14
14
  loadConfig
15
15
  } from "./chunk-75OC6E4F.js";
@@ -17,7 +17,7 @@ import {
17
17
  getCard,
18
18
  insertRequestLog,
19
19
  updateReputation
20
- } from "./chunk-O2OYBAVR.js";
20
+ } from "./chunk-SRBVKO2V.js";
21
21
  import {
22
22
  AgentBnBError
23
23
  } from "./chunk-WVY2W7AA.js";
@@ -10,7 +10,7 @@ import {
10
10
  settleEscrow,
11
11
  updateReputation,
12
12
  verifyEscrowReceipt
13
- } from "./chunk-7EF3HYVZ.js";
13
+ } from "./chunk-STJLWMXH.js";
14
14
  import {
15
15
  loadConfig
16
16
  } from "./chunk-IVOYM3WG.js";
@@ -3,7 +3,7 @@ import {
3
3
  confirmEscrowDebit,
4
4
  recordEarning,
5
5
  releaseEscrow
6
- } from "./chunk-D6RKW2XG.js";
6
+ } from "./chunk-JLNHMNES.js";
7
7
 
8
8
  // src/credit/settlement.ts
9
9
  function settleProviderEarning(providerDb, providerOwner, receipt) {
@@ -498,6 +498,15 @@ function openDatabase(path = ":memory:") {
498
498
  tags,
499
499
  content=""
500
500
  );
501
+
502
+ -- Expression index for capability_type lookups (used by Conductor routing).
503
+ -- Turns json_extract full-table-scan into O(log n) B-tree lookup.
504
+ CREATE INDEX IF NOT EXISTS idx_cards_capability_type
505
+ ON capability_cards(json_extract(data, '$.capability_type'));
506
+
507
+ -- Owner index for listCards(owner) and other owner-scoped queries.
508
+ CREATE INDEX IF NOT EXISTS idx_cards_owner
509
+ ON capability_cards(owner);
501
510
  `);
502
511
  createRequestLogTable(db);
503
512
  initFeedbackTable(db);
@@ -502,6 +502,15 @@ function openDatabase(path = ":memory:") {
502
502
  tags,
503
503
  content=""
504
504
  );
505
+
506
+ -- Expression index for capability_type lookups (used by Conductor routing).
507
+ -- Turns json_extract full-table-scan into O(log n) B-tree lookup.
508
+ CREATE INDEX IF NOT EXISTS idx_cards_capability_type
509
+ ON capability_cards(json_extract(data, '$.capability_type'));
510
+
511
+ -- Owner index for listCards(owner) and other owner-scoped queries.
512
+ CREATE INDEX IF NOT EXISTS idx_cards_owner
513
+ ON capability_cards(owner);
505
514
  `);
506
515
  createRequestLogTable(db);
507
516
  initFeedbackTable(db);
@@ -759,6 +768,9 @@ var AGENTS_SCHEMA = `
759
768
  function ensureAgentsTable(db) {
760
769
  db.exec(AGENTS_SCHEMA);
761
770
  }
771
+ function lookupAgent(db, agentId) {
772
+ return db.prepare("SELECT * FROM agents WHERE agent_id = ?").get(agentId) ?? null;
773
+ }
762
774
 
763
775
  // src/credit/ledger.ts
764
776
  var CREDIT_SCHEMA = `
@@ -839,10 +851,23 @@ function getBalance(db, owner) {
839
851
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
840
852
  return row?.balance ?? 0;
841
853
  }
842
- function getTransactions(db, owner, limit = 100) {
854
+ function getTransactions(db, owner, opts = 100) {
855
+ const page = typeof opts === "number" ? { limit: opts } : opts;
856
+ const limit = page.limit ?? 100;
857
+ const conditions = ["owner = ?"];
858
+ const params = [owner];
859
+ if (page.before) {
860
+ conditions.push("created_at < ?");
861
+ params.push(page.before);
862
+ }
863
+ if (page.after) {
864
+ conditions.push("created_at > ?");
865
+ params.push(page.after);
866
+ }
867
+ params.push(limit);
843
868
  return db.prepare(
844
- "SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE owner = ? ORDER BY created_at DESC LIMIT ?"
845
- ).all(owner, limit);
869
+ `SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
870
+ ).all(...params);
846
871
  }
847
872
  function registerProvider(db, owner) {
848
873
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1100,7 +1125,25 @@ function loadKeyPair(configDir) {
1100
1125
  };
1101
1126
  }
1102
1127
  function canonicalJson(data) {
1103
- return JSON.stringify(data, Object.keys(data).sort());
1128
+ return JSON.stringify(sortForCanonicalJson(data));
1129
+ }
1130
+ function sortForCanonicalJson(value) {
1131
+ if (Array.isArray(value)) {
1132
+ return value.map((item) => sortForCanonicalJson(item));
1133
+ }
1134
+ if (value !== null && typeof value === "object") {
1135
+ const proto = Object.getPrototypeOf(value);
1136
+ if (proto === Object.prototype || proto === null) {
1137
+ const input = value;
1138
+ const output = {};
1139
+ const sortedKeys = Object.keys(input).sort();
1140
+ for (const key of sortedKeys) {
1141
+ output[key] = sortForCanonicalJson(input[key]);
1142
+ }
1143
+ return output;
1144
+ }
1145
+ }
1146
+ return value;
1104
1147
  }
1105
1148
  function signEscrowReceipt(data, privateKey) {
1106
1149
  const message = Buffer.from(canonicalJson(data), "utf-8");
@@ -1140,6 +1183,7 @@ export {
1140
1183
  listCards,
1141
1184
  getCardsByCapabilityType,
1142
1185
  getCardsBySkillCapability,
1186
+ lookupAgent,
1143
1187
  openCreditDb,
1144
1188
  bootstrapAgent,
1145
1189
  getBalance,
@@ -8,16 +8,16 @@ import {
8
8
  } from "./chunk-GKVTD4EZ.js";
9
9
  import {
10
10
  searchCards
11
- } from "./chunk-LJM7FHPM.js";
11
+ } from "./chunk-BZOJ7HBT.js";
12
12
  import {
13
13
  getBalance,
14
14
  holdEscrow,
15
15
  releaseEscrow,
16
16
  settleEscrow
17
- } from "./chunk-D6RKW2XG.js";
17
+ } from "./chunk-JLNHMNES.js";
18
18
  import {
19
19
  requestCapability
20
- } from "./chunk-64AK4FJM.js";
20
+ } from "./chunk-EZVOG7QS.js";
21
21
  import {
22
22
  findPeer
23
23
  } from "./chunk-5AH3CMOX.js";
@@ -8,7 +8,7 @@ import {
8
8
  releaseEscrow,
9
9
  settleEscrow,
10
10
  signEscrowReceipt
11
- } from "./chunk-7EF3HYVZ.js";
11
+ } from "./chunk-STJLWMXH.js";
12
12
  import {
13
13
  AgentBnBError
14
14
  } from "./chunk-WVY2W7AA.js";
@@ -258,6 +258,13 @@ function decompose(task, _availableCapabilities) {
258
258
 
259
259
  // src/gateway/client.ts
260
260
  import { randomUUID as randomUUID2 } from "crypto";
261
+ import { Agent } from "undici";
262
+ var gatewayAgent = new Agent({
263
+ keepAliveTimeout: 3e4,
264
+ keepAliveMaxTimeout: 6e4,
265
+ connections: 10,
266
+ pipelining: 1
267
+ });
261
268
  async function requestCapability(opts) {
262
269
  const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
263
270
  const id = randomUUID2();
@@ -288,7 +295,9 @@ async function requestCapability(opts) {
288
295
  method: "POST",
289
296
  headers,
290
297
  body: JSON.stringify(payload),
291
- signal: controller.signal
298
+ signal: controller.signal,
299
+ // undici dispatcher for connection pooling (Node.js 20+)
300
+ dispatcher: gatewayAgent
292
301
  });
293
302
  } catch (err) {
294
303
  clearTimeout(timer);
@@ -306,6 +315,73 @@ async function requestCapability(opts) {
306
315
  }
307
316
  return body.result;
308
317
  }
318
+ async function requestCapabilityBatch(gatewayUrl, token, items, opts = {}) {
319
+ if (items.length === 0) return /* @__PURE__ */ new Map();
320
+ if (items.length === 1) {
321
+ const item = items[0];
322
+ const result = await requestCapability({
323
+ gatewayUrl,
324
+ token,
325
+ cardId: item.cardId,
326
+ params: item.params,
327
+ escrowReceipt: item.escrowReceipt,
328
+ timeoutMs: opts.timeoutMs,
329
+ identity: opts.identity
330
+ });
331
+ return /* @__PURE__ */ new Map([[item.id, result]]);
332
+ }
333
+ const { timeoutMs = 3e5, identity } = opts;
334
+ const batchPayload = items.map((item) => ({
335
+ jsonrpc: "2.0",
336
+ id: item.id,
337
+ method: "capability.execute",
338
+ params: {
339
+ card_id: item.cardId,
340
+ ...item.params,
341
+ ...item.escrowReceipt ? { escrow_receipt: item.escrowReceipt } : {}
342
+ }
343
+ }));
344
+ const headers = { "Content-Type": "application/json" };
345
+ if (identity) {
346
+ const signature = signEscrowReceipt(batchPayload, identity.privateKey);
347
+ headers["X-Agent-Id"] = identity.agentId;
348
+ headers["X-Agent-Public-Key"] = identity.publicKey;
349
+ headers["X-Agent-Signature"] = signature;
350
+ } else if (token) {
351
+ headers["Authorization"] = `Bearer ${token}`;
352
+ }
353
+ const controller = new AbortController();
354
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
355
+ let response;
356
+ try {
357
+ response = await fetch(`${gatewayUrl}/rpc`, {
358
+ method: "POST",
359
+ headers,
360
+ body: JSON.stringify(batchPayload),
361
+ signal: controller.signal,
362
+ dispatcher: gatewayAgent
363
+ });
364
+ } catch (err) {
365
+ clearTimeout(timer);
366
+ const isTimeout = err instanceof Error && err.name === "AbortError";
367
+ throw new AgentBnBError(
368
+ isTimeout ? "Batch request timed out" : `Network error: ${String(err)}`,
369
+ isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
370
+ );
371
+ } finally {
372
+ clearTimeout(timer);
373
+ }
374
+ const body = await response.json();
375
+ const results = /* @__PURE__ */ new Map();
376
+ for (const resp of body) {
377
+ if (resp.error) {
378
+ results.set(resp.id, new AgentBnBError(resp.error.message, `RPC_ERROR_${resp.error.code}`));
379
+ } else {
380
+ results.set(resp.id, resp.result);
381
+ }
382
+ }
383
+ return results;
384
+ }
309
385
  async function requestViaRelay(relay, opts) {
310
386
  try {
311
387
  return await relay.request({
@@ -376,7 +452,37 @@ function getReputationScore(db, agentId) {
376
452
  }
377
453
 
378
454
  // src/registry/matcher.ts
455
+ var CACHE_MAX_ENTRIES = 100;
456
+ var CACHE_TTL_MS = 3e4;
457
+ var dbCaches = /* @__PURE__ */ new WeakMap();
458
+ function getDbCache(db) {
459
+ let cache = dbCaches.get(db);
460
+ if (!cache) {
461
+ cache = /* @__PURE__ */ new Map();
462
+ dbCaches.set(db, cache);
463
+ }
464
+ return cache;
465
+ }
466
+ function cacheKey(query, filters) {
467
+ return `${query}|${filters.level ?? ""}|${filters.online ?? ""}|${(filters.apis_used ?? []).join(",")}|${filters.min_reputation ?? ""}`;
468
+ }
469
+ function evictCache(cache) {
470
+ const now = Date.now();
471
+ for (const [key, entry] of cache) {
472
+ if (entry.expiresAt <= now) cache.delete(key);
473
+ }
474
+ while (cache.size > CACHE_MAX_ENTRIES) {
475
+ const firstKey = cache.keys().next().value;
476
+ cache.delete(firstKey);
477
+ }
478
+ }
379
479
  function searchCards(db, query, filters = {}) {
480
+ const cache = getDbCache(db);
481
+ const key = cacheKey(query, filters);
482
+ const cached = cache.get(key);
483
+ if (cached && cached.expiresAt > Date.now()) {
484
+ return cached.results;
485
+ }
380
486
  const words = query.trim().split(/\s+/).map((w) => w.replace(/["*^{}():]/g, "")).filter((w) => w.length > 0);
381
487
  if (words.length === 0) return [];
382
488
  const ftsQuery = words.map((w) => `"${w}"`).join(" OR ");
@@ -414,6 +520,8 @@ function searchCards(db, query, filters = {}) {
414
520
  if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
415
521
  filtered = applyReputationFilter(db, filtered, filters.min_reputation);
416
522
  }
523
+ evictCache(cache);
524
+ cache.set(key, { results: filtered, expiresAt: Date.now() + CACHE_TTL_MS });
417
525
  return filtered;
418
526
  }
419
527
  function filterCards(db, filters) {
@@ -1087,6 +1195,65 @@ function computeWaves(subtasks) {
1087
1195
  }
1088
1196
  return waves;
1089
1197
  }
1198
+ async function executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl) {
1199
+ const { taskId, match: m, interpolatedParams, primary, teamId, capabilityType } = pt;
1200
+ try {
1201
+ let res;
1202
+ if (primary.url.startsWith("relay://") && relayClient) {
1203
+ const targetOwner = primary.url.replace("relay://", "");
1204
+ res = await relayClient.request({
1205
+ targetOwner,
1206
+ cardId: primary.cardId,
1207
+ params: interpolatedParams,
1208
+ requester: requesterOwner,
1209
+ timeoutMs
1210
+ });
1211
+ } else {
1212
+ res = await requestCapability({
1213
+ gatewayUrl: primary.url,
1214
+ token: gatewayToken,
1215
+ cardId: primary.cardId,
1216
+ params: { ...interpolatedParams, requester: requesterOwner },
1217
+ timeoutMs
1218
+ });
1219
+ }
1220
+ return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: capabilityType };
1221
+ } catch (primaryErr) {
1222
+ if (m.alternatives.length > 0) {
1223
+ const alt = m.alternatives[0];
1224
+ const altResolved = resolveAgentUrl ? resolveAgentUrl(alt.agent) : { url: `http://${alt.agent}:7700`, cardId: `card-${alt.agent}` };
1225
+ try {
1226
+ let altRes;
1227
+ if (altResolved.url.startsWith("relay://") && relayClient) {
1228
+ const targetOwner = altResolved.url.replace("relay://", "");
1229
+ altRes = await relayClient.request({
1230
+ targetOwner,
1231
+ cardId: altResolved.cardId,
1232
+ params: interpolatedParams,
1233
+ requester: requesterOwner,
1234
+ timeoutMs
1235
+ });
1236
+ } else {
1237
+ altRes = await requestCapability({
1238
+ gatewayUrl: altResolved.url,
1239
+ token: gatewayToken,
1240
+ cardId: altResolved.cardId,
1241
+ params: { ...interpolatedParams, requester: requesterOwner },
1242
+ timeoutMs
1243
+ });
1244
+ }
1245
+ return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: capabilityType };
1246
+ } catch (altErr) {
1247
+ throw new Error(
1248
+ `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)}`
1249
+ );
1250
+ }
1251
+ }
1252
+ throw new Error(
1253
+ `Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
1254
+ );
1255
+ }
1256
+ }
1090
1257
  async function orchestrate(opts) {
1091
1258
  const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
1092
1259
  const startTime = Date.now();
@@ -1124,89 +1291,127 @@ async function orchestrate(opts) {
1124
1291
  }
1125
1292
  executableIds.push(taskId);
1126
1293
  }
1127
- const waveResults = await Promise.allSettled(
1128
- executableIds.map(async (taskId) => {
1129
- const subtask = subtaskMap.get(taskId);
1130
- const m = matches.get(taskId);
1131
- if (!m) {
1132
- throw new Error(`No match found for subtask ${taskId}`);
1133
- }
1134
- const stepsContext = {};
1135
- for (const [id, val] of results) {
1136
- stepsContext[id] = val;
1137
- }
1138
- const interpContext = { steps: stepsContext, prev: void 0 };
1139
- if (subtask.depends_on.length > 0) {
1140
- const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
1141
- interpContext.prev = results.get(lastDep);
1142
- }
1143
- const interpolatedParams = interpolateObject(
1144
- subtask.params,
1145
- interpContext
1146
- );
1147
- const teamMember = teamMemberMap.get(taskId);
1148
- const teamId = opts.team?.team_id ?? null;
1149
- const taskCapabilityType = teamMember?.capability_type ?? null;
1150
- const agentOwner = teamMember?.agent ?? m.selected_agent;
1151
- const primary = resolveAgentUrl(agentOwner);
1152
- try {
1153
- let res;
1154
- if (primary.url.startsWith("relay://") && relayClient) {
1155
- const targetOwner = primary.url.replace("relay://", "");
1156
- res = await relayClient.request({
1157
- targetOwner,
1158
- cardId: primary.cardId,
1159
- params: interpolatedParams,
1160
- requester: requesterOwner,
1161
- timeoutMs
1162
- });
1163
- } else {
1164
- res = await requestCapability({
1165
- gatewayUrl: primary.url,
1166
- token: gatewayToken,
1167
- cardId: primary.cardId,
1168
- params: { ...interpolatedParams, requester: requesterOwner },
1169
- timeoutMs
1170
- });
1171
- }
1172
- return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: taskCapabilityType };
1173
- } catch (primaryErr) {
1174
- if (m.alternatives.length > 0) {
1175
- const alt = m.alternatives[0];
1176
- const altAgent = resolveAgentUrl(alt.agent);
1294
+ const preparedTasks = [];
1295
+ for (const taskId of executableIds) {
1296
+ const subtask = subtaskMap.get(taskId);
1297
+ const m = matches.get(taskId);
1298
+ if (!m) {
1299
+ errors.push(`No match found for subtask ${taskId}`);
1300
+ continue;
1301
+ }
1302
+ const stepsContext = {};
1303
+ for (const [id, val] of results) stepsContext[id] = val;
1304
+ const interpContext = { steps: stepsContext, prev: void 0 };
1305
+ if (subtask.depends_on.length > 0) {
1306
+ const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
1307
+ interpContext.prev = results.get(lastDep);
1308
+ }
1309
+ const interpolatedParams = interpolateObject(
1310
+ subtask.params,
1311
+ interpContext
1312
+ );
1313
+ const teamMember = teamMemberMap.get(taskId);
1314
+ const agentOwner = teamMember?.agent ?? m.selected_agent;
1315
+ const primary = resolveAgentUrl(agentOwner);
1316
+ preparedTasks.push({
1317
+ taskId,
1318
+ subtask,
1319
+ match: m,
1320
+ interpolatedParams,
1321
+ agentOwner,
1322
+ primary,
1323
+ teamId: opts.team?.team_id ?? null,
1324
+ capabilityType: teamMember?.capability_type ?? null
1325
+ });
1326
+ }
1327
+ const httpGroups = /* @__PURE__ */ new Map();
1328
+ const relayTasks = [];
1329
+ for (const pt of preparedTasks) {
1330
+ if (pt.primary.url.startsWith("relay://") && relayClient) {
1331
+ relayTasks.push(pt);
1332
+ } else {
1333
+ const group = httpGroups.get(pt.primary.url) ?? [];
1334
+ group.push(pt);
1335
+ httpGroups.set(pt.primary.url, group);
1336
+ }
1337
+ }
1338
+ const batchPromises = [];
1339
+ for (const [gatewayUrl, group] of httpGroups) {
1340
+ if (group.length >= 2) {
1341
+ batchPromises.push(
1342
+ (async () => {
1343
+ const items = group.map((pt) => ({
1344
+ id: pt.taskId,
1345
+ cardId: pt.primary.cardId,
1346
+ params: { ...pt.interpolatedParams, requester: requesterOwner },
1347
+ _pt: pt
1348
+ }));
1177
1349
  try {
1178
- let altRes;
1179
- if (altAgent.url.startsWith("relay://") && relayClient) {
1180
- const targetOwner = altAgent.url.replace("relay://", "");
1181
- altRes = await relayClient.request({
1182
- targetOwner,
1183
- cardId: altAgent.cardId,
1184
- params: interpolatedParams,
1185
- requester: requesterOwner,
1186
- timeoutMs
1187
- });
1188
- } else {
1189
- altRes = await requestCapability({
1190
- gatewayUrl: altAgent.url,
1191
- token: gatewayToken,
1192
- cardId: altAgent.cardId,
1193
- params: { ...interpolatedParams, requester: requesterOwner },
1194
- timeoutMs
1195
- });
1196
- }
1197
- return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
1198
- } catch (altErr) {
1199
- throw new Error(
1200
- `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)}`
1350
+ const batchResults = await requestCapabilityBatch(
1351
+ gatewayUrl,
1352
+ gatewayToken,
1353
+ items.map(({ _pt, ...item }) => item),
1354
+ { timeoutMs }
1201
1355
  );
1356
+ return items.map((item) => {
1357
+ const res = batchResults.get(item.id);
1358
+ if (res instanceof Error) {
1359
+ return {
1360
+ status: "rejected",
1361
+ reason: new Error(`Task ${item.id}: ${res.message}`)
1362
+ };
1363
+ }
1364
+ return {
1365
+ status: "fulfilled",
1366
+ value: {
1367
+ taskId: item.id,
1368
+ result: res,
1369
+ credits: item._pt.match.credits,
1370
+ team_id: item._pt.teamId,
1371
+ capability_type: item._pt.capabilityType
1372
+ }
1373
+ };
1374
+ });
1375
+ } catch (batchErr) {
1376
+ return Promise.all(group.map(async (pt) => {
1377
+ try {
1378
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
1379
+ return { status: "fulfilled", value: res };
1380
+ } catch (err) {
1381
+ return { status: "rejected", reason: err };
1382
+ }
1383
+ }));
1202
1384
  }
1385
+ })()
1386
+ );
1387
+ } else {
1388
+ const pt = group[0];
1389
+ batchPromises.push(
1390
+ (async () => {
1391
+ try {
1392
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
1393
+ return [{ status: "fulfilled", value: res }];
1394
+ } catch (err) {
1395
+ return [{ status: "rejected", reason: err }];
1396
+ }
1397
+ })()
1398
+ );
1399
+ }
1400
+ }
1401
+ for (const pt of relayTasks) {
1402
+ batchPromises.push(
1403
+ (async () => {
1404
+ try {
1405
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
1406
+ return [{ status: "fulfilled", value: res }];
1407
+ } catch (err) {
1408
+ return [{ status: "rejected", reason: err }];
1203
1409
  }
1204
- throw new Error(
1205
- `Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
1206
- );
1207
- }
1208
- })
1209
- );
1410
+ })()
1411
+ );
1412
+ }
1413
+ const allBatchResults = await Promise.all(batchPromises);
1414
+ const waveResults = allBatchResults.flat();
1210
1415
  for (const settlement of waveResults) {
1211
1416
  if (settlement.status === "fulfilled") {
1212
1417
  const { taskId, result, credits, team_id, capability_type } = settlement.value;