agentbnb 5.1.11 → 7.0.0-beta.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 (60) hide show
  1. package/README.md +245 -39
  2. package/dist/{card-RSGDCHCV.js → card-REW7BSWW.js} +1 -1
  3. package/dist/{chunk-FLY3WIQR.js → chunk-2HSUPCBT.js} +3 -3
  4. package/dist/{chunk-WGZ5AGOX.js → chunk-3CIMVISQ.js} +24 -1
  5. package/dist/{chunk-NH2FIERR.js → chunk-574W3HHE.js} +1 -1
  6. package/dist/{chunk-WTXRY7R2.js → chunk-APEG4QIN.js} +157 -9
  7. package/dist/chunk-BP3L2TET.js +148 -0
  8. package/dist/{chunk-NLAWT4DT.js → chunk-CWYPTQRQ.js} +7 -7
  9. package/dist/{chunk-UKT6H7YT.js → chunk-DUW6RX6I.js} +5 -2
  10. package/dist/chunk-EAD4A4KG.js +430 -0
  11. package/dist/{chunk-QT7TEVNV.js → chunk-EHSHB7TY.js} +23 -1
  12. package/dist/{chunk-B5FTAGFN.js → chunk-ETGOKDFR.js} +75 -75
  13. package/dist/{chunk-5KFI5X7B.js → chunk-F53QQIM2.js} +1 -1
  14. package/dist/{chunk-MLS6IGGG.js → chunk-FK2MDNTB.js} +117 -117
  15. package/dist/{chunk-EGUOAHCW.js → chunk-GO4FVRVN.js} +15 -13
  16. package/dist/{chunk-CRFCWD6V.js → chunk-J2K5S5MX.js} +136 -173
  17. package/dist/chunk-K5FO42YF.js +1136 -0
  18. package/dist/{chunk-DFBX3BBD.js → chunk-KA2VIEGM.js} +211 -16
  19. package/dist/chunk-NWIQJ2CL.js +108 -0
  20. package/dist/chunk-OCSU2S6W.js +168 -0
  21. package/dist/{chunk-QQFBFV4V.js → chunk-PGDBUUGR.js} +60 -19
  22. package/dist/{chunk-QITOPASZ.js → chunk-PSQHUZ7X.js} +1 -1
  23. package/dist/{chunk-C6KPAFCC.js → chunk-PU7LXOQ3.js} +23 -1
  24. package/dist/{chunk-JOY533UH.js → chunk-TW65F5EU.js} +1 -1
  25. package/dist/{chunk-ZX5623ER.js → chunk-VMH2YS2I.js} +1 -1
  26. package/dist/{chunk-XND2DWTZ.js → chunk-VPQ44XKE.js} +2 -2
  27. package/dist/{chunk-CSATDXZC.js → chunk-Y7T6IMM3.js} +1 -1
  28. package/dist/cli/index.js +755 -379
  29. package/dist/{client-T5MTY3CS.js → client-HRYRJKSA.js} +3 -3
  30. package/dist/{conduct-WU3VEXB6.js → conduct-JNYJCDHQ.js} +14 -13
  31. package/dist/conduct-KJUD2RTB.js +22 -0
  32. package/dist/{conductor-mode-ZMTFZGJP.js → conductor-mode-2VVFMKVE.js} +313 -14
  33. package/dist/conductor-mode-VGUU54QI.js +276 -0
  34. package/dist/execute-I4PKSNJM.js +12 -0
  35. package/dist/execute-MOXSSA3Q.js +15 -0
  36. package/dist/index.d.ts +795 -2
  37. package/dist/index.js +861 -111
  38. package/dist/{process-guard-CC7CNRQJ.js → process-guard-QCCBGILS.js} +1 -1
  39. package/dist/publish-capability-TS6CNR5G.js +12 -0
  40. package/dist/reliability-metrics-QG7WC5QK.js +18 -0
  41. package/dist/{request-VOXBFUOG.js → request-E7TA7COA.js} +19 -18
  42. package/dist/{serve-skill-IH7UAJNR.js → serve-skill-HIOWYKRU.js} +13 -11
  43. package/dist/{server-JVQW2TID.js → server-I63CXFX3.js} +17 -16
  44. package/dist/{service-coordinator-EYRDTHL5.js → service-coordinator-XBNT3SMU.js} +369 -260
  45. package/dist/skill-config-FETXPNVP.js +22 -0
  46. package/dist/skills/agentbnb/bootstrap.js +430 -84
  47. package/dist/websocket-client-5MH6QRJK.js +7 -0
  48. package/dist/{websocket-client-WRN3HO73.js → websocket-client-PFGVTXNE.js} +1 -1
  49. package/openclaw.plugin.json +2 -2
  50. package/package.json +2 -1
  51. package/skills/agentbnb/SKILL.md +35 -0
  52. package/skills/agentbnb/bootstrap.ts +126 -8
  53. package/skills/agentbnb/install.sh +49 -9
  54. package/dist/chunk-EANI2N2V.js +0 -309
  55. package/dist/chunk-EPIWHNB2.js +0 -946
  56. package/dist/conduct-6LKIJJKQ.js +0 -21
  57. package/dist/conductor-mode-Q4IIDY5E.js +0 -123
  58. package/dist/execute-4D4ITQCL.js +0 -10
  59. package/dist/execute-T7Y6RKSW.js +0 -13
  60. package/dist/websocket-client-6IIDGXKB.js +0 -7
