agentbnb 8.2.0 → 8.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TBJ3FZKZ.js → chunk-4IPJJRTP.js} +1 -1
- package/dist/chunk-CKOOVZOI.js +158 -0
- package/dist/chunk-CQFBNTGT.js +145 -0
- package/dist/{chunk-P4LOYSLA.js → chunk-DYQOFGGI.js} +331 -416
- package/dist/{chunk-ALX4WS3A.js → chunk-EG6RS4JC.js} +70 -46
- package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
- package/dist/{chunk-5AAFG2V2.js → chunk-LKLKYXLV.js} +239 -24
- package/dist/{chunk-7EF3HYVZ.js → chunk-MCED4GDW.js} +499 -86
- package/dist/{chunk-YHY7OG6S.js → chunk-MWOXW7JQ.js} +7 -7
- package/dist/{chunk-E2OKP5CY.js → chunk-QCGIG7WW.js} +182 -86
- package/dist/{chunk-5GME4KJZ.js → chunk-QHZGOG3O.js} +148 -46
- package/dist/{chunk-D6RKW2XG.js → chunk-RYISHSHB.js} +302 -4
- package/dist/{chunk-O2OYBAVR.js → chunk-S3V6R3EN.js} +75 -39
- package/dist/{chunk-X32NE6V4.js → chunk-WNXXLCV5.js} +1 -1
- package/dist/{chunk-C537SFHV.js → chunk-XBGVQMQJ.js} +72 -48
- package/dist/{chunk-FTZTEHYG.js → chunk-Z2GEFFDO.js} +135 -8
- package/dist/cli/index.js +42 -67
- package/dist/{client-HKV3QWZ3.js → client-XOLP5IUZ.js} +4 -2
- package/dist/{conduct-W6XF6DJW.js → conduct-AZFLNUX3.js} +10 -11
- package/dist/{conduct-YB64OHI6.js → conduct-VPUYTNEA.js} +10 -11
- package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-PLTB6MS3.js} +7 -8
- package/dist/{conductor-mode-TFCVCQHU.js → conductor-mode-WKB42PYM.js} +6 -3
- package/dist/{execute-EPE6MZLT.js → execute-NNDCXTN4.js} +3 -2
- package/dist/{execute-AYQWORVH.js → execute-RIRHTIBU.js} +6 -5
- package/dist/index.d.ts +8 -8
- package/dist/index.js +637 -693
- package/dist/{publish-capability-AH2HDW54.js → publish-capability-QDR2QIZ2.js} +2 -2
- package/dist/{request-HCCXSKAY.js → request-NX7GSPIG.js} +31 -36
- package/dist/{serve-skill-SZAQT5T5.js → serve-skill-E6EJQYAK.js} +10 -9
- package/dist/{server-LMY2A3GT.js → server-VBCT32FC.js} +12 -18
- package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-KMSA6BST.js} +137 -69
- package/dist/skills/agentbnb/bootstrap.js +561 -247
- package/package.json +13 -17
- package/skills/agentbnb/bootstrap.test.ts +8 -6
- package/skills/agentbnb/bootstrap.ts +21 -13
- package/skills/agentbnb/install.sh +0 -0
- package/dist/chunk-64AK4FJM.js +0 -84
- package/dist/chunk-KF3TZHA5.js +0 -91
- package/dist/chunk-LJM7FHPM.js +0 -138
- package/dist/chunk-OH7BP5NP.js +0 -96
|
@@ -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";
|
|
@@ -149,10 +152,23 @@ function getBalance(db, owner) {
|
|
|
149
152
|
const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
|
|
150
153
|
return row?.balance ?? 0;
|
|
151
154
|
}
|
|
152
|
-
function getTransactions(db, owner,
|
|
155
|
+
function getTransactions(db, owner, opts = 100) {
|
|
156
|
+
const page = typeof opts === "number" ? { limit: opts } : opts;
|
|
157
|
+
const limit = page.limit ?? 100;
|
|
158
|
+
const conditions = ["owner = ?"];
|
|
159
|
+
const params = [owner];
|
|
160
|
+
if (page.before) {
|
|
161
|
+
conditions.push("created_at < ?");
|
|
162
|
+
params.push(page.before);
|
|
163
|
+
}
|
|
164
|
+
if (page.after) {
|
|
165
|
+
conditions.push("created_at > ?");
|
|
166
|
+
params.push(page.after);
|
|
167
|
+
}
|
|
168
|
+
params.push(limit);
|
|
153
169
|
return db.prepare(
|
|
154
|
-
|
|
155
|
-
).all(
|
|
170
|
+
`SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
|
|
171
|
+
).all(...params);
|
|
156
172
|
}
|
|
157
173
|
function registerProvider(db, owner) {
|
|
158
174
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -377,6 +393,282 @@ function confirmEscrowDebit(db, escrowId) {
|
|
|
377
393
|
confirm();
|
|
378
394
|
}
|
|
379
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
|
+
|
|
380
672
|
export {
|
|
381
673
|
createAgentRecord,
|
|
382
674
|
lookupAgent,
|
|
@@ -391,5 +683,11 @@ export {
|
|
|
391
683
|
holdEscrow,
|
|
392
684
|
settleEscrow,
|
|
393
685
|
releaseEscrow,
|
|
394
|
-
confirmEscrowDebit
|
|
686
|
+
confirmEscrowDebit,
|
|
687
|
+
computeReputation,
|
|
688
|
+
searchCards,
|
|
689
|
+
filterCards,
|
|
690
|
+
buildReputationMap,
|
|
691
|
+
fetchRemoteCards,
|
|
692
|
+
mergeResults
|
|
395
693
|
};
|
|
@@ -315,7 +315,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
315
315
|
new.id,
|
|
316
316
|
new.owner,
|
|
317
317
|
COALESCE(
|
|
318
|
-
(SELECT group_concat(
|
|
318
|
+
(SELECT group_concat(
|
|
319
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
320
|
+
' '
|
|
321
|
+
)
|
|
319
322
|
FROM json_each(json_extract(new.data, '$.skills'))),
|
|
320
323
|
json_extract(new.data, '$.name'),
|
|
321
324
|
''
|
|
@@ -355,7 +358,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
355
358
|
old.id,
|
|
356
359
|
old.owner,
|
|
357
360
|
COALESCE(
|
|
358
|
-
(SELECT group_concat(
|
|
361
|
+
(SELECT group_concat(
|
|
362
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
363
|
+
' '
|
|
364
|
+
)
|
|
359
365
|
FROM json_each(json_extract(old.data, '$.skills'))),
|
|
360
366
|
json_extract(old.data, '$.name'),
|
|
361
367
|
''
|
|
@@ -391,7 +397,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
391
397
|
new.id,
|
|
392
398
|
new.owner,
|
|
393
399
|
COALESCE(
|
|
394
|
-
(SELECT group_concat(
|
|
400
|
+
(SELECT group_concat(
|
|
401
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
402
|
+
' '
|
|
403
|
+
)
|
|
395
404
|
FROM json_each(json_extract(new.data, '$.skills'))),
|
|
396
405
|
json_extract(new.data, '$.name'),
|
|
397
406
|
''
|
|
@@ -431,7 +440,10 @@ var V2_FTS_TRIGGERS = `
|
|
|
431
440
|
old.id,
|
|
432
441
|
old.owner,
|
|
433
442
|
COALESCE(
|
|
434
|
-
(SELECT group_concat(
|
|
443
|
+
(SELECT group_concat(
|
|
444
|
+
COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
|
|
445
|
+
' '
|
|
446
|
+
)
|
|
435
447
|
FROM json_each(json_extract(old.data, '$.skills'))),
|
|
436
448
|
json_extract(old.data, '$.name'),
|
|
437
449
|
''
|
|
@@ -498,6 +510,15 @@ function openDatabase(path = ":memory:") {
|
|
|
498
510
|
tags,
|
|
499
511
|
content=""
|
|
500
512
|
);
|
|
513
|
+
|
|
514
|
+
-- Expression index for capability_type lookups (used by Conductor routing).
|
|
515
|
+
-- Turns json_extract full-table-scan into O(log n) B-tree lookup.
|
|
516
|
+
CREATE INDEX IF NOT EXISTS idx_cards_capability_type
|
|
517
|
+
ON capability_cards(json_extract(data, '$.capability_type'));
|
|
518
|
+
|
|
519
|
+
-- Owner index for listCards(owner) and other owner-scoped queries.
|
|
520
|
+
CREATE INDEX IF NOT EXISTS idx_cards_owner
|
|
521
|
+
ON capability_cards(owner);
|
|
501
522
|
`);
|
|
502
523
|
createRequestLogTable(db);
|
|
503
524
|
initFeedbackTable(db);
|
|
@@ -509,6 +530,10 @@ function runMigrations(db) {
|
|
|
509
530
|
const version = db.pragma("user_version")[0]?.user_version ?? 0;
|
|
510
531
|
if (version < 2) {
|
|
511
532
|
migrateV1toV2(db);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
if (version < 3) {
|
|
536
|
+
migrateV2toV3(db);
|
|
512
537
|
}
|
|
513
538
|
}
|
|
514
539
|
function migrateV1toV2(db) {
|
|
@@ -550,44 +575,55 @@ function migrateV1toV2(db) {
|
|
|
550
575
|
);
|
|
551
576
|
}
|
|
552
577
|
db.exec(V2_FTS_TRIGGERS);
|
|
553
|
-
db
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
let tags;
|
|
564
|
-
if (skills.length > 0) {
|
|
565
|
-
name = skills.map((s) => String(s["name"] ?? "")).join(" ");
|
|
566
|
-
description = skills.map((s) => String(s["description"] ?? "")).join(" ");
|
|
567
|
-
tags = [
|
|
568
|
-
// tags from metadata.tags[]
|
|
569
|
-
...skills.flatMap((s) => {
|
|
570
|
-
const meta = s["metadata"];
|
|
571
|
-
return meta?.["tags"] ?? [];
|
|
572
|
-
}),
|
|
573
|
-
// capability_type (singular)
|
|
574
|
-
...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
|
|
575
|
-
// capability_types[] (plural)
|
|
576
|
-
...skills.flatMap((s) => s["capability_types"] ?? [])
|
|
577
|
-
].join(" ");
|
|
578
|
-
} else {
|
|
579
|
-
name = String(data["name"] ?? "");
|
|
580
|
-
description = String(data["description"] ?? "");
|
|
581
|
-
const meta = data["metadata"];
|
|
582
|
-
const rawTags = meta?.["tags"] ?? [];
|
|
583
|
-
tags = rawTags.join(" ");
|
|
584
|
-
}
|
|
585
|
-
ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
|
|
586
|
-
}
|
|
587
|
-
db.pragma("user_version = 2");
|
|
578
|
+
rebuildCardsFts(db);
|
|
579
|
+
db.pragma("user_version = 3");
|
|
580
|
+
});
|
|
581
|
+
migrate();
|
|
582
|
+
}
|
|
583
|
+
function migrateV2toV3(db) {
|
|
584
|
+
const migrate = db.transaction(() => {
|
|
585
|
+
db.exec(V2_FTS_TRIGGERS);
|
|
586
|
+
rebuildCardsFts(db);
|
|
587
|
+
db.pragma("user_version = 3");
|
|
588
588
|
});
|
|
589
589
|
migrate();
|
|
590
590
|
}
|
|
591
|
+
function rebuildCardsFts(db) {
|
|
592
|
+
db.exec(`INSERT INTO cards_fts(cards_fts) VALUES('delete-all')`);
|
|
593
|
+
const allRows = db.prepare("SELECT rowid, id, owner, data FROM capability_cards").all();
|
|
594
|
+
const ftsInsert = db.prepare(
|
|
595
|
+
"INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
|
|
596
|
+
);
|
|
597
|
+
for (const row of allRows) {
|
|
598
|
+
const data = JSON.parse(row.data);
|
|
599
|
+
const skills = data["skills"] ?? [];
|
|
600
|
+
let name;
|
|
601
|
+
let description;
|
|
602
|
+
let tags;
|
|
603
|
+
if (skills.length > 0) {
|
|
604
|
+
name = skills.map((s) => `${String(s["id"] ?? "")} ${String(s["name"] ?? "")}`.trim()).join(" ");
|
|
605
|
+
description = skills.map((s) => String(s["description"] ?? "")).join(" ");
|
|
606
|
+
tags = [
|
|
607
|
+
// tags from metadata.tags[]
|
|
608
|
+
...skills.flatMap((s) => {
|
|
609
|
+
const meta = s["metadata"];
|
|
610
|
+
return meta?.["tags"] ?? [];
|
|
611
|
+
}),
|
|
612
|
+
// capability_type (singular)
|
|
613
|
+
...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
|
|
614
|
+
// capability_types[] (plural)
|
|
615
|
+
...skills.flatMap((s) => s["capability_types"] ?? [])
|
|
616
|
+
].join(" ");
|
|
617
|
+
} else {
|
|
618
|
+
name = String(data["name"] ?? "");
|
|
619
|
+
description = String(data["description"] ?? "");
|
|
620
|
+
const meta = data["metadata"];
|
|
621
|
+
const rawTags = meta?.["tags"] ?? [];
|
|
622
|
+
tags = rawTags.join(" ");
|
|
623
|
+
}
|
|
624
|
+
ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
591
627
|
function insertCard(db, card) {
|
|
592
628
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
593
629
|
const withTimestamps = { ...card, created_at: card.created_at ?? now, updated_at: now };
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
settleProviderEarning
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-WNXXLCV5.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveTargetCapability
|
|
6
|
+
} from "./chunk-CQFBNTGT.js";
|
|
4
7
|
import {
|
|
5
8
|
getBalance,
|
|
6
9
|
holdEscrow,
|
|
7
10
|
releaseEscrow,
|
|
8
11
|
settleEscrow
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RYISHSHB.js";
|
|
10
13
|
import {
|
|
11
14
|
verifyEscrowReceipt
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-EJKW57ZV.js";
|
|
13
16
|
import {
|
|
14
17
|
loadConfig
|
|
15
18
|
} from "./chunk-75OC6E4F.js";
|
|
@@ -17,7 +20,7 @@ import {
|
|
|
17
20
|
getCard,
|
|
18
21
|
insertRequestLog,
|
|
19
22
|
updateReputation
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-S3V6R3EN.js";
|
|
21
24
|
import {
|
|
22
25
|
AgentBnBError
|
|
23
26
|
} from "./chunk-WVY2W7AA.js";
|
|
@@ -272,8 +275,12 @@ async function executeCapabilityBatch(options) {
|
|
|
272
275
|
};
|
|
273
276
|
}
|
|
274
277
|
const executeItem = async (item, index) => {
|
|
275
|
-
const
|
|
276
|
-
|
|
278
|
+
const resolved = await resolveTargetCapability(item.skill_id, {
|
|
279
|
+
registryDb,
|
|
280
|
+
registryUrl: options.registryUrl,
|
|
281
|
+
onlineOnly: true
|
|
282
|
+
});
|
|
283
|
+
if (!resolved) {
|
|
277
284
|
return {
|
|
278
285
|
request_index: index,
|
|
279
286
|
status: "failed",
|
|
@@ -282,26 +289,11 @@ async function executeCapabilityBatch(options) {
|
|
|
282
289
|
error: `Card/skill not found: ${item.skill_id}`
|
|
283
290
|
};
|
|
284
291
|
}
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const skill = v2card.skills[0];
|
|
291
|
-
if (!skill) {
|
|
292
|
-
return {
|
|
293
|
-
request_index: index,
|
|
294
|
-
status: "failed",
|
|
295
|
-
credits_spent: 0,
|
|
296
|
-
credits_refunded: 0,
|
|
297
|
-
error: `No skills defined on card: ${item.skill_id}`
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
creditsNeeded = skill.pricing.credits_per_call;
|
|
301
|
-
resolvedSkillId = skill.id;
|
|
302
|
-
} else {
|
|
303
|
-
creditsNeeded = card.pricing.credits_per_call;
|
|
304
|
-
}
|
|
292
|
+
const localCard = getCard(registryDb, resolved.cardId);
|
|
293
|
+
const localCardRaw = localCard;
|
|
294
|
+
const cardName = typeof localCardRaw?.["name"] === "string" ? localCardRaw["name"] : typeof localCardRaw?.["agent_name"] === "string" ? localCardRaw["agent_name"] : resolved.cardId;
|
|
295
|
+
const creditsNeeded = resolved.credits_per_call;
|
|
296
|
+
const resolvedSkillId = resolved.skillId;
|
|
305
297
|
if (creditsNeeded > item.max_credits) {
|
|
306
298
|
return {
|
|
307
299
|
request_index: index,
|
|
@@ -323,7 +315,7 @@ async function executeCapabilityBatch(options) {
|
|
|
323
315
|
error: "Insufficient credits"
|
|
324
316
|
};
|
|
325
317
|
}
|
|
326
|
-
escrowId = holdEscrow(creditDb, owner, creditsNeeded,
|
|
318
|
+
escrowId = holdEscrow(creditDb, owner, creditsNeeded, resolved.cardId);
|
|
327
319
|
} catch (err) {
|
|
328
320
|
const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
|
|
329
321
|
return {
|
|
@@ -335,30 +327,62 @@ async function executeCapabilityBatch(options) {
|
|
|
335
327
|
};
|
|
336
328
|
}
|
|
337
329
|
const startMs = Date.now();
|
|
338
|
-
const latencyMs = Date.now() - startMs;
|
|
339
|
-
settleEscrow(creditDb, escrowId, card.owner);
|
|
340
|
-
updateReputation(registryDb, card.id, true, latencyMs);
|
|
341
330
|
try {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
331
|
+
const result = options.dispatchRequest ? await options.dispatchRequest({
|
|
332
|
+
target: resolved,
|
|
333
|
+
params: item.params,
|
|
334
|
+
requester: owner
|
|
335
|
+
}) : { card_id: resolved.cardId, skill_id: resolvedSkillId };
|
|
336
|
+
const latencyMs = Date.now() - startMs;
|
|
337
|
+
settleEscrow(creditDb, escrowId, resolved.owner);
|
|
338
|
+
updateReputation(registryDb, resolved.cardId, true, latencyMs);
|
|
339
|
+
try {
|
|
340
|
+
insertRequestLog(registryDb, {
|
|
341
|
+
id: randomUUID(),
|
|
342
|
+
card_id: resolved.cardId,
|
|
343
|
+
card_name: cardName,
|
|
344
|
+
skill_id: resolvedSkillId,
|
|
345
|
+
requester: owner,
|
|
346
|
+
status: "success",
|
|
347
|
+
latency_ms: latencyMs,
|
|
348
|
+
credits_charged: creditsNeeded,
|
|
349
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
350
|
+
});
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
request_index: index,
|
|
348
355
|
status: "success",
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
} catch {
|
|
356
|
+
result,
|
|
357
|
+
credits_spent: creditsNeeded,
|
|
358
|
+
credits_refunded: 0
|
|
359
|
+
};
|
|
360
|
+
} catch (err) {
|
|
361
|
+
releaseEscrow(creditDb, escrowId);
|
|
362
|
+
const latencyMs = Date.now() - startMs;
|
|
363
|
+
try {
|
|
364
|
+
insertRequestLog(registryDb, {
|
|
365
|
+
id: randomUUID(),
|
|
366
|
+
card_id: resolved.cardId,
|
|
367
|
+
card_name: cardName,
|
|
368
|
+
skill_id: resolvedSkillId,
|
|
369
|
+
requester: owner,
|
|
370
|
+
status: "failure",
|
|
371
|
+
latency_ms: latencyMs,
|
|
372
|
+
credits_charged: 0,
|
|
373
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
374
|
+
failure_reason: "not_found"
|
|
375
|
+
});
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
request_index: index,
|
|
380
|
+
status: "failed",
|
|
381
|
+
credits_spent: 0,
|
|
382
|
+
credits_refunded: creditsNeeded,
|
|
383
|
+
error: err instanceof Error ? err.message : String(err)
|
|
384
|
+
};
|
|
354
385
|
}
|
|
355
|
-
return {
|
|
356
|
-
request_index: index,
|
|
357
|
-
status: "success",
|
|
358
|
-
result: { card_id: card.id, skill_id: resolvedSkillId },
|
|
359
|
-
credits_spent: creditsNeeded,
|
|
360
|
-
credits_refunded: 0
|
|
361
|
-
};
|
|
362
386
|
};
|
|
363
387
|
let results;
|
|
364
388
|
if (strategy === "sequential") {
|