agentbnb 4.0.2 → 5.1.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 (45) hide show
  1. package/README.md +31 -2
  2. package/dist/chunk-AUBHR7HH.js +25 -0
  3. package/dist/chunk-B5FTAGFN.js +393 -0
  4. package/dist/{chunk-GGYC5U2Z.js → chunk-BTTL24TZ.js} +29 -91
  5. package/dist/chunk-C6KPAFCC.js +387 -0
  6. package/dist/chunk-CRFCWD6V.js +366 -0
  7. package/dist/chunk-CSATDXZC.js +89 -0
  8. package/dist/{chunk-T7NS2J2B.js → chunk-DFBX3BBD.js} +84 -1
  9. package/dist/{chunk-DNWT5FZQ.js → chunk-EANI2N2V.js} +98 -1
  10. package/dist/{chunk-HH24WMFN.js → chunk-FLY3WIQR.js} +1 -1
  11. package/dist/chunk-HLUEOLSZ.js +62 -0
  12. package/dist/chunk-IVOYM3WG.js +25 -0
  13. package/dist/chunk-LCAIAAG2.js +916 -0
  14. package/dist/chunk-MLS6IGGG.js +294 -0
  15. package/dist/{chunk-4P3EMGL4.js → chunk-MNO4COST.js} +5 -3
  16. package/dist/chunk-NH2FIERR.js +138 -0
  17. package/dist/chunk-UKT6H7YT.js +29 -0
  18. package/dist/{chunk-BH6WGYFB.js → chunk-VE3E4AMH.js} +8 -8
  19. package/dist/{chunk-7NA43XCG.js → chunk-W5BZMKMF.js} +163 -29
  20. package/dist/{chunk-FF226TIV.js → chunk-ZX5623ER.js} +0 -57
  21. package/dist/cli/index.js +362 -4631
  22. package/dist/{conduct-N52JX7RT.js → conduct-KM6ZNJGE.js} +10 -8
  23. package/dist/{conduct-GZQNFTRP.js → conduct-WGTMQND5.js} +10 -8
  24. package/dist/{conductor-mode-XUWGR4ZE.js → conductor-mode-OL2FNOYY.js} +6 -4
  25. package/dist/conductor-mode-VRO7TYW2.js +592 -0
  26. package/dist/execute-CPFSOOO3.js +13 -0
  27. package/dist/execute-IP2QHALV.js +10 -0
  28. package/dist/index.d.ts +19 -8
  29. package/dist/index.js +190 -37
  30. package/dist/peers-CJ7T4RJO.js +13 -0
  31. package/dist/process-guard-CC7CNRQJ.js +176 -0
  32. package/dist/{request-4GQSSM4B.js → request-YOWPXVLQ.js} +13 -10
  33. package/dist/schema-7BSSLZ4S.js +8 -0
  34. package/dist/{serve-skill-TPHZH6BS.js → serve-skill-JHFNR7BW.js} +8 -7
  35. package/dist/{server-365V3GYD.js → server-HKJJWFRG.js} +10 -8
  36. package/dist/service-coordinator-5R4LQW6L.js +4917 -0
  37. package/dist/skills/agentbnb/bootstrap.js +6181 -0
  38. package/dist/websocket-client-WRN3HO73.js +6 -0
  39. package/openclaw.plugin.json +54 -0
  40. package/package.json +11 -2
  41. package/skills/agentbnb/SKILL.md +87 -70
  42. package/skills/agentbnb/bootstrap.test.ts +142 -242
  43. package/skills/agentbnb/bootstrap.ts +88 -95
  44. package/skills/agentbnb/install.sh +97 -27
  45. package/dist/execute-PNGQOMYO.js +0 -10