@@ -0,0 +1,148 @@
1
+ import {
2
+ insertCard
3
+ } from "./chunk-KA2VIEGM.js";
4
+ import {
5
+ CapabilityCardSchema
6
+ } from "./chunk-3CIMVISQ.js";
7
+
8
+ // src/skills/publish-capability.ts
9
+ import { randomUUID } from "crypto";
10
+ function parseSoulMd(content) {
11
+ const lines = content.split("\n");
12
+ let name = "";
13
+ let description = "";
14
+ const capabilities = [];
15
+ const unknownSections = [];
16
+ let currentSection = null;
17
+ let currentCapabilityName = "";
18
+ let currentCapabilityLines = [];
19
+ let currentCapabilityPricing = void 0;
20
+ let descriptionLines = [];
21
+ let pastFirstH1 = false;
22
+ let pastFirstH2 = false;
23
+ const flushCapability = () => {
24
+ if (currentCapabilityName) {
25
+ const cap = {
26
+ name: currentCapabilityName,
27
+ description: currentCapabilityLines.join(" ").trim()
28
+ };
29
+ if (currentCapabilityPricing !== void 0) {
30
+ cap.pricing = currentCapabilityPricing;
31
+ }
32
+ capabilities.push(cap);
33
+ currentCapabilityName = "";
34
+ currentCapabilityLines = [];
35
+ currentCapabilityPricing = void 0;
36
+ }
37
+ };
38
+ for (const line of lines) {
39
+ const trimmed = line.trim();
40
+ if (/^# /.test(trimmed) && !pastFirstH1) {
41
+ name = trimmed.slice(2).trim();
42
+ pastFirstH1 = true;
43
+ currentSection = "preamble";
44
+ continue;
45
+ }
46
+ if (/^## /.test(trimmed)) {
47
+ flushCapability();
48
+ const capName = trimmed.slice(3).trim();
49
+ currentCapabilityName = capName;
50
+ currentSection = "capability";
51
+ pastFirstH2 = true;
52
+ continue;
53
+ }
54
+ if (/^#{3,} /.test(trimmed)) {
55
+ const sectionName = trimmed.replace(/^#+\s*/, "");
56
+ if (!unknownSections.includes(sectionName)) {
57
+ unknownSections.push(sectionName);
58
+ }
59
+ continue;
60
+ }
61
+ if (trimmed === "") continue;
62
+ if (currentSection === "preamble" && !pastFirstH2) {
63
+ descriptionLines.push(trimmed);
64
+ } else if (currentSection === "capability") {
65
+ const pricingMatch = trimmed.match(/^pricing:\s*(\d+(?:\.\d+)?)$/i);
66
+ if (pricingMatch) {
67
+ const val = parseFloat(pricingMatch[1]);
68
+ if (!isNaN(val) && val >= 0) {
69
+ currentCapabilityPricing = val;
70
+ }
71
+ } else {
72
+ currentCapabilityLines.push(trimmed);
73
+ }
74
+ }
75
+ }
76
+ flushCapability();
77
+ if (descriptionLines.length > 0) {
78
+ description = descriptionLines[0] ?? "";
79
+ }
80
+ return {
81
+ name,
82
+ description,
83
+ level: 2,
84
+ capabilities,
85
+ unknownSections
86
+ };
87
+ }
88
+ function publishFromSoul(db, soulContent, owner) {
89
+ const parsed = parseSoulMd(soulContent);
90
+ const capsSummary = parsed.capabilities.map((c) => c.name).join(", ");
91
+ const description = parsed.description.length > 0 ? parsed.description.slice(0, 500) : capsSummary.slice(0, 500);
92
+ const card = {
93
+ spec_version: "1.0",
94
+ id: randomUUID(),
95
+ owner,
96
+ name: parsed.name || "Unknown Agent",
97
+ description,
98
+ level: parsed.level,
99
+ inputs: [
100
+ {
101
+ name: "input",
102
+ type: "text",
103
+ description: "Input for the capability",
104
+ required: true
105
+ }
106
+ ],
107
+ outputs: [
108
+ {
109
+ name: "output",
110
+ type: "text",
111
+ description: "Output from the capability",
112
+ required: true
113
+ }
114
+ ],
115
+ pricing: {
116
+ credits_per_call: 10
117
+ },
118
+ availability: {
119
+ online: true
120
+ },
121
+ metadata: {
122
+ tags: parsed.capabilities.map((c) => c.name.toLowerCase().replace(/\s+/g, "-"))
123
+ }
124
+ };
125
+ CapabilityCardSchema.parse(card);
126
+ insertCard(db, card);
127
+ return card;
128
+ }
129
+ function skillConfigToSkill(config) {
130
+ return {
131
+ id: config.id,
132
+ name: config.name,
133
+ description: config.description ?? "",
134
+ level: 2,
135
+ inputs: [],
136
+ outputs: [],
137
+ pricing: config.pricing,
138
+ ...config.capability_types !== void 0 && { capability_types: config.capability_types },
139
+ ...config.requires_capabilities !== void 0 && { requires_capabilities: config.requires_capabilities },
140
+ ...config.visibility !== void 0 && { visibility: config.visibility }
141
+ };
142
+ }
143
+
144
+ export {
145
+ parseSoulMd,
146
+ publishFromSoul,
147
+ skillConfigToSkill
148
+ };
@@ -1,16 +1,19 @@
1
1
  import {
2
2
  RelayClient
3
- } from "./chunk-JOY533UH.js";
3
+ } from "./chunk-TW65F5EU.js";
4
4
  import {
5
5
  BudgetController,
6
6
  ORCHESTRATION_FEE,
7
7
  decompose,
8
8
  matchSubTasks,
9
9
  orchestrate
10
- } from "./chunk-WTXRY7R2.js";
10
+ } from "./chunk-APEG4QIN.js";
11
11
  import {
12
12
  BudgetManager
13
- } from "./chunk-EGUOAHCW.js";
13
+ } from "./chunk-GO4FVRVN.js";
14
+ import {
15
+ openCreditDb
16
+ } from "./chunk-J2K5S5MX.js";
14
17
  import {
15
18
  loadPeers
16
19
  } from "./chunk-5AH3CMOX.js";
