agentbnb 8.2.1 → 8.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/{chunk-7Q2XUXSA.js → chunk-4IPJJRTP.js} +1 -1
  2. package/dist/{chunk-EZVOG7QS.js → chunk-CKOOVZOI.js} +15 -18
  3. package/dist/chunk-CQFBNTGT.js +145 -0
  4. package/dist/{chunk-WKWJWKX7.js → chunk-DYQOFGGI.js} +155 -445
  5. package/dist/{chunk-NP55V7RQ.js → chunk-EG6RS4JC.js} +70 -46
  6. package/dist/{chunk-KBQNTUTN.js → chunk-LKLKYXLV.js} +1 -1
  7. package/dist/{chunk-STJLWMXH.js → chunk-MCED4GDW.js} +467 -98
  8. package/dist/{chunk-GWMMYVLL.js → chunk-MWOXW7JQ.js} +7 -7
  9. package/dist/{chunk-GJETGML6.js → chunk-QCGIG7WW.js} +4 -6
  10. package/dist/{chunk-UYCD3JBZ.js → chunk-QHZGOG3O.js} +148 -46
  11. package/dist/{chunk-JLNHMNES.js → chunk-RYISHSHB.js} +286 -1
  12. package/dist/{chunk-SRBVKO2V.js → chunk-S3V6R3EN.js} +66 -39
  13. package/dist/{chunk-RBXTWWUH.js → chunk-WNXXLCV5.js} +1 -1
  14. package/dist/{chunk-LOUEJI6X.js → chunk-XBGVQMQJ.js} +71 -47
  15. package/dist/{chunk-DEWY7OQK.js → chunk-Z2GEFFDO.js} +1 -1
  16. package/dist/cli/index.js +25 -28
  17. package/dist/{client-66TFS7RS.js → client-XOLP5IUZ.js} +1 -1
  18. package/dist/{conduct-A6COHLHY.js → conduct-AZFLNUX3.js} +9 -10
  19. package/dist/{conduct-IUVAXUAV.js → conduct-VPUYTNEA.js} +9 -10
  20. package/dist/{conductor-mode-L2MB44BW.js → conductor-mode-PLTB6MS3.js} +6 -7
  21. package/dist/{conductor-mode-D5TFQW5L.js → conductor-mode-WKB42PYM.js} +6 -3
  22. package/dist/{execute-WOS457HW.js → execute-NNDCXTN4.js} +3 -2
  23. package/dist/{execute-5AWLARB5.js → execute-RIRHTIBU.js} +5 -4
  24. package/dist/index.d.ts +5069 -0
  25. package/dist/index.js +208 -610
  26. package/dist/{publish-capability-JJCBBMSX.js → publish-capability-QDR2QIZ2.js} +2 -2
  27. package/dist/{request-6YQLA7K3.js → request-NX7GSPIG.js} +30 -40
  28. package/dist/{serve-skill-X7TZSILV.js → serve-skill-E6EJQYAK.js} +9 -8
  29. package/dist/{server-5TSP4DBX.js → server-VBCT32FC.js} +10 -14
  30. package/dist/{service-coordinator-WTUSMPY6.js → service-coordinator-KMSA6BST.js} +77 -32
  31. package/dist/skills/agentbnb/bootstrap.js +113 -69
  32. package/package.json +1 -1
  33. package/dist/chunk-BZOJ7HBT.js +0 -170
  34. package/dist/chunk-KF3TZHA5.js +0 -91
@@ -1,23 +1,23 @@
1
- import {
2
- fetchRemoteCards
3
- } from "./chunk-KF3TZHA5.js";
4
1
  import {
5
2
  createPendingRequest,
6
3
  getAutonomyTier,
7
4
  insertAuditEvent
8
5
  } from "./chunk-GKVTD4EZ.js";
