agentbnb 8.2.2 → 8.3.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.
- package/dist/{card-EX2EYGCZ.js → card-BN643ZOY.js} +6 -2
- package/dist/card-T2XJZA5A.js +92 -0
- package/dist/{chunk-3LWBH7P3.js → chunk-4NFJ3VYZ.js} +20 -1
- package/dist/chunk-5AIYALBX.js +857 -0
- package/dist/chunk-6QMDJVMS.js +238 -0
- package/dist/{chunk-LKLKYXLV.js → chunk-74LZDEDT.js} +6 -4
- package/dist/{chunk-GKVTD4EZ.js → chunk-77KGEDH4.js} +1 -1
- package/dist/{chunk-QCGIG7WW.js → chunk-7IQE34QK.js} +14 -7
- package/dist/{chunk-QHZGOG3O.js → chunk-D242QZCR.js} +168 -41
- package/dist/chunk-EE3V3DXK.js +60 -0
- package/dist/{chunk-RYISHSHB.js → chunk-F3KIEVJ2.js} +207 -265
- package/dist/{chunk-XBGVQMQJ.js → chunk-FELGHDCA.js} +16 -39
- package/dist/{chunk-EJKW57ZV.js → chunk-GIEJVKZZ.js} +1 -1
- package/dist/{chunk-WVY2W7AA.js → chunk-I7KWA7OB.js} +20 -0
- package/dist/{chunk-4IPJJRTP.js → chunk-IGQNP3ZO.js} +5 -2
- package/dist/chunk-NQANA6WH.js +797 -0
- package/dist/{chunk-Z4MCGKTL.js → chunk-NX27AFPA.js} +15 -2
- package/dist/{chunk-Z2GEFFDO.js → chunk-O4Q7BRG6.js} +2 -2
- package/dist/{chunk-SSK653A6.js → chunk-PQIP7EXY.js} +6 -0
- package/dist/{chunk-EG6RS4JC.js → chunk-QFPXZITP.js} +20 -65
- package/dist/chunk-R4F4XII4.js +264 -0
- package/dist/{chunk-DYQOFGGI.js → chunk-RVBW2QXU.js} +178 -49
- package/dist/{chunk-CQFBNTGT.js → chunk-S7DZHKCG.js} +25 -12
- package/dist/chunk-U6LP4KWN.js +238 -0
- package/dist/{chunk-MWOXW7JQ.js → chunk-VJ7XBEY6.js} +24 -16
- package/dist/chunk-WTHMHNKC.js +129 -0
- package/dist/{chunk-OCSU2S6W.js → chunk-WX3GZVFG.js} +2 -1
- package/dist/{chunk-CKOOVZOI.js → chunk-YKMBFQC2.js} +37 -5
- package/dist/{chunk-S3V6R3EN.js → chunk-ZU2TP7CN.js} +70 -27
- package/dist/cli/index.js +211 -278
- package/dist/client-OKJJ3UP2.js +19 -0
- package/dist/client-UQBGCIPA.js +20 -0
- package/dist/conduct-4JDMWBQD.js +22 -0
- package/dist/{conduct-AZFLNUX3.js → conduct-VYYBCPHA.js} +14 -13
- package/dist/{conductor-mode-WKB42PYM.js → conductor-mode-OPGQJFLA.js} +12 -8
- package/dist/{conductor-mode-PLTB6MS3.js → conductor-mode-SBDCRIX6.js} +16 -11
- package/dist/execute-FZLQGIXB.js +14 -0
- package/dist/execute-TEZPQ5WP.js +15 -0
- package/dist/index.d.ts +172 -11
- package/dist/index.js +1529 -433
- package/dist/{process-guard-GH5LRNWO.js → process-guard-TNSUNHSR.js} +1 -1
- package/dist/{publish-capability-QDR2QIZ2.js → publish-capability-HVYILTPR.js} +4 -3
- package/dist/{reliability-metrics-QG7WC5QK.js → reliability-metrics-G7LPUYJD.js} +3 -1
- package/dist/reliability-metrics-RRUKJ4ME.js +20 -0
- package/dist/{request-NX7GSPIG.js → request-KJNKR27T.js} +96 -43
- package/dist/{serve-skill-E6EJQYAK.js → serve-skill-GC6NIQ5T.js} +10 -11
- package/dist/{server-VBCT32FC.js → server-YV3XPTX5.js} +11 -10
- package/dist/{service-coordinator-KMSA6BST.js → service-coordinator-RY5AKUZS.js} +420 -171
- package/dist/{skill-config-FETXPNVP.js → skill-config-5O2VR546.js} +1 -1
- package/dist/skills/agentbnb/bootstrap.js +550 -231
- package/dist/websocket-client-3U27WJUU.js +7 -0
- package/dist/{websocket-client-4Z5P54RU.js → websocket-client-SNDF3B6N.js} +1 -1
- package/package.json +18 -12
- package/skills/agentbnb/install.sh +0 -0
- package/dist/chunk-MCED4GDW.js +0 -1572
- package/dist/chunk-NWIQJ2CL.js +0 -108
- package/dist/chunk-WNXXLCV5.js +0 -32
- package/dist/client-XOLP5IUZ.js +0 -12
- package/dist/conduct-VPUYTNEA.js +0 -21
- package/dist/execute-NNDCXTN4.js +0 -13
- package/dist/execute-RIRHTIBU.js +0 -16
- package/dist/websocket-client-QOVARTRN.js +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeCapabilityBatch,
|
|
3
3
|
executeCapabilityRequest
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FELGHDCA.js";
|
|
5
5
|
import {
|
|
6
6
|
StructuredFeedbackSchema
|
|
7
7
|
} from "./chunk-AUBHR7HH.js";
|
|
@@ -16,21 +16,20 @@ import {
|
|
|
16
16
|
getPricingStats,
|
|
17
17
|
resolveSelfCli,
|
|
18
18
|
stopAnnouncement
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-O4Q7BRG6.js";
|
|
20
20
|
import {
|
|
21
21
|
createLedger,
|
|
22
22
|
deriveAgentId,
|
|
23
23
|
identityAuthPlugin
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-WNXXLCV5.js";
|
|
24
|
+
} from "./chunk-74LZDEDT.js";
|
|
26
25
|
import {
|
|
27
26
|
DEFAULT_AUTONOMY_CONFIG,
|
|
28
27
|
getAutonomyTier,
|
|
29
28
|
insertAuditEvent,
|
|
30
29
|
listPendingRequests,
|
|
31
30
|
resolvePendingRequest
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
31
|
+
} from "./chunk-77KGEDH4.js";
|
|
32
|
+
import "./chunk-S7DZHKCG.js";
|
|
34
33
|
import {
|
|
35
34
|
bootstrapAgent,
|
|
36
35
|
buildReputationMap,
|
|
@@ -39,24 +38,28 @@ import {
|
|
|
39
38
|
getBalance,
|
|
40
39
|
getTransactions,
|
|
41
40
|
holdEscrow,
|
|
41
|
+
markEscrowAbandoned,
|
|
42
|
+
markEscrowProgressing,
|
|
43
|
+
markEscrowStarted,
|
|
42
44
|
migrateOwner,
|
|
43
45
|
openCreditDb,
|
|
44
46
|
releaseEscrow,
|
|
45
47
|
searchCards,
|
|
46
48
|
settleEscrow
|
|
47
|
-
} from "./chunk-
|
|
48
|
-
import
|
|
49
|
+
} from "./chunk-F3KIEVJ2.js";
|
|
50
|
+
import {
|
|
51
|
+
RelayMessageSchema
|
|
52
|
+
} from "./chunk-PQIP7EXY.js";
|
|
49
53
|
import {
|
|
50
54
|
generateKeyPair,
|
|
51
55
|
verifyEscrowReceipt
|
|
52
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-GIEJVKZZ.js";
|
|
57
|
+
import "./chunk-U6LP4KWN.js";
|
|
53
58
|
import {
|
|
54
59
|
getConfigDir
|
|
55
60
|
} from "./chunk-75OC6E4F.js";
|
|
56
61
|
import {
|
|
57
|
-
|
|
58
|
-
} from "./chunk-SSK653A6.js";
|
|
59
|
-
import {
|
|
62
|
+
attachCanonicalAgentId,
|
|
60
63
|
getActivityFeed,
|
|
61
64
|
getCard,
|
|
62
65
|
getCardsBySkillCapability,
|
|
@@ -75,20 +78,24 @@ import {
|
|
|
75
78
|
updateCard,
|
|
76
79
|
updateSkillAvailability,
|
|
77
80
|
updateSkillIdleRate
|
|
78
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-5AIYALBX.js";
|
|
82
|
+
import "./chunk-WTHMHNKC.js";
|
|
79
83
|
import {
|
|
80
84
|
AgentBnBError,
|
|
81
85
|
AnyCardSchema
|
|
82
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-I7KWA7OB.js";
|
|
83
87
|
import {
|
|
84
88
|
ApiSkillConfigSchema,
|
|
85
89
|
parseSkillsFile
|
|
86
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-WX3GZVFG.js";
|
|
87
91
|
|
|
88
92
|
// src/runtime/agent-runtime.ts
|
|
89
93
|
import { readFileSync, existsSync } from "fs";
|
|
90
94
|
|
|
91
95
|
// src/skills/executor.ts
|
|
96
|
+
function buildTimeoutError(skillId, timeoutMs) {
|
|
97
|
+
return `Skill "${skillId}" timed out after ${timeoutMs}ms`;
|
|
98
|
+
}
|
|
92
99
|
var SkillExecutor = class {
|
|
93
100
|
skillMap;
|
|
94
101
|
modeMap;
|
|
@@ -147,7 +154,20 @@ var SkillExecutor = class {
|
|
|
147
154
|
this.concurrencyGuard.acquire(skillId);
|
|
148
155
|
}
|
|
149
156
|
try {
|
|
150
|
-
const
|
|
157
|
+
const configuredTimeoutMs = typeof config.timeout_ms === "number" ? config.timeout_ms : void 0;
|
|
158
|
+
const modeExecution = mode.execute(config, params, onProgress);
|
|
159
|
+
const modeResult = configuredTimeoutMs === void 0 ? await modeExecution : await new Promise((resolve, reject) => {
|
|
160
|
+
const timeout = setTimeout(() => {
|
|
161
|
+
reject(new Error(buildTimeoutError(skillId, configuredTimeoutMs)));
|
|
162
|
+
}, configuredTimeoutMs);
|
|
163
|
+
modeExecution.then((value) => {
|
|
164
|
+
clearTimeout(timeout);
|
|
165
|
+
resolve(value);
|
|
166
|
+
}).catch((err) => {
|
|
167
|
+
clearTimeout(timeout);
|
|
168
|
+
reject(err);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
151
171
|
return {
|
|
152
172
|
...modeResult,
|
|
153
173
|
latency_ms: Date.now() - startTime
|
|
@@ -345,6 +365,15 @@ var ApiExecutor = class {
|
|
|
345
365
|
import { execFile } from "child_process";
|
|
346
366
|
import { promisify } from "util";
|
|
347
367
|
var execFileAsync = promisify(execFile);
|
|
368
|
+
function isTimedOutCommandError(err) {
|
|
369
|
+
if (!(err instanceof Error)) {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
const timeoutCode = err.code;
|
|
373
|
+
const signal = err.signal;
|
|
374
|
+
const killed = err.killed;
|
|
375
|
+
return timeoutCode === "ETIMEDOUT" || err.message.includes("timed out") || killed === true && typeof signal === "string";
|
|
376
|
+
}
|
|
348
377
|
function shellEscape(value) {
|
|
349
378
|
return "'" + value.replace(/'/g, "'\\''") + "'";
|
|
350
379
|
}
|
|
@@ -396,6 +425,8 @@ var PipelineExecutor = class {
|
|
|
396
425
|
async execute(config, params, onProgress) {
|
|
397
426
|
const pipelineConfig = config;
|
|
398
427
|
const steps = pipelineConfig.steps ?? [];
|
|
428
|
+
const pipelineTimeoutMs = pipelineConfig.timeout_ms;
|
|
429
|
+
const deadline = typeof pipelineTimeoutMs === "number" ? Date.now() + pipelineTimeoutMs : void 0;
|
|
399
430
|
if (steps.length === 0) {
|
|
400
431
|
return { success: true, result: null };
|
|
401
432
|
}
|
|
@@ -417,11 +448,41 @@ var PipelineExecutor = class {
|
|
|
417
448
|
context
|
|
418
449
|
);
|
|
419
450
|
let stepResult;
|
|
451
|
+
const runWithRemainingDeadline = async (operation) => {
|
|
452
|
+
if (deadline === void 0) {
|
|
453
|
+
return operation();
|
|
454
|
+
}
|
|
455
|
+
const remainingMs = deadline - Date.now();
|
|
456
|
+
if (remainingMs <= 0) {
|
|
457
|
+
throw new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`);
|
|
458
|
+
}
|
|
459
|
+
return new Promise((resolve, reject) => {
|
|
460
|
+
const timeout = setTimeout(() => {
|
|
461
|
+
reject(new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`));
|
|
462
|
+
}, remainingMs);
|
|
463
|
+
operation().then((value) => {
|
|
464
|
+
clearTimeout(timeout);
|
|
465
|
+
resolve(value);
|
|
466
|
+
}).catch((err) => {
|
|
467
|
+
clearTimeout(timeout);
|
|
468
|
+
reject(err);
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
};
|
|
420
472
|
if ("skill_id" in step && step.skill_id) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
473
|
+
let subResult;
|
|
474
|
+
try {
|
|
475
|
+
subResult = await runWithRemainingDeadline(() => this.skillExecutor.execute(
|
|
476
|
+
step.skill_id,
|
|
477
|
+
resolvedInputs
|
|
478
|
+
));
|
|
479
|
+
} catch (err) {
|
|
480
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
481
|
+
return {
|
|
482
|
+
success: false,
|
|
483
|
+
error: `Step ${i} failed: ${message}`
|
|
484
|
+
};
|
|
485
|
+
}
|
|
425
486
|
if (!subResult.success) {
|
|
426
487
|
return {
|
|
427
488
|
success: false,
|
|
@@ -435,10 +496,16 @@ var PipelineExecutor = class {
|
|
|
435
496
|
context
|
|
436
497
|
);
|
|
437
498
|
try {
|
|
438
|
-
const
|
|
499
|
+
const remainingMs = deadline === void 0 ? void 0 : deadline - Date.now();
|
|
500
|
+
if (remainingMs !== void 0 && remainingMs <= 0) {
|
|
501
|
+
throw new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`);
|
|
502
|
+
}
|
|
503
|
+
const { stdout } = await execFileAsync("/bin/sh", ["-c", interpolatedCommand], {
|
|
504
|
+
timeout: remainingMs !== void 0 ? remainingMs : 3e4
|
|
505
|
+
});
|
|
439
506
|
stepResult = stdout.trim();
|
|
440
507
|
} catch (err) {
|
|
441
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
508
|
+
const message = pipelineTimeoutMs !== void 0 && isTimedOutCommandError(err) ? `pipeline timed out after ${pipelineTimeoutMs}ms` : err instanceof Error ? err.message : String(err);
|
|
442
509
|
return {
|
|
443
510
|
success: false,
|
|
444
511
|
error: `Step ${i} failed: ${message}`
|
|
@@ -525,17 +592,43 @@ function executeProcess(config, payload) {
|
|
|
525
592
|
error: `Invalid agent name: "${config.agent_name}" (only alphanumeric, hyphens, underscores, dots allowed)`
|
|
526
593
|
};
|
|
527
594
|
}
|
|
528
|
-
const
|
|
595
|
+
const skillId = config.id;
|
|
596
|
+
const message = `[AgentBnB Rental Request]
|
|
597
|
+
You are executing the "${skillId}" skill for an AgentBnB network rental.
|
|
598
|
+
Read your skills/${skillId}/SKILL.md for detailed instructions.
|
|
599
|
+
|
|
600
|
+
Input parameters:
|
|
601
|
+
${JSON.stringify(payload.params ?? {}, null, 2)}
|
|
602
|
+
|
|
603
|
+
IMPORTANT: Return ONLY a JSON object as your response.
|
|
604
|
+
Do NOT include explanations, markdown formatting, or code blocks.
|
|
605
|
+
The JSON should contain the output fields specified in your SKILL.md.
|
|
606
|
+
If you cannot complete the task, return: {"error": "reason"}`;
|
|
529
607
|
try {
|
|
530
|
-
const stdout = execFileSync("openclaw", [
|
|
608
|
+
const stdout = execFileSync("openclaw", [
|
|
609
|
+
"agent",
|
|
610
|
+
"--agent",
|
|
611
|
+
config.agent_name,
|
|
612
|
+
"--message",
|
|
613
|
+
message,
|
|
614
|
+
"--json",
|
|
615
|
+
"--local"
|
|
616
|
+
], {
|
|
531
617
|
timeout: timeoutMs
|
|
532
618
|
});
|
|
533
619
|
const text = stdout.toString().trim();
|
|
534
|
-
|
|
535
|
-
|
|
620
|
+
try {
|
|
621
|
+
const parsed = JSON.parse(text);
|
|
622
|
+
return { success: true, result: parsed };
|
|
623
|
+
} catch {
|
|
624
|
+
return {
|
|
625
|
+
success: false,
|
|
626
|
+
error: `OpenClaw process channel returned invalid JSON: ${text}`
|
|
627
|
+
};
|
|
628
|
+
}
|
|
536
629
|
} catch (err) {
|
|
537
|
-
const
|
|
538
|
-
return { success: false, error:
|
|
630
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
631
|
+
return { success: false, error: message2 };
|
|
539
632
|
}
|
|
540
633
|
}
|
|
541
634
|
async function executeTelegram(config, payload) {
|
|
@@ -944,23 +1037,27 @@ var AgentRuntime = class {
|
|
|
944
1037
|
}
|
|
945
1038
|
const modes = /* @__PURE__ */ new Map();
|
|
946
1039
|
if (this.conductorEnabled) {
|
|
947
|
-
const { ConductorMode } = await import("./conductor-mode-
|
|
948
|
-
const { registerConductorCard, CONDUCTOR_OWNER } = await import("./card-
|
|
1040
|
+
const { ConductorMode } = await import("./conductor-mode-SBDCRIX6.js");
|
|
1041
|
+
const { registerConductorCard, CONDUCTOR_OWNER } = await import("./card-T2XJZA5A.js");
|
|
949
1042
|
const { loadPeers } = await import("./peers-K7FSHPN3.js");
|
|
950
1043
|
registerConductorCard(this.registryDb);
|
|
951
1044
|
const resolveAgentUrl = (owner) => {
|
|
952
1045
|
const peers = loadPeers();
|
|
953
|
-
const
|
|
1046
|
+
const matchingCards = listCards(this.registryDb, owner);
|
|
1047
|
+
const candidateNames = /* @__PURE__ */ new Set([owner.toLowerCase()]);
|
|
1048
|
+
for (const card of matchingCards) {
|
|
1049
|
+
candidateNames.add(card.owner.toLowerCase());
|
|
1050
|
+
if (typeof card.agent_id === "string" && card.agent_id.length > 0) {
|
|
1051
|
+
candidateNames.add(card.agent_id.toLowerCase());
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const peer = peers.find((p) => candidateNames.has(p.name.toLowerCase()));
|
|
954
1055
|
if (!peer) {
|
|
955
1056
|
throw new Error(
|
|
956
1057
|
`No peer found for agent owner "${owner}". Add with: agentbnb connect ${owner} <url> <token>`
|
|
957
1058
|
);
|
|
958
1059
|
}
|
|
959
|
-
const
|
|
960
|
-
"SELECT id FROM capability_cards WHERE owner = ? LIMIT 1"
|
|
961
|
-
);
|
|
962
|
-
const row = stmt.get(owner);
|
|
963
|
-
const cardId = row?.id ?? owner;
|
|
1060
|
+
const cardId = matchingCards[0]?.id ?? owner;
|
|
964
1061
|
return { url: peer.url, cardId };
|
|
965
1062
|
};
|
|
966
1063
|
const conductorMode = new ConductorMode({
|
|
@@ -1002,7 +1099,8 @@ var AgentRuntime = class {
|
|
|
1002
1099
|
}
|
|
1003
1100
|
/**
|
|
1004
1101
|
* Recovers orphaned escrows by releasing them.
|
|
1005
|
-
* Orphaned escrows are 'held' escrows older than the
|
|
1102
|
+
* Orphaned escrows are stale 'held' or 'abandoned' escrows older than the
|
|
1103
|
+
* configured age threshold. In-flight started/progressing escrows are not touched.
|
|
1006
1104
|
* Errors during individual release are swallowed (escrow may have settled between query and release).
|
|
1007
1105
|
*/
|
|
1008
1106
|
async recoverOrphanedEscrows() {
|
|
@@ -1010,7 +1108,7 @@ var AgentRuntime = class {
|
|
|
1010
1108
|
Date.now() - this.orphanedEscrowAgeMinutes * 60 * 1e3
|
|
1011
1109
|
).toISOString();
|
|
1012
1110
|
const orphaned = this.creditDb.prepare(
|
|
1013
|
-
"SELECT id FROM credit_escrow WHERE status
|
|
1111
|
+
"SELECT id FROM credit_escrow WHERE status IN ('held', 'abandoned') AND created_at < ?"
|
|
1014
1112
|
).all(cutoff);
|
|
1015
1113
|
for (const row of orphaned) {
|
|
1016
1114
|
try {
|
|
@@ -1361,7 +1459,9 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
|
|
|
1361
1459
|
throw new Error("Invalid consumer signature on escrow settle");
|
|
1362
1460
|
}
|
|
1363
1461
|
}
|
|
1364
|
-
const escrowRow = creditDb.prepare(
|
|
1462
|
+
const escrowRow = creditDb.prepare(
|
|
1463
|
+
"SELECT amount, owner FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
1464
|
+
).get(escrowId);
|
|
1365
1465
|
if (!escrowRow) {
|
|
1366
1466
|
throw new Error(`Escrow not found or already settled: ${escrowId}`);
|
|
1367
1467
|
}
|
|
@@ -1692,7 +1792,16 @@ function handleJobRelayResponse(opts) {
|
|
|
1692
1792
|
// src/relay/websocket-relay.ts
|
|
1693
1793
|
var RATE_LIMIT_MAX = 60;
|
|
1694
1794
|
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
1695
|
-
var
|
|
1795
|
+
var RELAY_IDLE_TIMEOUT_MS = 3e4;
|
|
1796
|
+
var RELAY_HARD_TIMEOUT_MS = 3e5;
|
|
1797
|
+
var RELAY_DISCONNECT_GRACE_MS = RELAY_HARD_TIMEOUT_MS + 3e4;
|
|
1798
|
+
function readTimeoutOverride(envKey, fallbackMs) {
|
|
1799
|
+
const raw = process.env[envKey];
|
|
1800
|
+
if (!raw) return fallbackMs;
|
|
1801
|
+
const parsed = Number(raw);
|
|
1802
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallbackMs;
|
|
1803
|
+
return Math.floor(parsed);
|
|
1804
|
+
}
|
|
1696
1805
|
function registerWebSocketRelay(server, db, creditDb) {
|
|
1697
1806
|
const connections = /* @__PURE__ */ new Map();
|
|
1698
1807
|
const agentIdToOwner = /* @__PURE__ */ new Map();
|
|
@@ -1706,6 +1815,136 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1706
1815
|
if (connections.has(target)) return target;
|
|
1707
1816
|
return void 0;
|
|
1708
1817
|
}
|
|
1818
|
+
function clearPendingTimers(pending) {
|
|
1819
|
+
clearTimeout(pending.timeout);
|
|
1820
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
1821
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
1822
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
1823
|
+
}
|
|
1824
|
+
function setPendingTimer(pending, timerType, timer) {
|
|
1825
|
+
const existing = pending[timerType];
|
|
1826
|
+
if (existing) clearTimeout(existing);
|
|
1827
|
+
pending[timerType] = timer;
|
|
1828
|
+
pending.timeout = timer;
|
|
1829
|
+
}
|
|
1830
|
+
function scheduleIdleTimeout(requestId, pending) {
|
|
1831
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_IDLE_TIMEOUT_MS", RELAY_IDLE_TIMEOUT_MS);
|
|
1832
|
+
const timer = setTimeout(() => {
|
|
1833
|
+
const current = pendingRequests.get(requestId);
|
|
1834
|
+
if (!current || (current.lifecycle ?? "held") !== "held") return;
|
|
1835
|
+
pendingRequests.delete(requestId);
|
|
1836
|
+
clearPendingTimers(current);
|
|
1837
|
+
if (current.escrowId && creditDb) {
|
|
1838
|
+
try {
|
|
1839
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
1840
|
+
} catch (e) {
|
|
1841
|
+
console.error("[relay] escrow release on idle timeout failed:", e);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
const originWs = connections.get(current.originOwner);
|
|
1845
|
+
if (originWs && originWs.readyState === 1) {
|
|
1846
|
+
sendMessage(originWs, {
|
|
1847
|
+
type: "response",
|
|
1848
|
+
id: requestId,
|
|
1849
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
}, timeoutMs);
|
|
1853
|
+
setPendingTimer(pending, "idleTimeout", timer);
|
|
1854
|
+
}
|
|
1855
|
+
function scheduleHardTimeout(requestId, pending) {
|
|
1856
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_HARD_TIMEOUT_MS", RELAY_HARD_TIMEOUT_MS);
|
|
1857
|
+
const timer = setTimeout(() => {
|
|
1858
|
+
const current = pendingRequests.get(requestId);
|
|
1859
|
+
if (!current || current.lifecycle === "abandoned") return;
|
|
1860
|
+
pendingRequests.delete(requestId);
|
|
1861
|
+
clearPendingTimers(current);
|
|
1862
|
+
if (current.escrowId && creditDb) {
|
|
1863
|
+
try {
|
|
1864
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
1865
|
+
} catch (e) {
|
|
1866
|
+
console.error("[relay] escrow release on hard timeout failed:", e);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
const originWs = connections.get(current.originOwner);
|
|
1870
|
+
if (originWs && originWs.readyState === 1) {
|
|
1871
|
+
sendMessage(originWs, {
|
|
1872
|
+
type: "response",
|
|
1873
|
+
id: requestId,
|
|
1874
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
}, timeoutMs);
|
|
1878
|
+
setPendingTimer(pending, "hardTimeout", timer);
|
|
1879
|
+
}
|
|
1880
|
+
function scheduleGraceTimeout(requestId, pending) {
|
|
1881
|
+
const timeoutMs = readTimeoutOverride(
|
|
1882
|
+
"AGENTBNB_RELAY_DISCONNECT_GRACE_MS",
|
|
1883
|
+
RELAY_DISCONNECT_GRACE_MS
|
|
1884
|
+
);
|
|
1885
|
+
const timer = setTimeout(() => {
|
|
1886
|
+
const current = pendingRequests.get(requestId);
|
|
1887
|
+
if (!current || current.lifecycle !== "abandoned") return;
|
|
1888
|
+
pendingRequests.delete(requestId);
|
|
1889
|
+
clearPendingTimers(current);
|
|
1890
|
+
if (current.escrowId && creditDb) {
|
|
1891
|
+
try {
|
|
1892
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
1893
|
+
} catch (e) {
|
|
1894
|
+
console.error("[relay] escrow release after grace timeout failed:", e);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
}, timeoutMs);
|
|
1898
|
+
setPendingTimer(pending, "graceTimeout", timer);
|
|
1899
|
+
}
|
|
1900
|
+
function transitionPendingToStarted(requestId, pending) {
|
|
1901
|
+
if (pending.lifecycle === "started" || pending.lifecycle === "progressing" || pending.lifecycle === "abandoned") {
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
pending.lifecycle = "started";
|
|
1905
|
+
pending.startedAt = Date.now();
|
|
1906
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
1907
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
1908
|
+
if (pending.escrowId && creditDb) {
|
|
1909
|
+
try {
|
|
1910
|
+
markEscrowStarted(creditDb, pending.escrowId);
|
|
1911
|
+
} catch (e) {
|
|
1912
|
+
console.error("[relay] escrow transition to started failed:", e);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
scheduleHardTimeout(requestId, pending);
|
|
1916
|
+
}
|
|
1917
|
+
function transitionPendingToProgressing(requestId, pending) {
|
|
1918
|
+
if (pending.lifecycle === "abandoned") {
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if ((pending.lifecycle ?? "held") === "held") {
|
|
1922
|
+
transitionPendingToStarted(requestId, pending);
|
|
1923
|
+
}
|
|
1924
|
+
pending.lifecycle = "progressing";
|
|
1925
|
+
if (pending.escrowId && creditDb) {
|
|
1926
|
+
try {
|
|
1927
|
+
markEscrowProgressing(creditDb, pending.escrowId);
|
|
1928
|
+
} catch (e) {
|
|
1929
|
+
console.error("[relay] escrow transition to progressing failed:", e);
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
function transitionPendingToAbandoned(requestId, pending) {
|
|
1934
|
+
if (pending.lifecycle === "abandoned") return;
|
|
1935
|
+
pending.lifecycle = "abandoned";
|
|
1936
|
+
pending.abandonedAt = Date.now();
|
|
1937
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
1938
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
1939
|
+
if (pending.escrowId && creditDb) {
|
|
1940
|
+
try {
|
|
1941
|
+
markEscrowAbandoned(creditDb, pending.escrowId);
|
|
1942
|
+
} catch (e) {
|
|
1943
|
+
console.error("[relay] escrow transition to abandoned failed:", e);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
scheduleGraceTimeout(requestId, pending);
|
|
1947
|
+
}
|
|
1709
1948
|
function checkRateLimit(owner) {
|
|
1710
1949
|
const now = Date.now();
|
|
1711
1950
|
const entry = rateLimits.get(owner);
|
|
@@ -1755,15 +1994,20 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1755
1994
|
} catch {
|
|
1756
1995
|
}
|
|
1757
1996
|
}
|
|
1758
|
-
function upsertCard(cardData, owner) {
|
|
1759
|
-
const parsed = AnyCardSchema.safeParse(
|
|
1997
|
+
function upsertCard(cardData, owner, agentId) {
|
|
1998
|
+
const parsed = AnyCardSchema.safeParse(
|
|
1999
|
+
agentId ? { ...cardData, agent_id: agentId } : cardData
|
|
2000
|
+
);
|
|
1760
2001
|
if (!parsed.success) {
|
|
1761
2002
|
throw new AgentBnBError(
|
|
1762
2003
|
`Card validation failed: ${parsed.error.message}`,
|
|
1763
2004
|
"VALIDATION_ERROR"
|
|
1764
2005
|
);
|
|
1765
2006
|
}
|
|
1766
|
-
const card =
|
|
2007
|
+
const card = attachCanonicalAgentId(db, {
|
|
2008
|
+
...parsed.data,
|
|
2009
|
+
availability: { ...parsed.data.availability, online: true }
|
|
2010
|
+
});
|
|
1767
2011
|
const cardId = card.id;
|
|
1768
2012
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1769
2013
|
const existing = db.prepare("SELECT id FROM capability_cards WHERE id = ?").get(cardId);
|
|
@@ -1817,7 +2061,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1817
2061
|
agentIdToOwner.set(agentEntry.agent_id, owner);
|
|
1818
2062
|
for (const agentCard of agentEntry.cards) {
|
|
1819
2063
|
try {
|
|
1820
|
-
upsertCard(agentCard, owner);
|
|
2064
|
+
upsertCard(agentCard, owner, agentEntry.agent_id);
|
|
1821
2065
|
} catch {
|
|
1822
2066
|
}
|
|
1823
2067
|
}
|
|
@@ -1831,7 +2075,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1831
2075
|
}
|
|
1832
2076
|
let cardId;
|
|
1833
2077
|
try {
|
|
1834
|
-
cardId = upsertCard(card, owner);
|
|
2078
|
+
cardId = upsertCard(card, owner, msg.agent_id);
|
|
1835
2079
|
} catch (err) {
|
|
1836
2080
|
console.error(`[relay] card validation failed for ${owner}:`, err instanceof Error ? err.message : err);
|
|
1837
2081
|
cardId = card.id ?? owner;
|
|
@@ -1841,7 +2085,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1841
2085
|
if (msg.cards && msg.cards.length > 0) {
|
|
1842
2086
|
for (const extraCard of msg.cards) {
|
|
1843
2087
|
try {
|
|
1844
|
-
upsertCard(extraCard, owner);
|
|
2088
|
+
upsertCard(extraCard, owner, msg.agent_id);
|
|
1845
2089
|
} catch {
|
|
1846
2090
|
}
|
|
1847
2091
|
}
|
|
@@ -1896,23 +2140,17 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1896
2140
|
console.error("[relay] credit hold error (non-fatal):", err);
|
|
1897
2141
|
}
|
|
1898
2142
|
}
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
type: "response",
|
|
1911
|
-
id: msg.id,
|
|
1912
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
1913
|
-
});
|
|
1914
|
-
}, RELAY_TIMEOUT_MS);
|
|
1915
|
-
pendingRequests.set(msg.id, { originOwner: fromOwner, creditOwner, timeout, escrowId, targetOwner: msg.target_owner });
|
|
2143
|
+
const pending = {
|
|
2144
|
+
originOwner: fromOwner,
|
|
2145
|
+
creditOwner,
|
|
2146
|
+
timeout: setTimeout(() => void 0, 1),
|
|
2147
|
+
escrowId,
|
|
2148
|
+
targetOwner: targetKey ?? msg.target_owner,
|
|
2149
|
+
lifecycle: "held",
|
|
2150
|
+
createdAt: Date.now()
|
|
2151
|
+
};
|
|
2152
|
+
pendingRequests.set(msg.id, pending);
|
|
2153
|
+
scheduleIdleTimeout(msg.id, pending);
|
|
1916
2154
|
sendMessage(targetWs, {
|
|
1917
2155
|
type: "incoming_request",
|
|
1918
2156
|
id: msg.id,
|
|
@@ -1924,30 +2162,23 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1924
2162
|
escrow_receipt: msg.escrow_receipt
|
|
1925
2163
|
});
|
|
1926
2164
|
}
|
|
2165
|
+
function handleRelayStarted(msg) {
|
|
2166
|
+
const pending = pendingRequests.get(msg.id);
|
|
2167
|
+
if (!pending) return;
|
|
2168
|
+
transitionPendingToStarted(msg.id, pending);
|
|
2169
|
+
const originWs = connections.get(pending.originOwner);
|
|
2170
|
+
if (originWs && originWs.readyState === 1) {
|
|
2171
|
+
sendMessage(originWs, {
|
|
2172
|
+
type: "relay_started",
|
|
2173
|
+
id: msg.id,
|
|
2174
|
+
message: msg.message
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
1927
2178
|
function handleRelayProgress(msg) {
|
|
1928
2179
|
const pending = pendingRequests.get(msg.id);
|
|
1929
2180
|
if (!pending) return;
|
|
1930
|
-
|
|
1931
|
-
const newTimeout = setTimeout(() => {
|
|
1932
|
-
const p = pendingRequests.get(msg.id);
|
|
1933
|
-
pendingRequests.delete(msg.id);
|
|
1934
|
-
if (p?.escrowId && creditDb) {
|
|
1935
|
-
try {
|
|
1936
|
-
releaseForRelay(creditDb, p.escrowId);
|
|
1937
|
-
} catch (e) {
|
|
1938
|
-
console.error("[relay] escrow release on progress timeout failed:", e);
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
const originWs2 = connections.get(pending.originOwner);
|
|
1942
|
-
if (originWs2 && originWs2.readyState === 1) {
|
|
1943
|
-
sendMessage(originWs2, {
|
|
1944
|
-
type: "response",
|
|
1945
|
-
id: msg.id,
|
|
1946
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
1947
|
-
});
|
|
1948
|
-
}
|
|
1949
|
-
}, RELAY_TIMEOUT_MS);
|
|
1950
|
-
pending.timeout = newTimeout;
|
|
2181
|
+
transitionPendingToProgressing(msg.id, pending);
|
|
1951
2182
|
const originWs = connections.get(pending.originOwner);
|
|
1952
2183
|
if (originWs && originWs.readyState === 1) {
|
|
1953
2184
|
sendMessage(originWs, {
|
|
@@ -1961,7 +2192,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
1961
2192
|
function handleRelayResponse(msg) {
|
|
1962
2193
|
const pending = pendingRequests.get(msg.id);
|
|
1963
2194
|
if (!pending) return;
|
|
1964
|
-
|
|
2195
|
+
clearPendingTimers(pending);
|
|
1965
2196
|
pendingRequests.delete(msg.id);
|
|
1966
2197
|
if (pending.jobId && creditDb) {
|
|
1967
2198
|
try {
|
|
@@ -2024,16 +2255,15 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2024
2255
|
connections.delete(owner);
|
|
2025
2256
|
rateLimits.delete(owner);
|
|
2026
2257
|
agentCapacities.delete(owner);
|
|
2027
|
-
for (const [agentId,
|
|
2028
|
-
if (
|
|
2258
|
+
for (const [agentId, mappedOwner] of Array.from(agentIdToOwner.entries())) {
|
|
2259
|
+
if (mappedOwner === owner) {
|
|
2029
2260
|
agentIdToOwner.delete(agentId);
|
|
2030
|
-
break;
|
|
2031
2261
|
}
|
|
2032
2262
|
}
|
|
2033
2263
|
markOwnerOffline(owner);
|
|
2034
2264
|
for (const [reqId, pending] of pendingRequests) {
|
|
2035
2265
|
if (pending.targetOwner === owner) {
|
|
2036
|
-
|
|
2266
|
+
clearPendingTimers(pending);
|
|
2037
2267
|
pendingRequests.delete(reqId);
|
|
2038
2268
|
if (pending.escrowId && creditDb) {
|
|
2039
2269
|
try {
|
|
@@ -2051,14 +2281,19 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2051
2281
|
});
|
|
2052
2282
|
}
|
|
2053
2283
|
} else if (pending.originOwner === owner) {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2284
|
+
const lifecycle = pending.lifecycle ?? "held";
|
|
2285
|
+
if (lifecycle === "held") {
|
|
2286
|
+
clearPendingTimers(pending);
|
|
2287
|
+
pendingRequests.delete(reqId);
|
|
2288
|
+
if (pending.escrowId && creditDb) {
|
|
2289
|
+
try {
|
|
2290
|
+
releaseForRelay(creditDb, pending.escrowId);
|
|
2291
|
+
} catch (e) {
|
|
2292
|
+
console.error("[relay] escrow release on requester disconnect failed:", e);
|
|
2293
|
+
}
|
|
2061
2294
|
}
|
|
2295
|
+
} else {
|
|
2296
|
+
transitionPendingToAbandoned(reqId, pending);
|
|
2062
2297
|
}
|
|
2063
2298
|
}
|
|
2064
2299
|
}
|
|
@@ -2101,7 +2336,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2101
2336
|
return;
|
|
2102
2337
|
}
|
|
2103
2338
|
try {
|
|
2104
|
-
const escrow = creditDb.prepare(
|
|
2339
|
+
const escrow = creditDb.prepare(
|
|
2340
|
+
"SELECT card_id FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
2341
|
+
).get(msg.escrow_id);
|
|
2105
2342
|
if (!escrow) {
|
|
2106
2343
|
sendMessage(ws, { type: "error", code: "escrow_not_found", message: `Escrow not found: ${msg.escrow_id}`, request_id: msg.request_id });
|
|
2107
2344
|
return;
|
|
@@ -2198,6 +2435,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2198
2435
|
case "relay_response":
|
|
2199
2436
|
handleRelayResponse(msg);
|
|
2200
2437
|
break;
|
|
2438
|
+
case "relay_started":
|
|
2439
|
+
handleRelayStarted(msg);
|
|
2440
|
+
break;
|
|
2201
2441
|
case "relay_progress":
|
|
2202
2442
|
handleRelayProgress(msg);
|
|
2203
2443
|
break;
|
|
@@ -2244,7 +2484,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2244
2484
|
}
|
|
2245
2485
|
connections.clear();
|
|
2246
2486
|
for (const [, pending] of pendingRequests) {
|
|
2247
|
-
|
|
2487
|
+
clearPendingTimers(pending);
|
|
2248
2488
|
}
|
|
2249
2489
|
pendingRequests.clear();
|
|
2250
2490
|
rateLimits.clear();
|
|
@@ -3522,6 +3762,9 @@ function stripInternal(card) {
|
|
|
3522
3762
|
const { _internal: _, ...publicCard } = card;
|
|
3523
3763
|
return publicCard;
|
|
3524
3764
|
}
|
|
3765
|
+
function buildSqlPlaceholders(count) {
|
|
3766
|
+
return Array.from({ length: count }, () => "?").join(", ");
|
|
3767
|
+
}
|
|
3525
3768
|
function createRegistryServer(opts) {
|
|
3526
3769
|
const { registryDb: db, silent = false } = opts;
|
|
3527
3770
|
const server = Fastify2({ logger: !silent });
|
|
@@ -3931,11 +4174,11 @@ function createRegistryServer(opts) {
|
|
|
3931
4174
|
const card = result.data;
|
|
3932
4175
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3933
4176
|
if (card.spec_version === "2.0") {
|
|
3934
|
-
const cardWithTimestamps = {
|
|
4177
|
+
const cardWithTimestamps = attachCanonicalAgentId(db, {
|
|
3935
4178
|
...card,
|
|
3936
4179
|
created_at: card.created_at ?? now,
|
|
3937
4180
|
updated_at: now
|
|
3938
|
-
};
|
|
4181
|
+
});
|
|
3939
4182
|
db.prepare(
|
|
3940
4183
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
3941
4184
|
VALUES (?, ?, ?, ?, ?)`
|
|
@@ -4056,19 +4299,16 @@ function createRegistryServer(opts) {
|
|
|
4056
4299
|
if (ownerCards.length === 0) {
|
|
4057
4300
|
return reply.status(404).send({ error: "Agent not found" });
|
|
4058
4301
|
}
|
|
4059
|
-
const
|
|
4060
|
-
|
|
4302
|
+
const resolvedOwner = ownerCards[0]?.owner ?? owner;
|
|
4303
|
+
const ownerCardIds = ownerCards.map((card) => card.id);
|
|
4304
|
+
const cardIdPlaceholders = buildSqlPlaceholders(ownerCardIds.length);
|
|
4305
|
+
const joinedAt = ownerCards.map((card) => card.created_at).filter((value) => typeof value === "string" && value.length > 0).sort((left, right) => left.localeCompare(right))[0] ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
4306
|
+
const latestCardUpdate = ownerCards.map((card) => card.updated_at ?? card.created_at).filter((value) => typeof value === "string" && value.length > 0).sort((left, right) => right.localeCompare(left))[0] ?? joinedAt;
|
|
4307
|
+
const lastActiveStmt = db.prepare(
|
|
4308
|
+
`SELECT MAX(created_at) as last_req FROM request_log WHERE card_id IN (${cardIdPlaceholders})`
|
|
4061
4309
|
);
|
|
4062
|
-
const
|
|
4063
|
-
const
|
|
4064
|
-
const lastActiveStmt = db.prepare(`
|
|
4065
|
-
SELECT MAX(rl.created_at) as last_req
|
|
4066
|
-
FROM request_log rl
|
|
4067
|
-
INNER JOIN capability_cards cc ON rl.card_id = cc.id
|
|
4068
|
-
WHERE cc.owner = ?
|
|
4069
|
-
`);
|
|
4070
|
-
const lastActiveRow = lastActiveStmt.get(owner);
|
|
4071
|
-
const lastActive = lastActiveRow?.last_req ?? memberRow?.latest ?? joinedAt;
|
|
4310
|
+
const lastActiveRow = lastActiveStmt.get(...ownerCardIds);
|
|
4311
|
+
const lastActive = lastActiveRow?.last_req ?? latestCardUpdate ?? joinedAt;
|
|
4072
4312
|
const metricsStmt = db.prepare(`
|
|
4073
4313
|
SELECT
|
|
4074
4314
|
SUM(CASE WHEN rl.failure_reason IS NULL OR rl.failure_reason IN ('bad_execution','auth_error')
|
|
@@ -4078,10 +4318,9 @@ function createRegistryServer(opts) {
|
|
|
4078
4318
|
COUNT(DISTINCT rl.requester) as unique_requesters,
|
|
4079
4319
|
COUNT(DISTINCT CASE WHEN rl.status = 'success' THEN rl.requester END) as repeat_success_requesters
|
|
4080
4320
|
FROM request_log rl
|
|
4081
|
-
|
|
4082
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
4321
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
4083
4322
|
`);
|
|
4084
|
-
const metricsRow = metricsStmt.get(
|
|
4323
|
+
const metricsRow = metricsStmt.get(...ownerCardIds);
|
|
4085
4324
|
const totalExec = metricsRow?.total ?? 0;
|
|
4086
4325
|
const successExec = metricsRow?.successes ?? 0;
|
|
4087
4326
|
const successRate = totalExec > 0 ? successExec / totalExec : 0;
|
|
@@ -4095,25 +4334,23 @@ function createRegistryServer(opts) {
|
|
|
4095
4334
|
COUNT(*) as count,
|
|
4096
4335
|
SUM(CASE WHEN rl.status = 'success' THEN 1 ELSE 0 END) as success
|
|
4097
4336
|
FROM request_log rl
|
|
4098
|
-
|
|
4099
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
4337
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
4100
4338
|
AND rl.created_at >= DATE('now', '-7 days')
|
|
4101
4339
|
GROUP BY DATE(rl.created_at)
|
|
4102
4340
|
ORDER BY day ASC
|
|
4103
4341
|
`);
|
|
4104
|
-
const trend_7d = trendStmt.all(
|
|
4342
|
+
const trend_7d = trendStmt.all(...ownerCardIds).map((r) => ({ date: r.day, count: r.count, success: r.success }));
|
|
4105
4343
|
let performanceTier = 0;
|
|
4106
4344
|
if (totalExec > 10) performanceTier = 1;
|
|
4107
4345
|
if (totalExec > 50 && successRate >= 0.85) performanceTier = 2;
|
|
4108
4346
|
const proofsStmt = db.prepare(`
|
|
4109
4347
|
SELECT rl.card_name, rl.status, rl.latency_ms, rl.id, rl.created_at
|
|
4110
4348
|
FROM request_log rl
|
|
4111
|
-
|
|
4112
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
4349
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
4113
4350
|
ORDER BY rl.created_at DESC
|
|
4114
4351
|
LIMIT 10
|
|
4115
4352
|
`);
|
|
4116
|
-
const proofRows = proofsStmt.all(
|
|
4353
|
+
const proofRows = proofsStmt.all(...ownerCardIds);
|
|
4117
4354
|
const statusToOutcomeClass = (s) => {
|
|
4118
4355
|
if (s === "success") return "completed";
|
|
4119
4356
|
if (s === "timeout") return "cancelled";
|
|
@@ -4139,22 +4376,20 @@ function createRegistryServer(opts) {
|
|
|
4139
4376
|
const activityStmt = db.prepare(`
|
|
4140
4377
|
SELECT rl.id, rl.card_name, rl.requester, rl.status, rl.credits_charged, rl.created_at
|
|
4141
4378
|
FROM request_log rl
|
|
4142
|
-
|
|
4143
|
-
WHERE cc.owner = ?
|
|
4379
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
4144
4380
|
ORDER BY rl.created_at DESC
|
|
4145
4381
|
LIMIT 10
|
|
4146
4382
|
`);
|
|
4147
|
-
const recentActivity = activityStmt.all(
|
|
4383
|
+
const recentActivity = activityStmt.all(...ownerCardIds);
|
|
4148
4384
|
const skillCount = ownerCards.reduce((sum, card) => sum + (card.skills?.length ?? 1), 0);
|
|
4149
4385
|
const creditsStmt = db.prepare(`
|
|
4150
|
-
SELECT SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END) as credits_earned
|
|
4151
|
-
FROM
|
|
4152
|
-
|
|
4153
|
-
WHERE cc.owner = ?
|
|
4386
|
+
SELECT COALESCE(SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END), 0) as credits_earned
|
|
4387
|
+
FROM request_log rl
|
|
4388
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
4154
4389
|
`);
|
|
4155
|
-
const creditsRow = creditsStmt.get(
|
|
4390
|
+
const creditsRow = creditsStmt.get(...ownerCardIds);
|
|
4156
4391
|
const response = {
|
|
4157
|
-
owner,
|
|
4392
|
+
owner: resolvedOwner,
|
|
4158
4393
|
agent_name: v2Card?.agent_name,
|
|
4159
4394
|
short_description: v2Card?.short_description,
|
|
4160
4395
|
joined_at: joinedAt,
|
|
@@ -4186,7 +4421,7 @@ function createRegistryServer(opts) {
|
|
|
4186
4421
|
return reply.send({
|
|
4187
4422
|
...response,
|
|
4188
4423
|
profile: {
|
|
4189
|
-
owner,
|
|
4424
|
+
owner: resolvedOwner,
|
|
4190
4425
|
skill_count: skillCount,
|
|
4191
4426
|
success_rate: successRate > 0 ? successRate : null,
|
|
4192
4427
|
total_earned: creditsRow?.credits_earned ?? 0,
|
|
@@ -4458,7 +4693,7 @@ function createRegistryServer(opts) {
|
|
|
4458
4693
|
return { card_id: target.cardId, skill_id: target.skillId };
|
|
4459
4694
|
}
|
|
4460
4695
|
if (!relayClient) {
|
|
4461
|
-
const { RelayClient } = await import("./websocket-client-
|
|
4696
|
+
const { RelayClient } = await import("./websocket-client-3U27WJUU.js");
|
|
4462
4697
|
relayClient = new RelayClient({
|
|
4463
4698
|
registryUrl: relayRegistryUrl,
|
|
4464
4699
|
owner: relayRequesterOwner,
|
|
@@ -4480,7 +4715,7 @@ function createRegistryServer(opts) {
|
|
|
4480
4715
|
});
|
|
4481
4716
|
await relayClient.connect();
|
|
4482
4717
|
}
|
|
4483
|
-
const { requestViaRelay } = await import("./client-
|
|
4718
|
+
const { requestViaRelay } = await import("./client-UQBGCIPA.js");
|
|
4484
4719
|
return requestViaRelay(relayClient, {
|
|
4485
4720
|
targetOwner: target.owner,
|
|
4486
4721
|
cardId: target.cardId,
|
|
@@ -4736,7 +4971,7 @@ function createRegistryServer(opts) {
|
|
|
4736
4971
|
if (!opts.creditDb) {
|
|
4737
4972
|
return reply.code(404).send({ error: "Credit system not enabled" });
|
|
4738
4973
|
}
|
|
4739
|
-
const { getReliabilityMetrics } = await import("./reliability-metrics-
|
|
4974
|
+
const { getReliabilityMetrics } = await import("./reliability-metrics-RRUKJ4ME.js");
|
|
4740
4975
|
const metrics = getReliabilityMetrics(opts.creditDb, owner);
|
|
4741
4976
|
if (!metrics) {
|
|
4742
4977
|
return reply.code(404).send({ error: "No reliability data for this provider" });
|
|
@@ -4754,38 +4989,37 @@ function createRegistryServer(opts) {
|
|
|
4754
4989
|
}
|
|
4755
4990
|
}, async (request, reply) => {
|
|
4756
4991
|
const { owner } = request.params;
|
|
4757
|
-
const
|
|
4758
|
-
"SELECT id, data FROM capability_cards WHERE owner = ?"
|
|
4759
|
-
).all(owner);
|
|
4992
|
+
const cards = listCards(db, owner);
|
|
4760
4993
|
const agents = [];
|
|
4761
|
-
for (const
|
|
4994
|
+
for (const card of cards) {
|
|
4762
4995
|
try {
|
|
4763
|
-
const
|
|
4996
|
+
const rawCard = card;
|
|
4997
|
+
const providerIdentity = typeof card.agent_id === "string" && card.agent_id.length > 0 ? card.agent_id : card.owner;
|
|
4764
4998
|
let earnings = 0;
|
|
4765
4999
|
let spend = 0;
|
|
4766
5000
|
if (opts.creditDb) {
|
|
4767
5001
|
const earningRow = opts.creditDb.prepare(
|
|
4768
5002
|
"SELECT COALESCE(SUM(amount), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'settlement' AND amount > 0"
|
|
4769
|
-
).get(
|
|
5003
|
+
).get(providerIdentity);
|
|
4770
5004
|
earnings = earningRow.total;
|
|
4771
5005
|
const spendRow = opts.creditDb.prepare(
|
|
4772
5006
|
"SELECT COALESCE(SUM(ABS(amount)), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'escrow_hold'"
|
|
4773
|
-
).get(
|
|
5007
|
+
).get(providerIdentity);
|
|
4774
5008
|
spend = spendRow.total;
|
|
4775
5009
|
}
|
|
4776
5010
|
const successCount = db.prepare(
|
|
4777
5011
|
"SELECT COUNT(*) as cnt FROM request_log WHERE card_id = ? AND status = 'success' AND (action_type IS NULL OR action_type = 'auto_share')"
|
|
4778
|
-
).get(
|
|
5012
|
+
).get(card.id).cnt;
|
|
4779
5013
|
const failureCount = db.prepare(
|
|
4780
5014
|
"SELECT COUNT(*) as cnt FROM request_log WHERE card_id = ? AND status IN ('failure', 'timeout', 'refunded') AND (action_type IS NULL OR action_type = 'auto_share')"
|
|
4781
|
-
).get(
|
|
5015
|
+
).get(card.id).cnt;
|
|
4782
5016
|
const totalExec = successCount + failureCount;
|
|
4783
5017
|
const successRate = totalExec > 0 ? successCount / totalExec : 0;
|
|
4784
5018
|
let failureBreakdown = {};
|
|
4785
5019
|
try {
|
|
4786
5020
|
const failureRows = db.prepare(
|
|
4787
5021
|
"SELECT failure_reason, COUNT(*) as cnt FROM request_log WHERE card_id = ? AND status IN ('failure', 'timeout', 'refunded') AND failure_reason IS NOT NULL GROUP BY failure_reason"
|
|
4788
|
-
).all(
|
|
5022
|
+
).all(card.id);
|
|
4789
5023
|
for (const fr of failureRows) {
|
|
4790
5024
|
failureBreakdown[fr.failure_reason] = fr.cnt;
|
|
4791
5025
|
}
|
|
@@ -4793,12 +5027,12 @@ function createRegistryServer(opts) {
|
|
|
4793
5027
|
}
|
|
4794
5028
|
let reliability = null;
|
|
4795
5029
|
if (opts.creditDb) {
|
|
4796
|
-
const { getReliabilityMetrics } = await import("./reliability-metrics-
|
|
4797
|
-
reliability = getReliabilityMetrics(opts.creditDb,
|
|
5030
|
+
const { getReliabilityMetrics } = await import("./reliability-metrics-RRUKJ4ME.js");
|
|
5031
|
+
reliability = getReliabilityMetrics(opts.creditDb, providerIdentity);
|
|
4798
5032
|
}
|
|
4799
5033
|
agents.push({
|
|
4800
|
-
id:
|
|
4801
|
-
name:
|
|
5034
|
+
id: card.id,
|
|
5035
|
+
name: (typeof rawCard["name"] === "string" ? rawCard["name"] : void 0) ?? (typeof rawCard["agent_name"] === "string" ? rawCard["agent_name"] : void 0) ?? card.owner,
|
|
4802
5036
|
online: card.availability?.online ?? false,
|
|
4803
5037
|
current_load: 0,
|
|
4804
5038
|
// Will be populated from relay heartbeat data in future
|
|
@@ -4916,6 +5150,32 @@ import { spawn as spawn2 } from "child_process";
|
|
|
4916
5150
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
4917
5151
|
import { join as join2 } from "path";
|
|
4918
5152
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
5153
|
+
function buildFallbackRelayCard(owner) {
|
|
5154
|
+
return {
|
|
5155
|
+
id: randomUUID7(),
|
|
5156
|
+
owner,
|
|
5157
|
+
name: owner,
|
|
5158
|
+
description: "Agent registered via CLI",
|
|
5159
|
+
spec_version: "1.0",
|
|
5160
|
+
level: 1,
|
|
5161
|
+
inputs: [],
|
|
5162
|
+
outputs: [],
|
|
5163
|
+
pricing: { credits_per_call: 1 },
|
|
5164
|
+
availability: { online: true }
|
|
5165
|
+
};
|
|
5166
|
+
}
|
|
5167
|
+
function buildRelayRegistrationCards(owner, localCards) {
|
|
5168
|
+
if (localCards.length === 0) {
|
|
5169
|
+
return {
|
|
5170
|
+
primaryCard: buildFallbackRelayCard(owner),
|
|
5171
|
+
additionalCards: []
|
|
5172
|
+
};
|
|
5173
|
+
}
|
|
5174
|
+
return {
|
|
5175
|
+
primaryCard: localCards[0],
|
|
5176
|
+
additionalCards: localCards.slice(1)
|
|
5177
|
+
};
|
|
5178
|
+
}
|
|
4919
5179
|
var ServiceCoordinator = class {
|
|
4920
5180
|
config;
|
|
4921
5181
|
guard;
|
|
@@ -5060,8 +5320,11 @@ var ServiceCoordinator = class {
|
|
|
5060
5320
|
console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
|
|
5061
5321
|
}
|
|
5062
5322
|
if (opts.conductorEnabled && this.config.conductor?.public) {
|
|
5063
|
-
const { buildConductorCard } = await import("./card-
|
|
5064
|
-
const conductorCard =
|
|
5323
|
+
const { buildConductorCard } = await import("./card-T2XJZA5A.js");
|
|
5324
|
+
const conductorCard = attachCanonicalAgentId(
|
|
5325
|
+
this.runtime.registryDb,
|
|
5326
|
+
buildConductorCard(this.config.owner)
|
|
5327
|
+
);
|
|
5065
5328
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5066
5329
|
const existing = this.runtime.registryDb.prepare("SELECT id FROM capability_cards WHERE id = ?").get(conductorCard.id);
|
|
5067
5330
|
if (existing) {
|
|
@@ -5117,27 +5380,11 @@ var ServiceCoordinator = class {
|
|
|
5117
5380
|
}
|
|
5118
5381
|
}
|
|
5119
5382
|
if (opts.registryUrl && opts.relay) {
|
|
5120
|
-
const { RelayClient } = await import("./websocket-client-
|
|
5121
|
-
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("./execute-
|
|
5122
|
-
const
|
|
5123
|
-
const
|
|
5124
|
-
id: randomUUID7(),
|
|
5125
|
-
owner: this.config.owner,
|
|
5126
|
-
name: this.config.owner,
|
|
5127
|
-
description: "Agent registered via CLI",
|
|
5128
|
-
spec_version: "1.0",
|
|
5129
|
-
level: 1,
|
|
5130
|
-
inputs: [],
|
|
5131
|
-
outputs: [],
|
|
5132
|
-
pricing: { credits_per_call: 1 },
|
|
5133
|
-
availability: { online: true }
|
|
5134
|
-
};
|
|
5135
|
-
const additionalCards = [];
|
|
5383
|
+
const { RelayClient } = await import("./websocket-client-3U27WJUU.js");
|
|
5384
|
+
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("./execute-TEZPQ5WP.js");
|
|
5385
|
+
const localCards = listCards(this.runtime.registryDb, this.config.owner);
|
|
5386
|
+
const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
|
|
5136
5387
|
if (this.config.conductor?.public) {
|
|
5137
|
-
const { buildConductorCard } = await import("./card-EX2EYGCZ.js");
|
|
5138
|
-
additionalCards.push(
|
|
5139
|
-
buildConductorCard(this.config.owner)
|
|
5140
|
-
);
|
|
5141
5388
|
console.log("Conductor card will be published to registry (conductor.public: true)");
|
|
5142
5389
|
}
|
|
5143
5390
|
this.relayClient = new RelayClient({
|
|
@@ -5145,9 +5392,10 @@ var ServiceCoordinator = class {
|
|
|
5145
5392
|
owner: this.config.owner,
|
|
5146
5393
|
agent_id: this.config.agent_id,
|
|
5147
5394
|
token: this.config.token,
|
|
5148
|
-
card,
|
|
5395
|
+
card: primaryCard,
|
|
5149
5396
|
cards: additionalCards.length > 0 ? additionalCards : void 0,
|
|
5150
5397
|
onRequest: async (req) => {
|
|
5398
|
+
this.relayClient?.sendStarted(req.id, "provider acknowledged");
|
|
5151
5399
|
const onProgress = (info) => {
|
|
5152
5400
|
this.relayClient.sendProgress(req.id, info);
|
|
5153
5401
|
};
|
|
@@ -5427,6 +5675,7 @@ function sleep2(ms) {
|
|
|
5427
5675
|
}
|
|
5428
5676
|
export {
|
|
5429
5677
|
ServiceCoordinator,
|
|
5678
|
+
buildRelayRegistrationCards,
|
|
5430
5679
|
loadPersistedRuntime,
|
|
5431
5680
|
resolveNodeExecutable
|
|
5432
5681
|
};
|