@@ -19,10 +22,7 @@ import {
19
22
  } from "./chunk-75OC6E4F.js";
20
23
  import {
21
24
  openDatabase
22
- } from "./chunk-DFBX3BBD.js";
23
- import {
24
- openCreditDb
25
- } from "./chunk-EANI2N2V.js";
25
+ } from "./chunk-KA2VIEGM.js";
26
26
 
27
27
  // src/cli/conduct.ts
28
28
  async function conductAction(task, opts) {
@@ -1,15 +1,18 @@
1
1
  import {
2
+ NETWORK_FEE_RATE,
2
3
  confirmEscrowDebit,
3
4
  recordEarning,
4
5
  releaseEscrow
5
- } from "./chunk-EANI2N2V.js";
6
+ } from "./chunk-J2K5S5MX.js";
6
7
 
7
8
  // src/credit/settlement.ts
8
9
  function settleProviderEarning(providerDb, providerOwner, receipt) {
10
+ const feeAmount = Math.floor(receipt.amount * NETWORK_FEE_RATE);
11
+ const providerAmount = receipt.amount - feeAmount;
9
12
  recordEarning(
10
13
  providerDb,
11
14
  providerOwner,
12
- receipt.amount,
15
+ providerAmount,
13
16
  receipt.card_id,
14
17
  receipt.nonce
15
18
  );
@@ -0,0 +1,430 @@
1
+ import {
2
+ NETWORK_FEE_RATE,
3
+ confirmEscrowDebit,
4
+ getBalance,
5
+ getCard,
6
+ holdEscrow,
7
+ insertRequestLog,
8
+ recordEarning,
9
+ releaseEscrow,
10
+ settleEscrow,
11
+ updateReputation,
12
+ verifyEscrowReceipt
13
+ } from "./chunk-K5FO42YF.js";
14
+ import {
15
+ loadConfig
16
+ } from "./chunk-IVOYM3WG.js";
17
+ import {
18
+ AgentBnBError
19
+ } from "./chunk-3CIMVISQ.js";
20
+
21
+ // src/gateway/execute.ts
22
+ import { randomUUID } from "crypto";
23
+
24
+ // src/credit/settlement.ts
25
+ function settleProviderEarning(providerDb, providerOwner, receipt) {
26
+ const feeAmount = Math.floor(receipt.amount * NETWORK_FEE_RATE);
27
+ const providerAmount = receipt.amount - feeAmount;
28
+ recordEarning(
29
+ providerDb,
30
+ providerOwner,
31
+ providerAmount,
32
+ receipt.card_id,
33
+ receipt.nonce
34
+ );
35
+ return { settled: true };
36
+ }
37
+ function settleRequesterEscrow(requesterDb, escrowId) {
38
+ confirmEscrowDebit(requesterDb, escrowId);
39
+ }
40
+ function releaseRequesterEscrow(requesterDb, escrowId) {
41
+ releaseEscrow(requesterDb, escrowId);
42
+ }
43
+
44
+ // src/gateway/execute.ts
45
+ async function notifyTelegramSkillExecuted(opts) {
46
+ const cfg = loadConfig();
47
+ if (!cfg?.telegram_notifications) return;
48
+ const token = cfg.telegram_bot_token ?? process.env["TELEGRAM_BOT_TOKEN"];
49
+ const chatId = cfg.telegram_chat_id ?? process.env["TELEGRAM_CHAT_ID"];
50
+ if (!token || !chatId) return;
51
+ const balance = getBalance(opts.creditDb, opts.owner);
52
+ const skillLabel = opts.skillId ? `${opts.skillName} (${opts.skillId})` : opts.skillName;
53
+ const text = [
54
+ "[AgentBnB] Skill executed",
55
+ `Skill: ${skillLabel}`,
56
+ `Requester: ${opts.requester}`,
57
+ `Earned: +${opts.creditsEarned} credits`,
58
+ `Balance: ${balance} credits`,
59
+ `Latency: ${opts.latencyMs}ms`
60
+ ].join("\n");
61
+ await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify({ chat_id: chatId, text })
65
+ });
66
+ }
67
+ async function executeCapabilityRequest(opts) {
68
+ const {
69
+ registryDb,
70
+ creditDb,
71
+ cardId,
72
+ skillId,
73
+ params,
74
+ requester,
75
+ escrowReceipt: receipt,
76
+ skillExecutor,
77
+ handlerUrl,
78
+ timeoutMs = 3e5,
79
+ onProgress,
80
+ relayAuthorized = false
81
+ } = opts;
82
+ const card = getCard(registryDb, cardId);
83
+ if (!card) {
84
+ return { success: false, error: { code: -32602, message: `Card not found: ${cardId}` } };
85
+ }
86
+ if (requester === card.owner && !relayAuthorized) {
87
+ const msg = `Self-request blocked: requester (${requester}) is the card owner. Set AGENTBNB_DIR to your agent's config directory before calling agentbnb request.`;
88
+ try {
89
+ insertRequestLog(registryDb, {
90
+ id: randomUUID(),
91
+ card_id: cardId,
92
+ card_name: card.name,
93
+ skill_id: skillId,
94
+ requester,
95
+ status: "failure",
96
+ latency_ms: 0,
97
+ credits_charged: 0,
98
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
99
+ failure_reason: "auth_error"
100
+ });
101
+ } catch {
102
+ }
103
+ return { success: false, error: { code: -32603, message: msg } };
104
+ }
105
+ let creditsNeeded;
106
+ let cardName;
107
+ let resolvedSkillId;
108
+ const rawCard = card;
109
+ if (Array.isArray(rawCard["skills"])) {
110
+ const v2card = card;
111
+ const skill = skillId ? v2card.skills.find((s) => s.id === skillId) : v2card.skills[0];
112
+ if (!skill) {
113
+ return { success: false, error: { code: -32602, message: `Skill not found: ${skillId}` } };
114
+ }
115
+ creditsNeeded = skill.pricing.credits_per_call;
116
+ cardName = skill.name;
117
+ resolvedSkillId = skill.id;
118
+ } else {
119
+ creditsNeeded = card.pricing.credits_per_call;
120
+ cardName = card.name;
121
+ }
122
+ let escrowId = null;
123
+ let isRemoteEscrow = false;
124
+ if (relayAuthorized) {
125
+ } else if (receipt) {
126
+ const { signature, ...receiptData2 } = receipt;
127
+ const publicKeyBuf = Buffer.from(receipt.requester_public_key, "hex");
128
+ const valid = verifyEscrowReceipt(receiptData2, signature, publicKeyBuf);
129
+ if (!valid) {
130
+ return { success: false, error: { code: -32603, message: "Invalid escrow receipt signature" } };
131
+ }
132
+ if (receipt.amount < creditsNeeded) {
133
+ return { success: false, error: { code: -32603, message: "Insufficient escrow amount" } };
134
+ }
135
+ const receiptAge = Date.now() - new Date(receipt.timestamp).getTime();
136
+ if (receiptAge > 5 * 60 * 1e3) {
137
+ return { success: false, error: { code: -32603, message: "Escrow receipt expired" } };
138
+ }
139
+ isRemoteEscrow = true;
140
+ } else {
141
+ try {
142
+ const balance = getBalance(creditDb, requester);
143
+ if (balance < creditsNeeded) {
144
+ return { success: false, error: { code: -32603, message: "Insufficient credits" } };
145
+ }
146
+ escrowId = holdEscrow(creditDb, requester, creditsNeeded, cardId);
147
+ } catch (err) {
148
+ const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
149
+ return { success: false, error: { code: -32603, message: msg } };
150
+ }
151
+ }
152
+ const startMs = Date.now();
153
+ const receiptData = isRemoteEscrow ? { receipt_released: true } : void 0;
154
+ const handleFailure = (status, latencyMs, message, failureReason = "bad_execution") => {
155
+ if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
156
+ if (failureReason === "bad_execution" || failureReason === "auth_error") {
157
+ updateReputation(registryDb, cardId, false, latencyMs);
158
+ }
159
+ try {
160
+ insertRequestLog(registryDb, {
161
+ id: randomUUID(),
162
+ card_id: cardId,
163
+ card_name: cardName,
164
+ skill_id: resolvedSkillId,
165
+ requester,
166
+ status,
167
+ latency_ms: latencyMs,
168
+ credits_charged: 0,
169
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
170
+ failure_reason: failureReason
171
+ });
172
+ } catch {
173
+ }
174
+ return {
175
+ success: false,
176
+ error: { code: -32603, message, ...receiptData ? { data: receiptData } : {} }
177
+ };
178
+ };
179
+ const handleSuccess = (result, latencyMs) => {
180
+ if (isRemoteEscrow && receipt) {
181
+ settleProviderEarning(creditDb, card.owner, receipt);
182
+ } else if (escrowId) {
183
+ settleEscrow(creditDb, escrowId, card.owner);
184
+ }
185
+ updateReputation(registryDb, cardId, true, latencyMs);
186
+ try {
187
+ insertRequestLog(registryDb, {
188
+ id: randomUUID(),
189
+ card_id: cardId,
190
+ card_name: cardName,
191
+ skill_id: resolvedSkillId,
192
+ requester,
193
+ status: "success",
194
+ latency_ms: latencyMs,
195
+ credits_charged: creditsNeeded,
196
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
197
+ });
198
+ } catch {
199
+ }
200
+ notifyTelegramSkillExecuted({
201
+ creditDb,
202
+ owner: card.owner,
203
+ skillName: cardName,
204
+ skillId: resolvedSkillId ?? null,
205
+ requester,
206
+ creditsEarned: creditsNeeded,
207
+ latencyMs
208
+ }).catch(() => {
209
+ });
210
+ const successResult = isRemoteEscrow ? {
211
+ ...typeof result === "object" && result !== null ? result : { data: result },
212
+ receipt_settled: true,
213
+ receipt_nonce: receipt.nonce
214
+ } : result;
215
+ return { success: true, result: successResult };
216
+ };
217
+ if (skillExecutor) {
218
+ let targetSkillId = resolvedSkillId ?? skillId;
219
+ if (!targetSkillId) {
220
+ const available = skillExecutor.listSkills();
221
+ if (available.length > 0) {
222
+ targetSkillId = available[0];
223
+ } else {
224
+ return handleFailure(
225
+ "failure",
226
+ Date.now() - startMs,
227
+ "No skill_id specified and no skills registered on this provider.",
228
+ "not_found"
229
+ );
230
+ }
231
+ }
232
+ try {
233
+ const execResult = await skillExecutor.execute(targetSkillId, params, onProgress);
234
+ if (!execResult.success) {
235
+ return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed", "bad_execution");
236
+ }
237
+ return handleSuccess(execResult.result, execResult.latency_ms);
238
+ } catch (err) {
239
+ const message = err instanceof Error ? err.message : "Execution error";
240
+ return handleFailure("failure", Date.now() - startMs, message, "bad_execution");
241
+ }
242
+ }
243
+ if (!handlerUrl) {
244
+ return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured", "bad_execution");
245
+ }
246
+ const controller = new AbortController();
247
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
248
+ try {
249
+ const response = await fetch(handlerUrl, {
250
+ method: "POST",
251
+ headers: { "Content-Type": "application/json" },
252
+ body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
253
+ signal: controller.signal
254
+ });
255
+ clearTimeout(timer);
256
+ if (!response.ok) {
257
+ return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`, "bad_execution");
258
+ }
259
+ const result = await response.json();
260
+ return handleSuccess(result, Date.now() - startMs);
261
+ } catch (err) {
262
+ clearTimeout(timer);
263
+ const isTimeout = err instanceof Error && err.name === "AbortError";
264
+ return handleFailure(
265
+ isTimeout ? "timeout" : "failure",
266
+ Date.now() - startMs,
267
+ isTimeout ? "Execution timeout" : "Handler error",
268
+ isTimeout ? "timeout" : "bad_execution"
269
+ );
270
+ }
271
+ }
272
+ async function executeCapabilityBatch(options) {
273
+ const { requests, strategy, total_budget, registryDb, creditDb, owner } = options;
274
+ if (requests.length === 0) {
275
+ return { results: [], total_credits_spent: 0, total_credits_refunded: 0, success: true };
276
+ }
277
+ const sumMaxCredits = requests.reduce((acc, r) => acc + r.max_credits, 0);
278
+ if (sumMaxCredits > total_budget) {
279
+ return {
280
+ results: requests.map((_, i) => ({
281
+ request_index: i,
282
+ status: "skipped",
283
+ credits_spent: 0,
284
+ credits_refunded: 0,
285
+ error: `Total requested credits (${sumMaxCredits}) exceeds total_budget (${total_budget})`
286
+ })),
287
+ total_credits_spent: 0,
288
+ total_credits_refunded: 0,
289
+ success: false
290
+ };
291
+ }
292
+ const executeItem = async (item, index) => {
293
+ const card = getCard(registryDb, item.skill_id);
294
+ if (!card) {
295
+ return {
296
+ request_index: index,
297
+ status: "failed",
298
+ credits_spent: 0,
299
+ credits_refunded: 0,
300
+ error: `Card/skill not found: ${item.skill_id}`
301
+ };
302
+ }
303
+ const rawCard = card;
304
+ let creditsNeeded;
305
+ let resolvedSkillId;
306
+ if (Array.isArray(rawCard["skills"])) {
307
+ const v2card = card;
308
+ const skill = v2card.skills[0];
309
+ if (!skill) {
310
+ return {
311
+ request_index: index,
312
+ status: "failed",
313
+ credits_spent: 0,
314
+ credits_refunded: 0,
315
+ error: `No skills defined on card: ${item.skill_id}`
316
+ };
317
+ }
318
+ creditsNeeded = skill.pricing.credits_per_call;
319
+ resolvedSkillId = skill.id;
320
+ } else {
321
+ creditsNeeded = card.pricing.credits_per_call;
322
+ }
323
+ if (creditsNeeded > item.max_credits) {
324
+ return {
325
+ request_index: index,
326
+ status: "failed",
327
+ credits_spent: 0,
328
+ credits_refunded: 0,
329
+ error: `Skill costs ${creditsNeeded} credits but max_credits is ${item.max_credits}`
330
+ };
331
+ }
332
+ let escrowId;
333
+ try {
334
+ const balance = getBalance(creditDb, owner);
335
+ if (balance < creditsNeeded) {
336
+ return {
337
+ request_index: index,
338
+ status: "failed",
339
+ credits_spent: 0,
340
+ credits_refunded: 0,
341
+ error: "Insufficient credits"
342
+ };
343
+ }
344
+ escrowId = holdEscrow(creditDb, owner, creditsNeeded, card.id);
345
+ } catch (err) {
346
+ const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
347
+ return {
348
+ request_index: index,
349
+ status: "failed",
350
+ credits_spent: 0,
351
+ credits_refunded: 0,
352
+ error: msg
353
+ };
354
+ }
355
+ const startMs = Date.now();
356
+ const latencyMs = Date.now() - startMs;
357
+ settleEscrow(creditDb, escrowId, card.owner);
358
+ updateReputation(registryDb, card.id, true, latencyMs);
359
+ try {
360
+ insertRequestLog(registryDb, {
361
+ id: randomUUID(),
362
+ card_id: card.id,
363
+ card_name: card.name,
364
+ skill_id: resolvedSkillId,
365
+ requester: owner,
366
+ status: "success",
367
+ latency_ms: latencyMs,
368
+ credits_charged: creditsNeeded,
369
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
370
+ });
371
+ } catch {
372
+ }
373
+ return {
374
+ request_index: index,
375
+ status: "success",
376
+ result: { card_id: card.id, skill_id: resolvedSkillId },
377
+ credits_spent: creditsNeeded,
378
+ credits_refunded: 0
379
+ };
380
+ };
381
+ let results;
382
+ if (strategy === "sequential") {
383
+ results = [];
384
+ let stopped = false;
385
+ for (let i = 0; i < requests.length; i++) {
386
+ if (stopped) {
387
+ results.push({
388
+ request_index: i,
389
+ status: "skipped",
390
+ credits_spent: 0,
391
+ credits_refunded: 0,
392
+ error: "Skipped due to earlier failure"
393
+ });
394
+ continue;
395
+ }
396
+ const result = await executeItem(requests[i], i);
397
+ results.push(result);
398
+ if (result.status === "failed") {
399
+ stopped = true;
400
+ }
401
+ }
402
+ } else {
403
+ const settled = await Promise.allSettled(
404
+ requests.map((item, i) => executeItem(item, i))
405
+ );
406
+ results = settled.map((outcome, i) => {
407
+ if (outcome.status === "fulfilled") {
408
+ return outcome.value;
409
+ }
410
+ return {
411
+ request_index: i,
412
+ status: "failed",
413
+ credits_spent: 0,
414
+ credits_refunded: 0,
415
+ error: outcome.reason instanceof Error ? outcome.reason.message : "Unknown error"
416
+ };
417
+ });
418
+ }
419
+ const total_credits_spent = results.reduce((acc, r) => acc + r.credits_spent, 0);
420
+ const total_credits_refunded = results.reduce((acc, r) => acc + r.credits_refunded, 0);
421
+ const success = results.every((r) => r.status === "success");
422
+ return { results, total_credits_spent, total_credits_refunded, success };
423
+ }
424
+
425
+ export {
426
+ settleRequesterEscrow,
427
+ releaseRequesterEscrow,
428
+ executeCapabilityRequest,
429
+ executeCapabilityBatch
430
+ };
@@ -66,6 +66,27 @@ var RelayProgressMessageSchema = z.object({
66
66
  message: z.string().optional()
67
67
  // optional status message
68
68
  });
69
+ var HeartbeatMessageSchema = z.object({
70
+ type: z.literal("heartbeat"),
71
+ owner: z.string().min(1),
72
+ capacity: z.object({
73
+ current_load: z.number(),
74
+ max_concurrent: z.number(),
75
+ queue_depth: z.number()
76
+ }),
77
+ self_summary: z.object({
78
+ capabilities: z.array(z.string()),
79
+ success_rate: z.number(),
80
+ credit_balance: z.number(),
81
+ total_completed: z.number(),
82
+ provider_number: z.number(),
83
+ reliability: z.object({
84
+ current_streak: z.number(),
85
+ repeat_hire_rate: z.number(),
86
+ avg_feedback: z.number()
87
+ })
88
+ })
89
+ });
69
90
  var RelayMessageSchema = z.discriminatedUnion("type", [
70
91
  RegisterMessageSchema,
71
92
  RegisteredMessageSchema,
@@ -74,7 +95,8 @@ var RelayMessageSchema = z.discriminatedUnion("type", [
74
95
  RelayResponseMessageSchema,
75
96
  ResponseMessageSchema,
76
97
  ErrorMessageSchema,
77
- RelayProgressMessageSchema
98
+ RelayProgressMessageSchema,
99
+ HeartbeatMessageSchema
78
100
  ]);
79
101
 
80
102
  export {