@@ -0,0 +1,916 @@
1
+ import {
2
+ confirmEscrowDebit,
3
+ getBalance,
4
+ holdEscrow,
5
+ initFeedbackTable,
6
+ recordEarning,
7
+ releaseEscrow,
8
+ settleEscrow,
9
+ verifyEscrowReceipt
10
+ } from "./chunk-CRFCWD6V.js";
11
+ import {
12
+ AgentBnBError,
13
+ AnyCardSchema,
14
+ CapabilityCardSchema
15
+ } from "./chunk-WGZ5AGOX.js";
16
+
17
+ // src/gateway/execute.ts
18
+ import { randomUUID as randomUUID2 } from "crypto";
19
+
20
+ // src/registry/store.ts
21
+ import Database from "better-sqlite3";
22
+
23
+ // src/registry/request-log.ts
24
+ var SINCE_MS = {
25
+ "24h": 864e5,
26
+ "7d": 6048e5,
27
+ "30d": 2592e6
28
+ };
29
+ function createRequestLogTable(db) {
30
+ db.exec(`
31
+ CREATE TABLE IF NOT EXISTS request_log (
32
+ id TEXT PRIMARY KEY,
33
+ card_id TEXT NOT NULL,
34
+ card_name TEXT NOT NULL,
35
+ requester TEXT NOT NULL,
36
+ status TEXT NOT NULL CHECK(status IN ('success', 'failure', 'timeout')),
37
+ latency_ms INTEGER NOT NULL,
38
+ credits_charged INTEGER NOT NULL,
39
+ created_at TEXT NOT NULL
40
+ );
41
+
42
+ CREATE INDEX IF NOT EXISTS request_log_created_at_idx
43
+ ON request_log (created_at DESC);
44
+ `);
45
+ try {
46
+ db.exec("ALTER TABLE request_log ADD COLUMN skill_id TEXT");
47
+ } catch {
48
+ }
49
+ try {
50
+ db.exec("ALTER TABLE request_log ADD COLUMN action_type TEXT");
51
+ } catch {
52
+ }
53
+ try {
54
+ db.exec("ALTER TABLE request_log ADD COLUMN tier_invoked INTEGER");
55
+ } catch {
56
+ }
57
+ }
58
+ function insertRequestLog(db, entry) {
59
+ const stmt = db.prepare(`
60
+ INSERT INTO request_log (id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked)
61
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
62
+ `);
63
+ stmt.run(
64
+ entry.id,
65
+ entry.card_id,
66
+ entry.card_name,
67
+ entry.requester,
68
+ entry.status,
69
+ entry.latency_ms,
70
+ entry.credits_charged,
71
+ entry.created_at,
72
+ entry.skill_id ?? null,
73
+ entry.action_type ?? null,
74
+ entry.tier_invoked ?? null
75
+ );
76
+ }
77
+ function getSkillRequestCount(db, skillId, windowMs) {
78
+ const cutoff = new Date(Date.now() - windowMs).toISOString();
79
+ const stmt = db.prepare(
80
+ `SELECT COUNT(*) as cnt FROM request_log
81
+ WHERE skill_id = ? AND created_at >= ? AND status = 'success' AND action_type IS NULL`
82
+ );
83
+ const row = stmt.get(skillId, cutoff);
84
+ return row.cnt;
85
+ }
86
+ function getActivityFeed(db, limit = 20, since) {
87
+ const effectiveLimit = Math.min(limit, 100);
88
+ if (since !== void 0) {
89
+ const stmt2 = db.prepare(`
90
+ SELECT r.id, r.card_name, r.requester, c.owner AS provider,
91
+ r.status, r.credits_charged, r.latency_ms, r.created_at, r.action_type
92
+ FROM request_log r
93
+ LEFT JOIN capability_cards c ON r.card_id = c.id
94
+ WHERE (r.action_type IS NULL OR r.action_type IN ('auto_share', 'agent_joined'))
95
+ AND r.created_at > ?
96
+ ORDER BY r.created_at DESC
97
+ LIMIT ?
98
+ `);
99
+ return stmt2.all(since, effectiveLimit);
100
+ }
101
+ const stmt = db.prepare(`
102
+ SELECT r.id, r.card_name, r.requester, c.owner AS provider,
103
+ r.status, r.credits_charged, r.latency_ms, r.created_at, r.action_type
104
+ FROM request_log r
105
+ LEFT JOIN capability_cards c ON r.card_id = c.id
106
+ WHERE (r.action_type IS NULL OR r.action_type IN ('auto_share', 'agent_joined'))
107
+ ORDER BY r.created_at DESC
108
+ LIMIT ?
109
+ `);
110
+ return stmt.all(effectiveLimit);
111
+ }
112
+ function getRequestLog(db, limit = 10, since) {
113
+ if (since !== void 0) {
114
+ const cutoff = new Date(Date.now() - SINCE_MS[since]).toISOString();
115
+ const stmt2 = db.prepare(`
116
+ SELECT id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked
117
+ FROM request_log
118
+ WHERE created_at >= ?
119
+ ORDER BY created_at DESC
120
+ LIMIT ?
121
+ `);
122
+ return stmt2.all(cutoff, limit);
123
+ }
124
+ const stmt = db.prepare(`
125
+ SELECT id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked
126
+ FROM request_log
127
+ ORDER BY created_at DESC
128
+ LIMIT ?
129
+ `);
130
+ return stmt.all(limit);
131
+ }
132
+
133
+ // src/evolution/store.ts
134
+ import { randomUUID } from "crypto";
135
+ function initEvolutionTable(db) {
136
+ db.exec(`
137
+ CREATE TABLE IF NOT EXISTS evolution_versions (
138
+ id TEXT PRIMARY KEY,
139
+ template_name TEXT NOT NULL,
140
+ template_version TEXT NOT NULL,
141
+ publisher_agent TEXT NOT NULL,
142
+ changelog TEXT NOT NULL,
143
+ core_memory_snapshot TEXT NOT NULL,
144
+ fitness_improvement REAL NOT NULL,
145
+ timestamp TEXT NOT NULL,
146
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
147
+ );
148
+
149
+ CREATE INDEX IF NOT EXISTS evolution_template_idx
150
+ ON evolution_versions(template_name, created_at DESC);
151
+ `);
152
+ }
153
+ function insertEvolution(db, ev) {
154
+ const id = randomUUID();
155
+ const now = (/* @__PURE__ */ new Date()).toISOString();
156
+ db.prepare(`
157
+ INSERT INTO evolution_versions (
158
+ id, template_name, template_version, publisher_agent,
159
+ changelog, core_memory_snapshot, fitness_improvement, timestamp, created_at
160
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
161
+ `).run(
162
+ id,
163
+ ev.template_name,
164
+ ev.template_version,
165
+ ev.publisher_agent,
166
+ ev.changelog,
167
+ JSON.stringify(ev.core_memory_snapshot),
168
+ ev.fitness_improvement,
169
+ ev.timestamp,
170
+ now
171
+ );
172
+ return id;
173
+ }
174
+ function getLatestEvolution(db, templateName) {
175
+ const row = db.prepare(`
176
+ SELECT * FROM evolution_versions
177
+ WHERE template_name = ?
178
+ ORDER BY created_at DESC
179
+ LIMIT 1
180
+ `).get(templateName);
181
+ if (!row) return null;
182
+ return rowToEvolution(row);
183
+ }
184
+ function getEvolutionHistory(db, templateName, limit = 20) {
185
+ const rows = db.prepare(`
186
+ SELECT * FROM evolution_versions
187
+ WHERE template_name = ?
188
+ ORDER BY created_at DESC
189
+ LIMIT ?
190
+ `).all(templateName, limit);
191
+ return rows.map(rowToEvolution);
192
+ }
193
+ function rowToEvolution(row) {
194
+ return {
195
+ template_name: row["template_name"],
196
+ template_version: row["template_version"],
197
+ publisher_agent: row["publisher_agent"],
198
+ changelog: row["changelog"],
199
+ core_memory_snapshot: JSON.parse(row["core_memory_snapshot"]),
200
+ fitness_improvement: row["fitness_improvement"],
201
+ timestamp: row["timestamp"]
202
+ };
203
+ }
204
+
205
+ // src/registry/store.ts
206
+ var V2_FTS_TRIGGERS = `
207
+ DROP TRIGGER IF EXISTS cards_ai;
208
+ DROP TRIGGER IF EXISTS cards_au;
209
+ DROP TRIGGER IF EXISTS cards_ad;
210
+
211
+ CREATE TRIGGER cards_ai AFTER INSERT ON capability_cards BEGIN
212
+ INSERT INTO cards_fts(rowid, id, owner, name, description, tags)
213
+ VALUES (
214
+ new.rowid,
215
+ new.id,
216
+ new.owner,
217
+ COALESCE(
218
+ (SELECT group_concat(json_extract(value, '$.name'), ' ')
219
+ FROM json_each(json_extract(new.data, '$.skills'))),
220
+ json_extract(new.data, '$.name'),
221
+ ''
222
+ ),
223
+ COALESCE(
224
+ (SELECT group_concat(json_extract(value, '$.description'), ' ')
225
+ FROM json_each(json_extract(new.data, '$.skills'))),
226
+ json_extract(new.data, '$.description'),
227
+ ''
228
+ ),
229
+ COALESCE(
230
+ (SELECT group_concat(json_extract(value, '$.metadata.tags'), ' ')
231
+ FROM json_each(json_extract(new.data, '$.skills'))),
232
+ (SELECT group_concat(value, ' ')
233
+ FROM json_each(json_extract(new.data, '$.metadata.tags'))),
234
+ ''
235
+ )
236
+ );
237
+ END;
238
+
239
+ CREATE TRIGGER cards_au AFTER UPDATE ON capability_cards BEGIN
240
+ INSERT INTO cards_fts(cards_fts, rowid, id, owner, name, description, tags)
241
+ VALUES (
242
+ 'delete',
243
+ old.rowid,
244
+ old.id,
245
+ old.owner,
246
+ COALESCE(
247
+ (SELECT group_concat(json_extract(value, '$.name'), ' ')
248
+ FROM json_each(json_extract(old.data, '$.skills'))),
249
+ json_extract(old.data, '$.name'),
250
+ ''
251
+ ),
252
+ COALESCE(
253
+ (SELECT group_concat(json_extract(value, '$.description'), ' ')
254
+ FROM json_each(json_extract(old.data, '$.skills'))),
255
+ json_extract(old.data, '$.description'),
256
+ ''
257
+ ),
258
+ COALESCE(
259
+ (SELECT group_concat(json_extract(value, '$.metadata.tags'), ' ')
260
+ FROM json_each(json_extract(old.data, '$.skills'))),
261
+ (SELECT group_concat(value, ' ')
262
+ FROM json_each(json_extract(old.data, '$.metadata.tags'))),
263
+ ''
264
+ )
265
+ );
266
+ INSERT INTO cards_fts(rowid, id, owner, name, description, tags)
267
+ VALUES (
268
+ new.rowid,
269
+ new.id,
270
+ new.owner,
271
+ COALESCE(
272
+ (SELECT group_concat(json_extract(value, '$.name'), ' ')
273
+ FROM json_each(json_extract(new.data, '$.skills'))),
274
+ json_extract(new.data, '$.name'),
275
+ ''
276
+ ),
277
+ COALESCE(
278
+ (SELECT group_concat(json_extract(value, '$.description'), ' ')
279
+ FROM json_each(json_extract(new.data, '$.skills'))),
280
+ json_extract(new.data, '$.description'),
281
+ ''
282
+ ),
283
+ COALESCE(
284
+ (SELECT group_concat(json_extract(value, '$.metadata.tags'), ' ')
285
+ FROM json_each(json_extract(new.data, '$.skills'))),
286
+ (SELECT group_concat(value, ' ')
287
+ FROM json_each(json_extract(new.data, '$.metadata.tags'))),
288
+ ''
289
+ )
290
+ );
291
+ END;
292
+
293
+ CREATE TRIGGER cards_ad AFTER DELETE ON capability_cards BEGIN
294
+ INSERT INTO cards_fts(cards_fts, rowid, id, owner, name, description, tags)
295
+ VALUES (
296
+ 'delete',
297
+ old.rowid,
298
+ old.id,
299
+ old.owner,
300
+ COALESCE(
301
+ (SELECT group_concat(json_extract(value, '$.name'), ' ')
302
+ FROM json_each(json_extract(old.data, '$.skills'))),
303
+ json_extract(old.data, '$.name'),
304
+ ''
305
+ ),
306
+ COALESCE(
307
+ (SELECT group_concat(json_extract(value, '$.description'), ' ')
308
+ FROM json_each(json_extract(old.data, '$.skills'))),
309
+ json_extract(old.data, '$.description'),
310
+ ''
311
+ ),
312
+ COALESCE(
313
+ (SELECT group_concat(json_extract(value, '$.metadata.tags'), ' ')
314
+ FROM json_each(json_extract(old.data, '$.skills'))),
315
+ (SELECT group_concat(value, ' ')
316
+ FROM json_each(json_extract(old.data, '$.metadata.tags'))),
317
+ ''
318
+ )
319
+ );
320
+ END;
321
+ `;
322
+ function openDatabase(path = ":memory:") {
323
+ const db = new Database(path);
324
+ db.pragma("journal_mode = WAL");
325
+ db.pragma("foreign_keys = ON");
326
+ db.exec(`
327
+ CREATE TABLE IF NOT EXISTS capability_cards (
328
+ id TEXT PRIMARY KEY,
329
+ owner TEXT NOT NULL,
330
+ data TEXT NOT NULL,
331
+ created_at TEXT NOT NULL,
332
+ updated_at TEXT NOT NULL
333
+ );
334
+
335
+ CREATE TABLE IF NOT EXISTS pending_requests (
336
+ id TEXT PRIMARY KEY,
337
+ skill_query TEXT NOT NULL,
338
+ max_cost_credits REAL NOT NULL,
339
+ selected_peer TEXT,
340
+ selected_card_id TEXT,
341
+ selected_skill_id TEXT,
342
+ credits REAL NOT NULL,
343
+ status TEXT NOT NULL DEFAULT 'pending',
344
+ params TEXT,
345
+ created_at TEXT NOT NULL,
346
+ resolved_at TEXT
347
+ );
348
+
349
+ CREATE VIRTUAL TABLE IF NOT EXISTS cards_fts USING fts5(
350
+ id UNINDEXED,
351
+ owner,
352
+ name,
353
+ description,
354
+ tags,
355
+ content=""
356
+ );
357
+ `);
358
+ createRequestLogTable(db);
359
+ initFeedbackTable(db);
360
+ initEvolutionTable(db);
361
+ runMigrations(db);
362
+ return db;
363
+ }
364
+ function runMigrations(db) {
365
+ const version = db.pragma("user_version")[0]?.user_version ?? 0;
366
+ if (version < 2) {
367
+ migrateV1toV2(db);
368
+ }
369
+ }
370
+ function migrateV1toV2(db) {
371
+ const migrate = db.transaction(() => {
372
+ const rows = db.prepare("SELECT rowid, id, data FROM capability_cards").all();
373
+ const now = (/* @__PURE__ */ new Date()).toISOString();
374
+ for (const row of rows) {
375
+ const parsed = JSON.parse(row.data);
376
+ if (parsed["spec_version"] === "2.0") continue;
377
+ const v1 = parsed;
378
+ const v2 = {
379
+ spec_version: "2.0",
380
+ id: v1.id,
381
+ owner: v1.owner,
382
+ agent_name: v1.name,
383
+ skills: [
384
+ {
385
+ id: `skill-${v1.id}`,
386
+ name: v1.name,
387
+ description: v1.description,
388
+ level: v1.level,
389
+ inputs: v1.inputs,
390
+ outputs: v1.outputs,
391
+ pricing: v1.pricing,
392
+ availability: { online: v1.availability.online },
393
+ powered_by: v1.powered_by,
394
+ metadata: v1.metadata,
395
+ _internal: v1._internal
396
+ }
397
+ ],
398
+ availability: v1.availability,
399
+ created_at: v1.created_at,
400
+ updated_at: now
401
+ };
402
+ db.prepare("UPDATE capability_cards SET data = ?, updated_at = ? WHERE id = ?").run(
403
+ JSON.stringify(v2),
404
+ now,
405
+ v2.id
406
+ );
407
+ }
408
+ db.exec(V2_FTS_TRIGGERS);
409
+ db.exec(`INSERT INTO cards_fts(cards_fts) VALUES('delete-all')`);
410
+ const allRows = db.prepare("SELECT rowid, id, owner, data FROM capability_cards").all();
411
+ const ftsInsert = db.prepare(
412
+ "INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
413
+ );
414
+ for (const row of allRows) {
415
+ const data = JSON.parse(row.data);
416
+ const skills = data["skills"] ?? [];
417
+ let name;
418
+ let description;
419
+ let tags;
420
+ if (skills.length > 0) {
421
+ name = skills.map((s) => String(s["name"] ?? "")).join(" ");
422
+ description = skills.map((s) => String(s["description"] ?? "")).join(" ");
423
+ tags = skills.flatMap((s) => {
424
+ const meta = s["metadata"];
425
+ return meta?.["tags"] ?? [];
426
+ }).join(" ");
427
+ } else {
428
+ name = String(data["name"] ?? "");
429
+ description = String(data["description"] ?? "");
430
+ const meta = data["metadata"];
431
+ const rawTags = meta?.["tags"] ?? [];
432
+ tags = rawTags.join(" ");
433
+ }
434
+ ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
435
+ }
436
+ db.pragma("user_version = 2");
437
+ });
438
+ migrate();
439
+ }
440
+ function insertCard(db, card) {
441
+ const now = (/* @__PURE__ */ new Date()).toISOString();
442
+ const withTimestamps = { ...card, created_at: card.created_at ?? now, updated_at: now };
443
+ const parsed = CapabilityCardSchema.safeParse(withTimestamps);
444
+ if (!parsed.success) {
445
+ throw new AgentBnBError(
446
+ `Card validation failed: ${parsed.error.message}`,
447
+ "VALIDATION_ERROR"
448
+ );
449
+ }
450
+ const stmt = db.prepare(`
451
+ INSERT INTO capability_cards (id, owner, data, created_at, updated_at)
452
+ VALUES (?, ?, ?, ?, ?)
453
+ `);
454
+ stmt.run(
455
+ parsed.data.id,
456
+ parsed.data.owner,
457
+ JSON.stringify(parsed.data),
458
+ parsed.data.created_at ?? now,
459
+ parsed.data.updated_at ?? now
460
+ );
461
+ }
462
+ function getCard(db, id) {
463
+ const stmt = db.prepare("SELECT data FROM capability_cards WHERE id = ?");
464
+ const row = stmt.get(id);
465
+ if (!row) return null;
466
+ return JSON.parse(row.data);
467
+ }
468
+ function updateCard(db, id, owner, updates) {
469
+ const existing = getCard(db, id);
470
+ if (!existing) {
471
+ throw new AgentBnBError(`Card not found: ${id}`, "NOT_FOUND");
472
+ }
473
+ if (existing.owner !== owner) {
474
+ throw new AgentBnBError("Forbidden: you do not own this card", "FORBIDDEN");
475
+ }
476
+ const now = (/* @__PURE__ */ new Date()).toISOString();
477
+ const merged = { ...existing, ...updates, updated_at: now };
478
+ const parsed = AnyCardSchema.safeParse(merged);
479
+ if (!parsed.success) {
480
+ throw new AgentBnBError(
481
+ `Card validation failed: ${parsed.error.message}`,
482
+ "VALIDATION_ERROR"
483
+ );
484
+ }
485
+ const stmt = db.prepare(`
486
+ UPDATE capability_cards
487
+ SET data = ?, updated_at = ?
488
+ WHERE id = ?
489
+ `);
490
+ stmt.run(JSON.stringify(parsed.data), now, id);
491
+ }
492
+ function updateReputation(db, cardId, success, latencyMs) {
493
+ const existing = getCard(db, cardId);
494
+ if (!existing) return;
495
+ const ALPHA = 0.1;
496
+ const observed = success ? 1 : 0;
497
+ const prevSuccessRate = existing.metadata?.success_rate;
498
+ const prevLatency = existing.metadata?.avg_latency_ms;
499
+ const newSuccessRate = prevSuccessRate === void 0 ? observed : ALPHA * observed + (1 - ALPHA) * prevSuccessRate;
500
+ const newLatency = prevLatency === void 0 ? latencyMs : ALPHA * latencyMs + (1 - ALPHA) * prevLatency;
501
+ const now = (/* @__PURE__ */ new Date()).toISOString();
502
+ const updatedMetadata = {
503
+ ...existing.metadata,
504
+ success_rate: Math.round(newSuccessRate * 1e3) / 1e3,
505
+ avg_latency_ms: Math.round(newLatency)
506
+ };
507
+ const updatedCard = { ...existing, metadata: updatedMetadata, updated_at: now };
508
+ const stmt = db.prepare(`
509
+ UPDATE capability_cards
510
+ SET data = ?, updated_at = ?
511
+ WHERE id = ?
512
+ `);
513
+ stmt.run(JSON.stringify(updatedCard), now, cardId);
514
+ }
515
+ function updateSkillAvailability(db, cardId, skillId, online) {
516
+ const row = db.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId);
517
+ if (!row) return;
518
+ const card = JSON.parse(row.data);
519
+ const skills = card["skills"];
520
+ if (!skills) return;
521
+ const skill = skills.find((s) => s["id"] === skillId);
522
+ if (!skill) return;
523
+ const existing = skill["availability"] ?? {};
524
+ skill["availability"] = { ...existing, online };
525
+ const now = (/* @__PURE__ */ new Date()).toISOString();
526
+ db.prepare("UPDATE capability_cards SET data = ?, updated_at = ? WHERE id = ?").run(
527
+ JSON.stringify(card),
528
+ now,
529
+ cardId
530
+ );
531
+ }
532
+ function updateSkillIdleRate(db, cardId, skillId, idleRate) {
533
+ const row = db.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId);
534
+ if (!row) return;
535
+ const card = JSON.parse(row.data);
536
+ const skills = card["skills"];
537
+ if (!skills) return;
538
+ const skill = skills.find((s) => s["id"] === skillId);
539
+ if (!skill) return;
540
+ const existing = skill["_internal"] ?? {};
541
+ skill["_internal"] = {
542
+ ...existing,
543
+ idle_rate: idleRate,
544
+ idle_rate_computed_at: (/* @__PURE__ */ new Date()).toISOString()
545
+ };
546
+ const now = (/* @__PURE__ */ new Date()).toISOString();
547
+ db.prepare("UPDATE capability_cards SET data = ?, updated_at = ? WHERE id = ?").run(
548
+ JSON.stringify(card),
549
+ now,
550
+ cardId
551
+ );
552
+ }
553
+ function listCards(db, owner) {
554
+ let stmt;
555
+ let rows;
556
+ if (owner !== void 0) {
557
+ stmt = db.prepare("SELECT data FROM capability_cards WHERE owner = ?");
558
+ rows = stmt.all(owner);
559
+ } else {
560
+ stmt = db.prepare("SELECT data FROM capability_cards");
561
+ rows = stmt.all();
562
+ }
563
+ return rows.map((row) => JSON.parse(row.data));
564
+ }
565
+
566
+ // src/credit/settlement.ts
567
+ function settleProviderEarning(providerDb, providerOwner, receipt) {
568
+ recordEarning(
569
+ providerDb,
570
+ providerOwner,
571
+ receipt.amount,
572
+ receipt.card_id,
573
+ receipt.nonce
574
+ );
575
+ return { settled: true };
576
+ }
577
+ function settleRequesterEscrow(requesterDb, escrowId) {
578
+ confirmEscrowDebit(requesterDb, escrowId);
579
+ }
580
+ function releaseRequesterEscrow(requesterDb, escrowId) {
581
+ releaseEscrow(requesterDb, escrowId);
582
+ }
583
+
584
+ // src/gateway/execute.ts
585
+ async function executeCapabilityRequest(opts) {
586
+ const {
587
+ registryDb,
588
+ creditDb,
589
+ cardId,
590
+ skillId,
591
+ params,
592
+ requester,
593
+ escrowReceipt: receipt,
594
+ skillExecutor,
595
+ handlerUrl,
596
+ timeoutMs = 3e5,
597
+ onProgress,
598
+ relayAuthorized = false
599
+ } = opts;
600
+ const card = getCard(registryDb, cardId);
601
+ if (!card) {
602
+ return { success: false, error: { code: -32602, message: `Card not found: ${cardId}` } };
603
+ }
604
+ let creditsNeeded;
605
+ let cardName;
606
+ let resolvedSkillId;
607
+ const rawCard = card;
608
+ if (Array.isArray(rawCard["skills"])) {
609
+ const v2card = card;
610
+ const skill = skillId ? v2card.skills.find((s) => s.id === skillId) : v2card.skills[0];
611
+ if (!skill) {
612
+ return { success: false, error: { code: -32602, message: `Skill not found: ${skillId}` } };
613
+ }
614
+ creditsNeeded = skill.pricing.credits_per_call;
615
+ cardName = skill.name;
616
+ resolvedSkillId = skill.id;
617
+ } else {
618
+ creditsNeeded = card.pricing.credits_per_call;
619
+ cardName = card.name;
620
+ }
621
+ let escrowId = null;
622
+ let isRemoteEscrow = false;
623
+ if (relayAuthorized) {
624
+ } else if (receipt) {
625
+ const { signature, ...receiptData2 } = receipt;
626
+ const publicKeyBuf = Buffer.from(receipt.requester_public_key, "hex");
627
+ const valid = verifyEscrowReceipt(receiptData2, signature, publicKeyBuf);
628
+ if (!valid) {
629
+ return { success: false, error: { code: -32603, message: "Invalid escrow receipt signature" } };
630
+ }
631
+ if (receipt.amount < creditsNeeded) {
632
+ return { success: false, error: { code: -32603, message: "Insufficient escrow amount" } };
633
+ }
634
+ const receiptAge = Date.now() - new Date(receipt.timestamp).getTime();
635
+ if (receiptAge > 5 * 60 * 1e3) {
636
+ return { success: false, error: { code: -32603, message: "Escrow receipt expired" } };
637
+ }
638
+ isRemoteEscrow = true;
639
+ } else {
640
+ try {
641
+ const balance = getBalance(creditDb, requester);
642
+ if (balance < creditsNeeded) {
643
+ return { success: false, error: { code: -32603, message: "Insufficient credits" } };
644
+ }
645
+ escrowId = holdEscrow(creditDb, requester, creditsNeeded, cardId);
646
+ } catch (err) {
647
+ const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
648
+ return { success: false, error: { code: -32603, message: msg } };
649
+ }
650
+ }
651
+ const startMs = Date.now();
652
+ const receiptData = isRemoteEscrow ? { receipt_released: true } : void 0;
653
+ const handleFailure = (status, latencyMs, message) => {
654
+ if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
655
+ updateReputation(registryDb, cardId, false, latencyMs);
656
+ try {
657
+ insertRequestLog(registryDb, {
658
+ id: randomUUID2(),
659
+ card_id: cardId,
660
+ card_name: cardName,
661
+ skill_id: resolvedSkillId,
662
+ requester,
663
+ status,
664
+ latency_ms: latencyMs,
665
+ credits_charged: 0,
666
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
667
+ });
668
+ } catch {
669
+ }
670
+ return {
671
+ success: false,
672
+ error: { code: -32603, message, ...receiptData ? { data: receiptData } : {} }
673
+ };
674
+ };
675
+ const handleSuccess = (result, latencyMs) => {
676
+ if (isRemoteEscrow && receipt) {
677
+ settleProviderEarning(creditDb, card.owner, receipt);
678
+ } else if (escrowId) {
679
+ settleEscrow(creditDb, escrowId, card.owner);
680
+ }
681
+ updateReputation(registryDb, cardId, true, latencyMs);
682
+ try {
683
+ insertRequestLog(registryDb, {
684
+ id: randomUUID2(),
685
+ card_id: cardId,
686
+ card_name: cardName,
687
+ skill_id: resolvedSkillId,
688
+ requester,
689
+ status: "success",
690
+ latency_ms: latencyMs,
691
+ credits_charged: creditsNeeded,
692
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
693
+ });
694
+ } catch {
695
+ }
696
+ const successResult = isRemoteEscrow ? {
697
+ ...typeof result === "object" && result !== null ? result : { data: result },
698
+ receipt_settled: true,
699
+ receipt_nonce: receipt.nonce
700
+ } : result;
701
+ return { success: true, result: successResult };
702
+ };
703
+ if (skillExecutor) {
704
+ const targetSkillId = resolvedSkillId ?? skillId ?? cardId;
705
+ try {
706
+ const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
707
+ if (!execResult.success) {
708
+ return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed");
709
+ }
710
+ return handleSuccess(execResult.result, execResult.latency_ms);
711
+ } catch (err) {
712
+ const message = err instanceof Error ? err.message : "Execution error";
713
+ return handleFailure("failure", Date.now() - startMs, message);
714
+ }
715
+ }
716
+ if (!handlerUrl) {
717
+ return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured");
718
+ }
719
+ const controller = new AbortController();
720
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
721
+ try {
722
+ const response = await fetch(handlerUrl, {
723
+ method: "POST",
724
+ headers: { "Content-Type": "application/json" },
725
+ body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
726
+ signal: controller.signal
727
+ });
728
+ clearTimeout(timer);
729
+ if (!response.ok) {
730
+ return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`);
731
+ }
732
+ const result = await response.json();
733
+ return handleSuccess(result, Date.now() - startMs);
734
+ } catch (err) {
735
+ clearTimeout(timer);
736
+ const isTimeout = err instanceof Error && err.name === "AbortError";
737
+ return handleFailure(
738
+ isTimeout ? "timeout" : "failure",
739
+ Date.now() - startMs,
740
+ isTimeout ? "Execution timeout" : "Handler error"
741
+ );
742
+ }
743
+ }
744
+ async function executeCapabilityBatch(options) {
745
+ const { requests, strategy, total_budget, registryDb, creditDb, owner } = options;
746
+ if (requests.length === 0) {
747
+ return { results: [], total_credits_spent: 0, total_credits_refunded: 0, success: true };
748
+ }
749
+ const sumMaxCredits = requests.reduce((acc, r) => acc + r.max_credits, 0);
750
+ if (sumMaxCredits > total_budget) {
751
+ return {
752
+ results: requests.map((_, i) => ({
753
+ request_index: i,
754
+ status: "skipped",
755
+ credits_spent: 0,
756
+ credits_refunded: 0,
757
+ error: `Total requested credits (${sumMaxCredits}) exceeds total_budget (${total_budget})`
758
+ })),
759
+ total_credits_spent: 0,
760
+ total_credits_refunded: 0,
761
+ success: false
762
+ };
763
+ }
764
+ const executeItem = async (item, index) => {
765
+ const card = getCard(registryDb, item.skill_id);
766
+ if (!card) {
767
+ return {
768
+ request_index: index,
769
+ status: "failed",
770
+ credits_spent: 0,
771
+ credits_refunded: 0,
772
+ error: `Card/skill not found: ${item.skill_id}`
773
+ };
774
+ }
775
+ const rawCard = card;
776
+ let creditsNeeded;
777
+ let resolvedSkillId;
778
+ if (Array.isArray(rawCard["skills"])) {
779
+ const v2card = card;
780
+ const skill = v2card.skills[0];
781
+ if (!skill) {
782
+ return {
783
+ request_index: index,
784
+ status: "failed",
785
+ credits_spent: 0,
786
+ credits_refunded: 0,
787
+ error: `No skills defined on card: ${item.skill_id}`
788
+ };
789
+ }
790
+ creditsNeeded = skill.pricing.credits_per_call;
791
+ resolvedSkillId = skill.id;
792
+ } else {
793
+ creditsNeeded = card.pricing.credits_per_call;
794
+ }
795
+ if (creditsNeeded > item.max_credits) {
796
+ return {
797
+ request_index: index,
798
+ status: "failed",
799
+ credits_spent: 0,
800
+ credits_refunded: 0,
801
+ error: `Skill costs ${creditsNeeded} credits but max_credits is ${item.max_credits}`
802
+ };
803
+ }
804
+ let escrowId;
805
+ try {
806
+ const balance = getBalance(creditDb, owner);
807
+ if (balance < creditsNeeded) {
808
+ return {
809
+ request_index: index,
810
+ status: "failed",
811
+ credits_spent: 0,
812
+ credits_refunded: 0,
813
+ error: "Insufficient credits"
814
+ };
815
+ }
816
+ escrowId = holdEscrow(creditDb, owner, creditsNeeded, card.id);
817
+ } catch (err) {
818
+ const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
819
+ return {
820
+ request_index: index,
821
+ status: "failed",
822
+ credits_spent: 0,
823
+ credits_refunded: 0,
824
+ error: msg
825
+ };
826
+ }
827
+ const startMs = Date.now();
828
+ const latencyMs = Date.now() - startMs;
829
+ settleEscrow(creditDb, escrowId, card.owner);
830
+ updateReputation(registryDb, card.id, true, latencyMs);
831
+ try {
832
+ insertRequestLog(registryDb, {
833
+ id: randomUUID2(),
834
+ card_id: card.id,
835
+ card_name: card.name,
836
+ skill_id: resolvedSkillId,
837
+ requester: owner,
838
+ status: "success",
839
+ latency_ms: latencyMs,
840
+ credits_charged: creditsNeeded,
841
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
842
+ });
843
+ } catch {
844
+ }
845
+ return {
846
+ request_index: index,
847
+ status: "success",
848
+ result: { card_id: card.id, skill_id: resolvedSkillId },
849
+ credits_spent: creditsNeeded,
850
+ credits_refunded: 0
851
+ };
852
+ };
853
+ let results;
854
+ if (strategy === "sequential") {
855
+ results = [];
856
+ let stopped = false;
857
+ for (let i = 0; i < requests.length; i++) {
858
+ if (stopped) {
859
+ results.push({
860
+ request_index: i,
861
+ status: "skipped",
862
+ credits_spent: 0,
863
+ credits_refunded: 0,
864
+ error: "Skipped due to earlier failure"
865
+ });
866
+ continue;
867
+ }
868
+ const result = await executeItem(requests[i], i);
869
+ results.push(result);
870
+ if (result.status === "failed") {
871
+ stopped = true;
872
+ }
873
+ }
874
+ } else {
875
+ const settled = await Promise.allSettled(
876
+ requests.map((item, i) => executeItem(item, i))
877
+ );
878
+ results = settled.map((outcome, i) => {
879
+ if (outcome.status === "fulfilled") {
880
+ return outcome.value;
881
+ }
882
+ return {
883
+ request_index: i,
884
+ status: "failed",
885
+ credits_spent: 0,
886
+ credits_refunded: 0,
887
+ error: outcome.reason instanceof Error ? outcome.reason.message : "Unknown error"
888
+ };
889
+ });
890
+ }
891
+ const total_credits_spent = results.reduce((acc, r) => acc + r.credits_spent, 0);
892
+ const total_credits_refunded = results.reduce((acc, r) => acc + r.credits_refunded, 0);
893
+ const success = results.every((r) => r.status === "success");
894
+ return { results, total_credits_spent, total_credits_refunded, success };
895
+ }
896
+
897
+ export {
898
+ insertRequestLog,
899
+ getSkillRequestCount,
900
+ getActivityFeed,
901
+ getRequestLog,
902
+ insertEvolution,
903
+ getLatestEvolution,
904
+ getEvolutionHistory,
905
+ openDatabase,
906
+ insertCard,
907
+ getCard,
908
+ updateCard,
909
+ updateSkillAvailability,
910
+ updateSkillIdleRate,
911
+ listCards,
912
+ settleRequesterEscrow,
913
+ releaseRequesterEscrow,
914
+ executeCapabilityRequest,
915
+ executeCapabilityBatch
916
+ };