9
6
  import {
10
- searchCards
11
- } from "./chunk-BZOJ7HBT.js";
7
+ resolveTargetCapability
8
+ } from "./chunk-CQFBNTGT.js";
12
9
  import {
10
+ fetchRemoteCards,
13
11
  getBalance,
14
12
  holdEscrow,
15
13
  releaseEscrow,
14
+ searchCards,
16
15
  settleEscrow
17
- } from "./chunk-JLNHMNES.js";
16
+ } from "./chunk-RYISHSHB.js";
18
17
  import {
19
- requestCapability
20
- } from "./chunk-EZVOG7QS.js";
18
+ requestCapability,
19
+ requestViaRelay
20
+ } from "./chunk-CKOOVZOI.js";
21
21
  import {
22
22
  findPeer
23
23
  } from "./chunk-5AH3CMOX.js";
@@ -68,6 +68,7 @@ var BudgetManager = class {
68
68
  };
69
69
 
70
70
  // src/autonomy/auto-request.ts
71
+ import { randomUUID } from "crypto";
71
72
  function minMaxNormalize(values) {
72
73
  if (values.length === 0) return [];
73
74
  if (values.length === 1) return [1];
@@ -190,88 +191,189 @@ var AutoRequestor = class {
190
191
  }
191
192
  }
192
193
  const scored = scorePeers(candidates, this.owner);
194
+ const resolverOptions = {
195
+ registryDb: this.registryDb,
196
+ registryUrl: this.registryUrl,
197
+ onlineOnly: true
198
+ };
199
+ let resolvedTarget = null;
193
200
  if (scored.length === 0) {
201
+ resolvedTarget = await resolveTargetCapability(need.query, resolverOptions);
202
+ if (!resolvedTarget || resolvedTarget.owner === this.owner || resolvedTarget.credits_per_call > need.maxCostCredits) {
203
+ this.logFailure("auto_request_failed", "system", "none", 3, 0, "none", "No eligible peer found");
204
+ return { status: "no_peer", reason: "No eligible peer found" };
205
+ }
206
+ } else {
207
+ const top = scored[0];
208
+ const targetKey = top.skillId ?? top.card.id;
209
+ resolvedTarget = await resolveTargetCapability(targetKey, resolverOptions) ?? await resolveTargetCapability(need.query, resolverOptions);
210
+ if (!resolvedTarget || resolvedTarget.owner === this.owner) {
211
+ this.logFailure("auto_request_failed", top.card.id, top.skillId ?? "none", 3, top.cost, top.card.owner, "No eligible peer found");
212
+ return { status: "no_peer", reason: "No eligible peer found" };
213
+ }
214
+ }
215
+ if (!resolvedTarget) {
194
216
  this.logFailure("auto_request_failed", "system", "none", 3, 0, "none", "No eligible peer found");
195
217
  return { status: "no_peer", reason: "No eligible peer found" };
196
218
  }
197
- const top = scored[0];
198
- const peerConfig = findPeer(top.card.owner);
199
- if (!peerConfig) {
200
- this.logFailure("auto_request_failed", top.card.id, top.skillId ?? "none", 3, top.cost, top.card.owner, "No gateway config for peer");
201
- return { status: "no_peer", reason: "No gateway config for peer" };
202
- }
203
- const tier = getAutonomyTier(top.cost, this.autonomyConfig);
219
+ const selectedCardId = resolvedTarget.cardId;
220
+ const selectedSkillId = resolvedTarget.skillId;
221
+ const selectedPeer = resolvedTarget.owner;
222
+ const selectedCost = resolvedTarget.credits_per_call;
223
+ const selectedViaRelay = resolvedTarget.via_relay;
224
+ const tier = getAutonomyTier(selectedCost, this.autonomyConfig);
204
225
  if (tier === 3) {
205
226
  createPendingRequest(this.registryDb, {
206
227
  skill_query: need.query,
207
228
  max_cost_credits: need.maxCostCredits,
208
- credits: top.cost,
209
- selected_peer: top.card.owner,
210
- selected_card_id: top.card.id,
211
- selected_skill_id: top.skillId,
229
+ credits: selectedCost,
230
+ selected_peer: selectedPeer,
231
+ selected_card_id: selectedCardId,
232
+ selected_skill_id: selectedSkillId,
212
233
  params: need.params
213
234
  });
214
235
  insertAuditEvent(this.registryDb, {
215
236
  type: "auto_request_pending",
216
- card_id: top.card.id,
217
- skill_id: top.skillId ?? top.card.id,
237
+ card_id: selectedCardId,
238
+ skill_id: selectedSkillId ?? selectedCardId,
218
239
  tier_invoked: 3,
219
- credits: top.cost,
220
- peer: top.card.owner
240
+ credits: selectedCost,
241
+ peer: selectedPeer
221
242
  });
222
243
  return {
223
244
  status: "tier_blocked",
224
245
  reason: "Tier 3: owner approval required",
225
- peer: top.card.owner
246
+ peer: selectedPeer
226
247
  };
227
248
  }
228
- if (!this.budgetManager.canSpend(top.cost)) {
229
- this.logFailure("auto_request_failed", top.card.id, top.skillId ?? "none", tier, top.cost, top.card.owner, "Budget reserve would be breached");
249
+ if (!this.budgetManager.canSpend(selectedCost)) {
250
+ this.logFailure(
251
+ "auto_request_failed",
252
+ selectedCardId,
253
+ selectedSkillId ?? "none",
254
+ tier,
255
+ selectedCost,
256
+ selectedPeer,
257
+ "Budget reserve would be breached"
258
+ );
230
259
  return { status: "budget_blocked", reason: "Insufficient credits \u2014 reserve floor would be breached" };
231
260
  }
232
- const escrowId = holdEscrow(this.creditDb, this.owner, top.cost, top.card.id);
261
+ const escrowId = holdEscrow(this.creditDb, this.owner, selectedCost, selectedCardId);
233
262
  try {
234
- const execResult = await requestCapability({
235
- gatewayUrl: peerConfig.url,
236
- token: peerConfig.token,
237
- cardId: top.card.id,
238
- params: top.skillId ? { skill_id: top.skillId, ...need.params, requester: this.owner } : { ...need.params, requester: this.owner }
239
- });
240
- settleEscrow(this.creditDb, escrowId, top.card.owner);
263
+ const requestParams = selectedSkillId ? { skill_id: selectedSkillId, ...need.params, requester: this.owner } : { ...need.params, requester: this.owner };
264
+ let execResult;
265
+ if (selectedViaRelay) {
266
+ if (!this.registryUrl) {
267
+ this.logFailure(
268
+ "auto_request_failed",
269
+ selectedCardId,
270
+ selectedSkillId ?? "none",
271
+ tier,
272
+ selectedCost,
273
+ selectedPeer,
274
+ "Relay target found but registryUrl is not configured"
275
+ );
276
+ releaseEscrow(this.creditDb, escrowId);
277
+ return { status: "no_peer", reason: "Relay target found but registryUrl is not configured" };
278
+ }
279
+ const relayRequesterOwner = `${this.owner}:req:${randomUUID()}`;
280
+ const { RelayClient } = await import("./websocket-client-QOVARTRN.js");
281
+ const relayClient = new RelayClient({
282
+ registryUrl: this.registryUrl,
283
+ owner: relayRequesterOwner,
284
+ token: "auto-request-token",
285
+ card: {
286
+ spec_version: "1.0",
287
+ id: randomUUID(),
288
+ owner: relayRequesterOwner,
289
+ name: relayRequesterOwner,
290
+ description: "Auto-request requester",
291
+ level: 1,
292
+ inputs: [],
293
+ outputs: [],
294
+ pricing: { credits_per_call: 1 },
295
+ availability: { online: false }
296
+ },
297
+ onRequest: async () => ({ error: { code: -32601, message: "Auto-request relay requester does not serve capabilities" } }),
298
+ silent: true
299
+ });
300
+ try {
301
+ await relayClient.connect();
302
+ execResult = await requestViaRelay(relayClient, {
303
+ targetOwner: selectedPeer,
304
+ cardId: selectedCardId,
305
+ skillId: selectedSkillId,
306
+ params: requestParams,
307
+ requester: this.owner
308
+ });
309
+ } finally {
310
+ relayClient.disconnect();
311
+ }
312
+ } else {
313
+ const peerConfig = findPeer(selectedPeer);
314
+ if (!peerConfig) {
315
+ this.logFailure(
316
+ "auto_request_failed",
317
+ selectedCardId,
318
+ selectedSkillId ?? "none",
319
+ tier,
320
+ selectedCost,
321
+ selectedPeer,
322
+ "No gateway config for peer"
323
+ );
324
+ releaseEscrow(this.creditDb, escrowId);
325
+ return { status: "no_peer", reason: "No gateway config for peer" };
326
+ }
327
+ execResult = await requestCapability({
328
+ gatewayUrl: peerConfig.url,
329
+ token: peerConfig.token,
330
+ cardId: selectedCardId,
331
+ params: requestParams
332
+ });
333
+ }
334
+ settleEscrow(this.creditDb, escrowId, selectedPeer);
241
335
  if (tier === 2) {
242
336
  insertAuditEvent(this.registryDb, {
243
337
  type: "auto_request_notify",
244
- card_id: top.card.id,
245
- skill_id: top.skillId ?? top.card.id,
338
+ card_id: selectedCardId,
339
+ skill_id: selectedSkillId ?? selectedCardId,
246
340
  tier_invoked: 2,
247
- credits: top.cost,
248
- peer: top.card.owner
341
+ credits: selectedCost,
342
+ peer: selectedPeer
249
343
  });
250
344
  } else {
251
345
  insertAuditEvent(this.registryDb, {
252
346
  type: "auto_request",
253
- card_id: top.card.id,
254
- skill_id: top.skillId ?? top.card.id,
347
+ card_id: selectedCardId,
348
+ skill_id: selectedSkillId ?? selectedCardId,
255
349
  tier_invoked: 1,
256
- credits: top.cost,
257
- peer: top.card.owner
350
+ credits: selectedCost,
351
+ peer: selectedPeer
258
352
  });
259
353
  }
260
354
  return {
261
355
  status: "success",
262
356
  result: execResult,
263
357
  escrowId,
264
- peer: top.card.owner,
265
- creditsSpent: top.cost
358
+ peer: selectedPeer,
359
+ creditsSpent: selectedCost
266
360
  };
267
361
  } catch (err) {
268
362
  releaseEscrow(this.creditDb, escrowId);
269
363
  const reason = err instanceof Error ? err.message : String(err);
270
- this.logFailure("auto_request_failed", top.card.id, top.skillId ?? "none", tier, top.cost, top.card.owner, `Execution failed: ${reason}`);
364
+ this.logFailure(
365
+ "auto_request_failed",
366
+ selectedCardId,
367
+ selectedSkillId ?? "none",
368
+ tier,
369
+ selectedCost,
370
+ selectedPeer,
371
+ `Execution failed: ${reason}`
372
+ );
271
373
  return {
272
374
  status: "failed",
273
375
  reason: `Execution failed: ${reason}`,
274
- peer: top.card.owner
376
+ peer: selectedPeer
275
377
  };
276
378
  }
277
379
  }
@@ -2,6 +2,9 @@ import {
2
2
  ensureReliabilityTable,
3
3
  recordSuccessfulHire
4
4
  } from "./chunk-NWIQJ2CL.js";
5
+ import {
6
+ getFeedbackForProvider
7
+ } from "./chunk-S3V6R3EN.js";
5
8
  import {
6
9
  AgentBnBError
7
10
  } from "./chunk-WVY2W7AA.js";
@@ -390,6 +393,282 @@ function confirmEscrowDebit(db, escrowId) {
390
393
  confirm();
391
394
  }
392
395
 
396
+ // src/feedback/reputation.ts
397
+ var QUALITY_SCORES = {
398
+ excellent: 1,
399
+ good: 0.8,
400
+ acceptable: 0.6,
401
+ poor: 0.3,
402
+ failed: 0
403
+ };
404
+ var COST_VALUE_SCORES = {
405
+ great: 1,
406
+ fair: 0.6,
407
+ overpriced: 0.2
408
+ };
409
+ var DECAY_DAYS = 30;
410
+ var WEIGHTS = {
411
+ rating: 0.4,
412
+ quality: 0.3,
413
+ would_reuse: 0.2,
414
+ cost_value: 0.1
415
+ };
416
+ function computeReputation(feedbacks) {
417
+ if (feedbacks.length === 0) return 0.5;
418
+ const now = Date.now();
419
+ let weightedSum = 0;
420
+ let totalWeight = 0;
421
+ for (const fb of feedbacks) {
422
+ const feedbackDate = new Date(fb.timestamp).getTime();
423
+ const ageDays = Math.max(0, (now - feedbackDate) / (1e3 * 60 * 60 * 24));
424
+ const recencyWeight = Math.exp(-ageDays / DECAY_DAYS);
425
+ const ratingScore = (fb.rating - 1) / 4;
426
+ const qualityScore = QUALITY_SCORES[fb.result_quality];
427
+ const reuseScore = fb.would_reuse ? 1 : 0;
428
+ const costScore = COST_VALUE_SCORES[fb.cost_value_ratio];
429
+ const componentScore = WEIGHTS.rating * ratingScore + WEIGHTS.quality * qualityScore + WEIGHTS.would_reuse * reuseScore + WEIGHTS.cost_value * costScore;
430
+ weightedSum += recencyWeight * componentScore;
431
+ totalWeight += recencyWeight;
432
+ }
433
+ if (totalWeight === 0) return 0.5;
434
+ const raw = weightedSum / totalWeight;
435
+ return Math.max(0, Math.min(1, raw));
436
+ }
437
+ function getReputationScore(db, agentId) {
438
+ const feedbacks = getFeedbackForProvider(db, agentId);
439
+ return computeReputation(feedbacks);
440
+ }
441
+
442
+ // src/registry/matcher.ts
443
+ var CACHE_MAX_ENTRIES = 100;
444
+ var CACHE_TTL_MS = 3e4;
445
+ var dbCaches = /* @__PURE__ */ new WeakMap();
446
+ function getDbCache(db) {
447
+ let cache = dbCaches.get(db);
448
+ if (!cache) {
449
+ cache = /* @__PURE__ */ new Map();
450
+ dbCaches.set(db, cache);
451
+ }
452
+ return cache;
453
+ }
454
+ function cacheKey(query, filters) {
455
+ return `${query}|${filters.level ?? ""}|${filters.online ?? ""}|${(filters.apis_used ?? []).join(",")}|${filters.min_reputation ?? ""}`;
456
+ }
457
+ function evictCache(cache) {
458
+ const now = Date.now();
459
+ for (const [key, entry] of cache) {
460
+ if (entry.expiresAt <= now) cache.delete(key);
461
+ }
462
+ while (cache.size > CACHE_MAX_ENTRIES) {
463
+ const firstKey = cache.keys().next().value;
464
+ cache.delete(firstKey);
465
+ }
466
+ }
467
+ function searchCards(db, query, filters = {}) {
468
+ const cache = getDbCache(db);
469
+ const key = cacheKey(query, filters);
470
+ const cached = cache.get(key);
471
+ if (cached && cached.expiresAt > Date.now()) {
472
+ return cached.results;
473
+ }
474
+ const trimmedQuery = query.trim();
475
+ const exactSkillMatches = findCardsByExactSkillId(db, trimmedQuery, filters);
476
+ const words = query.trim().split(/\s+/).map((w) => w.replace(/["*^{}():]/g, "")).filter((w) => w.length > 0);
477
+ if (words.length === 0) {
478
+ return exactSkillMatches;
479
+ }
480
+ const ftsQuery = words.map((w) => `"${w}"`).join(" OR ");
481
+ const conditions = [];
482
+ const params = [ftsQuery];
483
+ if (filters.level !== void 0) {
484
+ conditions.push(`json_extract(cc.data, '$.level') = ?`);
485
+ params.push(filters.level);
486
+ }
487
+ if (filters.online !== void 0) {
488
+ conditions.push(`json_extract(cc.data, '$.availability.online') = ?`);
489
+ params.push(filters.online ? 1 : 0);
490
+ }
491
+ const whereClause = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
492
+ const sql = `
493
+ SELECT cc.data
494
+ FROM capability_cards cc
495
+ JOIN cards_fts ON cc.rowid = cards_fts.rowid
496
+ WHERE cards_fts MATCH ?
497
+ ${whereClause}
498
+ ORDER BY bm25(cards_fts)
499
+ LIMIT 50
500
+ `;
501
+ const stmt = db.prepare(sql);
502
+ const rows = stmt.all(...params);
503
+ const results = rows.map((row) => JSON.parse(row.data));
504
+ const mergedResults = mergeByCardId(exactSkillMatches, results);
505
+ let filtered = mergedResults;
506
+ if (filters.apis_used && filters.apis_used.length > 0) {
507
+ const requiredApis = filters.apis_used;
508
+ filtered = filtered.filter((card) => {
509
+ const cardApis = card.metadata?.apis_used ?? [];
510
+ return requiredApis.every((api) => cardApis.includes(api));
511
+ });
512
+ }
513
+ if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
514
+ filtered = applyReputationFilter(db, filtered, filters.min_reputation);
515
+ }
516
+ evictCache(cache);
517
+ cache.set(key, { results: filtered, expiresAt: Date.now() + CACHE_TTL_MS });
518
+ return filtered;
519
+ }
520
+ function mergeByCardId(primary, secondary) {
521
+ const seen = /* @__PURE__ */ new Set();
522
+ const merged = [];
523
+ for (const card of primary) {
524
+ if (seen.has(card.id)) continue;
525
+ seen.add(card.id);
526
+ merged.push(card);
527
+ }
528
+ for (const card of secondary) {
529
+ if (seen.has(card.id)) continue;
530
+ seen.add(card.id);
531
+ merged.push(card);
532
+ }
533
+ return merged;
534
+ }
535
+ function findCardsByExactSkillId(db, query, filters) {
536
+ if (query.length === 0) return [];
537
+ const rows = db.prepare("SELECT data FROM capability_cards").all();
538
+ const cards = rows.map((row) => JSON.parse(row.data));
539
+ return cards.filter((card) => {
540
+ if (filters.level !== void 0 && card.level !== filters.level) return false;
541
+ if (filters.online !== void 0 && card.availability?.online !== filters.online) return false;
542
+ const asRecord = card;
543
+ const skills = asRecord["skills"];
544
+ if (!Array.isArray(skills)) return false;
545
+ return skills.some((skill) => String(skill["id"] ?? "") === query);
546
+ });
547
+ }
548
+ function filterCards(db, filters) {
549
+ const conditions = [];
550
+ const params = [];
551
+ if (filters.level !== void 0) {
552
+ conditions.push(`json_extract(data, '$.level') = ?`);
553
+ params.push(filters.level);
554
+ }
555
+ if (filters.online !== void 0) {
556
+ conditions.push(`json_extract(data, '$.availability.online') = ?`);
557
+ params.push(filters.online ? 1 : 0);
558
+ }
559
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
560
+ const sql = `SELECT data FROM capability_cards ${whereClause}`;
561
+ const stmt = db.prepare(sql);
562
+ const rows = stmt.all(...params);
563
+ let cards = rows.map((row) => JSON.parse(row.data));
564
+ if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
565
+ cards = applyReputationFilter(db, cards, filters.min_reputation);
566
+ }
567
+ return cards;
568
+ }
569
+ function applyReputationFilter(db, cards, minReputation) {
570
+ const owners = [...new Set(cards.map((c) => c.owner))];
571
+ const reputationMap = /* @__PURE__ */ new Map();
572
+ for (const owner of owners) {
573
+ reputationMap.set(owner, getReputationScore(db, owner));
574
+ }
575
+ return cards.filter((card) => {
576
+ const score = reputationMap.get(card.owner) ?? 0.5;
577
+ return score >= minReputation;
578
+ });
579
+ }
580
+ function buildReputationMap(db, owners) {
581
+ const unique = [...new Set(owners)];
582
+ const map = /* @__PURE__ */ new Map();
583
+ for (const owner of unique) {
584
+ map.set(owner, getReputationScore(db, owner));
585
+ }
586
+ return map;
587
+ }
588
+
589
+ // src/cli/remote-registry.ts
590
+ var RegistryTimeoutError = class extends AgentBnBError {
591
+ constructor(url) {
592
+ super(
593
+ `Registry at ${url} did not respond within 5s. Showing local results only.`,
594
+ "REGISTRY_TIMEOUT"
595
+ );
596
+ this.name = "RegistryTimeoutError";
597
+ }
598
+ };
599
+ var RegistryConnectionError = class extends AgentBnBError {
600
+ constructor(url) {
601
+ super(
602
+ `Cannot reach ${url}. Is the registry running? Showing local results only.`,
603
+ "REGISTRY_CONNECTION"
604
+ );
605
+ this.name = "RegistryConnectionError";
606
+ }
607
+ };
608
+ var RegistryAuthError = class extends AgentBnBError {
609
+ constructor(url) {
610
+ super(
611
+ `Authentication failed for ${url}. Run \`agentbnb config set token <your-token>\`.`,
612
+ "REGISTRY_AUTH"
613
+ );
614
+ this.name = "RegistryAuthError";
615
+ }
616
+ };
617
+ async function fetchRemoteCards(registryUrl, params, timeoutMs = 5e3) {
618
+ let cardsUrl;
619
+ try {
620
+ cardsUrl = new URL("/cards", registryUrl);
621
+ } catch {
622
+ throw new AgentBnBError(`Invalid registry URL: ${registryUrl}`, "INVALID_REGISTRY_URL");
623
+ }
624
+ const searchParams = new URLSearchParams();
625
+ if (params.q !== void 0) searchParams.set("q", params.q);
626
+ if (params.level !== void 0) searchParams.set("level", String(params.level));
627
+ if (params.online !== void 0) searchParams.set("online", String(params.online));
628
+ if (params.tag !== void 0) searchParams.set("tag", params.tag);
629
+ searchParams.set("limit", "100");
630
+ cardsUrl.search = searchParams.toString();
631
+ const controller = new AbortController();
632
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
633
+ let response;
634
+ try {
635
+ response = await fetch(cardsUrl.toString(), { signal: controller.signal });
636
+ } catch (err) {
637
+ clearTimeout(timer);
638
+ const isTimeout = err instanceof Error && err.name === "AbortError";
639
+ if (isTimeout) {
640
+ throw new RegistryTimeoutError(registryUrl);
641
+ }
642
+ throw new RegistryConnectionError(registryUrl);
643
+ } finally {
644
+ clearTimeout(timer);
645
+ }
646
+ if (response.status === 401 || response.status === 403) {
647
+ throw new RegistryAuthError(registryUrl);
648
+ }
649
+ if (!response.ok) {
650
+ throw new RegistryConnectionError(registryUrl);
651
+ }
652
+ const body = await response.json();
653
+ return body.items;
654
+ }
655
+ function mergeResults(localCards, remoteCards, hasQuery) {
656
+ const taggedLocal = localCards.map((c) => ({ ...c, source: "local" }));
657
+ const taggedRemote = remoteCards.map((c) => ({ ...c, source: "remote" }));
658
+ const localIds = new Set(localCards.map((c) => c.id));
659
+ const dedupedRemote = taggedRemote.filter((c) => !localIds.has(c.id));
660
+ if (!hasQuery) {
661
+ return [...taggedLocal, ...dedupedRemote];
662
+ }
663
+ const result = [];
664
+ const maxLen = Math.max(taggedLocal.length, dedupedRemote.length);
665
+ for (let i = 0; i < maxLen; i++) {
666
+ if (i < taggedLocal.length) result.push(taggedLocal[i]);
667
+ if (i < dedupedRemote.length) result.push(dedupedRemote[i]);
668
+ }
669
+ return result;
670
+ }
671
+
393
672
  export {
394
673
  createAgentRecord,
395
674
  lookupAgent,
@@ -404,5 +683,11 @@ export {
404
683
  holdEscrow,
405
684
  settleEscrow,
406
685
  releaseEscrow,
407
- confirmEscrowDebit
686
+ confirmEscrowDebit,
687
+ computeReputation,
688
+ searchCards,
689
+ filterCards,
690
+ buildReputationMap,
691
+ fetchRemoteCards,
692
+ mergeResults
408
693
  };