agentbnb 8.2.3 → 8.3.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.
- 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-GKVTD4EZ.js → chunk-77KGEDH4.js} +1 -1
- package/dist/{chunk-QCGIG7WW.js → chunk-7IQE34QK.js} +14 -7
- package/dist/{chunk-LKLKYXLV.js → chunk-BARHNIKG.js} +10 -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 +203 -237
- 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-OERS5BE7.js → request-KJNKR27T.js} +76 -71
- package/dist/{serve-skill-E6EJQYAK.js → serve-skill-GC6NIQ5T.js} +10 -11
- package/dist/{server-46VEG2W7.js → server-YVLMQ2BO.js} +11 -10
- package/dist/{service-coordinator-KMSA6BST.js → service-coordinator-SCP2YIFT.js} +420 -171
- package/dist/{skill-config-FETXPNVP.js → skill-config-5O2VR546.js} +1 -1
- package/dist/skills/agentbnb/bootstrap.js +532 -256
- package/dist/websocket-client-3U27WJUU.js +7 -0
- package/dist/{websocket-client-4Z5P54RU.js → websocket-client-SNDF3B6N.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-MCED4GDW.js +0 -1572
- package/dist/chunk-NWIQJ2CL.js +0 -108
- package/dist/chunk-TUCEDQGM.js +0 -44
- 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,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RelayClient,
|
|
3
|
-
RelayMessageSchema
|
|
4
|
-
} from "../../chunk-3LWBH7P3.js";
|
|
5
1
|
import {
|
|
6
2
|
AutoRequestor,
|
|
7
3
|
BudgetController,
|
|
@@ -16,21 +12,29 @@ import {
|
|
|
16
12
|
listPendingRequests,
|
|
17
13
|
matchSubTasks,
|
|
18
14
|
orchestrate,
|
|
15
|
+
requestViaTemporaryRelay,
|
|
19
16
|
resolvePendingRequest
|
|
20
|
-
} from "../../chunk-
|
|
17
|
+
} from "../../chunk-RVBW2QXU.js";
|
|
21
18
|
import {
|
|
19
|
+
generateKeyPair,
|
|
20
|
+
loadKeyPair,
|
|
22
21
|
requestCapability,
|
|
23
|
-
requestViaRelay
|
|
24
|
-
|
|
22
|
+
requestViaRelay,
|
|
23
|
+
saveKeyPair,
|
|
24
|
+
signEscrowReceipt,
|
|
25
|
+
verifyEscrowReceipt
|
|
26
|
+
} from "../../chunk-R4F4XII4.js";
|
|
27
|
+
import {
|
|
28
|
+
RelayClient,
|
|
29
|
+
RelayMessageSchema
|
|
30
|
+
} from "../../chunk-4NFJ3VYZ.js";
|
|
25
31
|
import {
|
|
26
32
|
loadPeers
|
|
27
33
|
} from "../../chunk-HLUEOLSZ.js";
|
|
28
34
|
import {
|
|
29
35
|
executeCapabilityBatch,
|
|
30
|
-
executeCapabilityRequest
|
|
31
|
-
|
|
32
|
-
settleRequesterEscrow
|
|
33
|
-
} from "../../chunk-EG6RS4JC.js";
|
|
36
|
+
executeCapabilityRequest
|
|
37
|
+
} from "../../chunk-QFPXZITP.js";
|
|
34
38
|
import {
|
|
35
39
|
bootstrapAgent,
|
|
36
40
|
buildReputationMap,
|
|
@@ -38,8 +42,27 @@ import {
|
|
|
38
42
|
confirmEscrowDebit,
|
|
39
43
|
fetchRemoteCards,
|
|
40
44
|
filterCards,
|
|
41
|
-
getActivityFeed,
|
|
42
45
|
getBalance,
|
|
46
|
+
getTransactions,
|
|
47
|
+
holdEscrow,
|
|
48
|
+
markEscrowAbandoned,
|
|
49
|
+
markEscrowProgressing,
|
|
50
|
+
markEscrowStarted,
|
|
51
|
+
mergeResults,
|
|
52
|
+
migrateOwner,
|
|
53
|
+
openCreditDb,
|
|
54
|
+
releaseEscrow,
|
|
55
|
+
searchCards,
|
|
56
|
+
settleEscrow
|
|
57
|
+
} from "../../chunk-NQANA6WH.js";
|
|
58
|
+
import "../../chunk-6QMDJVMS.js";
|
|
59
|
+
import {
|
|
60
|
+
getConfigDir,
|
|
61
|
+
loadConfig
|
|
62
|
+
} from "../../chunk-IVOYM3WG.js";
|
|
63
|
+
import {
|
|
64
|
+
attachCanonicalAgentId,
|
|
65
|
+
getActivityFeed,
|
|
43
66
|
getCard,
|
|
44
67
|
getCardsBySkillCapability,
|
|
45
68
|
getEvolutionHistory,
|
|
@@ -48,41 +71,23 @@ import {
|
|
|
48
71
|
getLatestEvolution,
|
|
49
72
|
getRequestLog,
|
|
50
73
|
getSkillRequestCount,
|
|
51
|
-
getTransactions,
|
|
52
|
-
holdEscrow,
|
|
53
74
|
insertCard,
|
|
54
75
|
insertEvolution,
|
|
55
76
|
insertFeedback,
|
|
56
77
|
insertRequestLog,
|
|
57
78
|
listCards,
|
|
58
|
-
lookupAgent,
|
|
59
|
-
mergeResults,
|
|
60
|
-
migrateOwner,
|
|
61
|
-
openCreditDb,
|
|
62
79
|
openDatabase,
|
|
63
|
-
releaseEscrow,
|
|
64
|
-
searchCards,
|
|
65
|
-
settleEscrow,
|
|
66
80
|
updateCard,
|
|
67
81
|
updateSkillAvailability,
|
|
68
82
|
updateSkillIdleRate
|
|
69
|
-
} from "../../chunk-
|
|
70
|
-
import "../../chunk-NWIQJ2CL.js";
|
|
83
|
+
} from "../../chunk-ZU2TP7CN.js";
|
|
71
84
|
import {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
saveKeyPair,
|
|
75
|
-
signEscrowReceipt,
|
|
76
|
-
verifyEscrowReceipt
|
|
77
|
-
} from "../../chunk-EJKW57ZV.js";
|
|
78
|
-
import {
|
|
79
|
-
getConfigDir,
|
|
80
|
-
loadConfig
|
|
81
|
-
} from "../../chunk-IVOYM3WG.js";
|
|
85
|
+
lookupAgent
|
|
86
|
+
} from "../../chunk-EE3V3DXK.js";
|
|
82
87
|
import {
|
|
83
88
|
AgentBnBError,
|
|
84
89
|
AnyCardSchema
|
|
85
|
-
} from "../../chunk-
|
|
90
|
+
} from "../../chunk-I7KWA7OB.js";
|
|
86
91
|
|
|
87
92
|
// skills/agentbnb/bootstrap.ts
|
|
88
93
|
import { join as join7, basename as basename2, dirname as dirname3 } from "path";
|
|
@@ -265,6 +270,9 @@ function isPidFileContent(value) {
|
|
|
265
270
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
266
271
|
|
|
267
272
|
// src/skills/executor.ts
|
|
273
|
+
function buildTimeoutError(skillId, timeoutMs) {
|
|
274
|
+
return `Skill "${skillId}" timed out after ${timeoutMs}ms`;
|
|
275
|
+
}
|
|
268
276
|
var SkillExecutor = class {
|
|
269
277
|
skillMap;
|
|
270
278
|
modeMap;
|
|
@@ -323,7 +331,20 @@ var SkillExecutor = class {
|
|
|
323
331
|
this.concurrencyGuard.acquire(skillId);
|
|
324
332
|
}
|
|
325
333
|
try {
|
|
326
|
-
const
|
|
334
|
+
const configuredTimeoutMs = typeof config.timeout_ms === "number" ? config.timeout_ms : void 0;
|
|
335
|
+
const modeExecution = mode.execute(config, params, onProgress);
|
|
336
|
+
const modeResult = configuredTimeoutMs === void 0 ? await modeExecution : await new Promise((resolve2, reject) => {
|
|
337
|
+
const timeout = setTimeout(() => {
|
|
338
|
+
reject(new Error(buildTimeoutError(skillId, configuredTimeoutMs)));
|
|
339
|
+
}, configuredTimeoutMs);
|
|
340
|
+
modeExecution.then((value) => {
|
|
341
|
+
clearTimeout(timeout);
|
|
342
|
+
resolve2(value);
|
|
343
|
+
}).catch((err) => {
|
|
344
|
+
clearTimeout(timeout);
|
|
345
|
+
reject(err);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
327
348
|
return {
|
|
328
349
|
...modeResult,
|
|
329
350
|
latency_ms: Date.now() - startTime
|
|
@@ -394,7 +415,8 @@ var CapabilityDeclarationSchema = {
|
|
|
394
415
|
description: z.string().optional(),
|
|
395
416
|
capability_types: z.array(z.string()).optional(),
|
|
396
417
|
requires_capabilities: z.array(z.string()).optional(),
|
|
397
|
-
visibility: z.enum(["public", "private"]).optional()
|
|
418
|
+
visibility: z.enum(["public", "private"]).optional(),
|
|
419
|
+
expected_duration_ms: z.number().positive().optional()
|
|
398
420
|
};
|
|
399
421
|
var ApiSkillConfigSchema = z.object({
|
|
400
422
|
id: z.string().min(1),
|
|
@@ -678,6 +700,15 @@ var ApiExecutor = class {
|
|
|
678
700
|
import { execFile } from "child_process";
|
|
679
701
|
import { promisify } from "util";
|
|
680
702
|
var execFileAsync = promisify(execFile);
|
|
703
|
+
function isTimedOutCommandError(err) {
|
|
704
|
+
if (!(err instanceof Error)) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
const timeoutCode = err.code;
|
|
708
|
+
const signal = err.signal;
|
|
709
|
+
const killed = err.killed;
|
|
710
|
+
return timeoutCode === "ETIMEDOUT" || err.message.includes("timed out") || killed === true && typeof signal === "string";
|
|
711
|
+
}
|
|
681
712
|
function shellEscape(value) {
|
|
682
713
|
return "'" + value.replace(/'/g, "'\\''") + "'";
|
|
683
714
|
}
|
|
@@ -729,6 +760,8 @@ var PipelineExecutor = class {
|
|
|
729
760
|
async execute(config, params, onProgress) {
|
|
730
761
|
const pipelineConfig = config;
|
|
731
762
|
const steps = pipelineConfig.steps ?? [];
|
|
763
|
+
const pipelineTimeoutMs = pipelineConfig.timeout_ms;
|
|
764
|
+
const deadline = typeof pipelineTimeoutMs === "number" ? Date.now() + pipelineTimeoutMs : void 0;
|
|
732
765
|
if (steps.length === 0) {
|
|
733
766
|
return { success: true, result: null };
|
|
734
767
|
}
|
|
@@ -750,11 +783,41 @@ var PipelineExecutor = class {
|
|
|
750
783
|
context
|
|
751
784
|
);
|
|
752
785
|
let stepResult;
|
|
786
|
+
const runWithRemainingDeadline = async (operation) => {
|
|
787
|
+
if (deadline === void 0) {
|
|
788
|
+
return operation();
|
|
789
|
+
}
|
|
790
|
+
const remainingMs = deadline - Date.now();
|
|
791
|
+
if (remainingMs <= 0) {
|
|
792
|
+
throw new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`);
|
|
793
|
+
}
|
|
794
|
+
return new Promise((resolve2, reject) => {
|
|
795
|
+
const timeout = setTimeout(() => {
|
|
796
|
+
reject(new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`));
|
|
797
|
+
}, remainingMs);
|
|
798
|
+
operation().then((value) => {
|
|
799
|
+
clearTimeout(timeout);
|
|
800
|
+
resolve2(value);
|
|
801
|
+
}).catch((err) => {
|
|
802
|
+
clearTimeout(timeout);
|
|
803
|
+
reject(err);
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
};
|
|
753
807
|
if ("skill_id" in step && step.skill_id) {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
808
|
+
let subResult;
|
|
809
|
+
try {
|
|
810
|
+
subResult = await runWithRemainingDeadline(() => this.skillExecutor.execute(
|
|
811
|
+
step.skill_id,
|
|
812
|
+
resolvedInputs
|
|
813
|
+
));
|
|
814
|
+
} catch (err) {
|
|
815
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
816
|
+
return {
|
|
817
|
+
success: false,
|
|
818
|
+
error: `Step ${i} failed: ${message}`
|
|
819
|
+
};
|
|
820
|
+
}
|
|
758
821
|
if (!subResult.success) {
|
|
759
822
|
return {
|
|
760
823
|
success: false,
|
|
@@ -768,10 +831,16 @@ var PipelineExecutor = class {
|
|
|
768
831
|
context
|
|
769
832
|
);
|
|
770
833
|
try {
|
|
771
|
-
const
|
|
834
|
+
const remainingMs = deadline === void 0 ? void 0 : deadline - Date.now();
|
|
835
|
+
if (remainingMs !== void 0 && remainingMs <= 0) {
|
|
836
|
+
throw new Error(`pipeline timed out after ${pipelineTimeoutMs}ms`);
|
|
837
|
+
}
|
|
838
|
+
const { stdout } = await execFileAsync("/bin/sh", ["-c", interpolatedCommand], {
|
|
839
|
+
timeout: remainingMs !== void 0 ? remainingMs : 3e4
|
|
840
|
+
});
|
|
772
841
|
stepResult = stdout.trim();
|
|
773
842
|
} catch (err) {
|
|
774
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
843
|
+
const message = pipelineTimeoutMs !== void 0 && isTimedOutCommandError(err) ? `pipeline timed out after ${pipelineTimeoutMs}ms` : err instanceof Error ? err.message : String(err);
|
|
775
844
|
return {
|
|
776
845
|
success: false,
|
|
777
846
|
error: `Step ${i} failed: ${message}`
|
|
@@ -858,17 +927,43 @@ function executeProcess(config, payload) {
|
|
|
858
927
|
error: `Invalid agent name: "${config.agent_name}" (only alphanumeric, hyphens, underscores, dots allowed)`
|
|
859
928
|
};
|
|
860
929
|
}
|
|
861
|
-
const
|
|
930
|
+
const skillId = config.id;
|
|
931
|
+
const message = `[AgentBnB Rental Request]
|
|
932
|
+
You are executing the "${skillId}" skill for an AgentBnB network rental.
|
|
933
|
+
Read your skills/${skillId}/SKILL.md for detailed instructions.
|
|
934
|
+
|
|
935
|
+
Input parameters:
|
|
936
|
+
${JSON.stringify(payload.params ?? {}, null, 2)}
|
|
937
|
+
|
|
938
|
+
IMPORTANT: Return ONLY a JSON object as your response.
|
|
939
|
+
Do NOT include explanations, markdown formatting, or code blocks.
|
|
940
|
+
The JSON should contain the output fields specified in your SKILL.md.
|
|
941
|
+
If you cannot complete the task, return: {"error": "reason"}`;
|
|
862
942
|
try {
|
|
863
|
-
const stdout = execFileSync("openclaw", [
|
|
943
|
+
const stdout = execFileSync("openclaw", [
|
|
944
|
+
"agent",
|
|
945
|
+
"--agent",
|
|
946
|
+
config.agent_name,
|
|
947
|
+
"--message",
|
|
948
|
+
message,
|
|
949
|
+
"--json",
|
|
950
|
+
"--local"
|
|
951
|
+
], {
|
|
864
952
|
timeout: timeoutMs
|
|
865
953
|
});
|
|
866
954
|
const text = stdout.toString().trim();
|
|
867
|
-
|
|
868
|
-
|
|
955
|
+
try {
|
|
956
|
+
const parsed = JSON.parse(text);
|
|
957
|
+
return { success: true, result: parsed };
|
|
958
|
+
} catch {
|
|
959
|
+
return {
|
|
960
|
+
success: false,
|
|
961
|
+
error: `OpenClaw process channel returned invalid JSON: ${text}`
|
|
962
|
+
};
|
|
963
|
+
}
|
|
869
964
|
} catch (err) {
|
|
870
|
-
const
|
|
871
|
-
return { success: false, error:
|
|
965
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
966
|
+
return { success: false, error: message2 };
|
|
872
967
|
}
|
|
873
968
|
}
|
|
874
969
|
async function executeTelegram(config, payload) {
|
|
@@ -1277,23 +1372,27 @@ var AgentRuntime = class {
|
|
|
1277
1372
|
}
|
|
1278
1373
|
const modes = /* @__PURE__ */ new Map();
|
|
1279
1374
|
if (this.conductorEnabled) {
|
|
1280
|
-
const { ConductorMode } = await import("../../conductor-mode-
|
|
1281
|
-
const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-
|
|
1375
|
+
const { ConductorMode } = await import("../../conductor-mode-OPGQJFLA.js");
|
|
1376
|
+
const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-BN643ZOY.js");
|
|
1282
1377
|
const { loadPeers: loadPeers2 } = await import("../../peers-CJ7T4RJO.js");
|
|
1283
1378
|
registerConductorCard(this.registryDb);
|
|
1284
1379
|
const resolveAgentUrl = (owner) => {
|
|
1285
1380
|
const peers = loadPeers2();
|
|
1286
|
-
const
|
|
1381
|
+
const matchingCards = listCards(this.registryDb, owner);
|
|
1382
|
+
const candidateNames = /* @__PURE__ */ new Set([owner.toLowerCase()]);
|
|
1383
|
+
for (const card of matchingCards) {
|
|
1384
|
+
candidateNames.add(card.owner.toLowerCase());
|
|
1385
|
+
if (typeof card.agent_id === "string" && card.agent_id.length > 0) {
|
|
1386
|
+
candidateNames.add(card.agent_id.toLowerCase());
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
const peer = peers.find((p) => candidateNames.has(p.name.toLowerCase()));
|
|
1287
1390
|
if (!peer) {
|
|
1288
1391
|
throw new Error(
|
|
1289
1392
|
`No peer found for agent owner "${owner}". Add with: agentbnb connect ${owner} <url> <token>`
|
|
1290
1393
|
);
|
|
1291
1394
|
}
|
|
1292
|
-
const
|
|
1293
|
-
"SELECT id FROM capability_cards WHERE owner = ? LIMIT 1"
|
|
1294
|
-
);
|
|
1295
|
-
const row = stmt.get(owner);
|
|
1296
|
-
const cardId = row?.id ?? owner;
|
|
1395
|
+
const cardId = matchingCards[0]?.id ?? owner;
|
|
1297
1396
|
return { url: peer.url, cardId };
|
|
1298
1397
|
};
|
|
1299
1398
|
const conductorMode = new ConductorMode({
|
|
@@ -1335,7 +1434,8 @@ var AgentRuntime = class {
|
|
|
1335
1434
|
}
|
|
1336
1435
|
/**
|
|
1337
1436
|
* Recovers orphaned escrows by releasing them.
|
|
1338
|
-
* Orphaned escrows are 'held' escrows older than the
|
|
1437
|
+
* Orphaned escrows are stale 'held' or 'abandoned' escrows older than the
|
|
1438
|
+
* configured age threshold. In-flight started/progressing escrows are not touched.
|
|
1339
1439
|
* Errors during individual release are swallowed (escrow may have settled between query and release).
|
|
1340
1440
|
*/
|
|
1341
1441
|
async recoverOrphanedEscrows() {
|
|
@@ -1343,7 +1443,7 @@ var AgentRuntime = class {
|
|
|
1343
1443
|
Date.now() - this.orphanedEscrowAgeMinutes * 60 * 1e3
|
|
1344
1444
|
).toISOString();
|
|
1345
1445
|
const orphaned = this.creditDb.prepare(
|
|
1346
|
-
"SELECT id FROM credit_escrow WHERE status
|
|
1446
|
+
"SELECT id FROM credit_escrow WHERE status IN ('held', 'abandoned') AND created_at < ?"
|
|
1347
1447
|
).all(cutoff);
|
|
1348
1448
|
for (const row of orphaned) {
|
|
1349
1449
|
try {
|
|
@@ -1942,10 +2042,11 @@ async function verifyIdentity(request, reply, options) {
|
|
|
1942
2042
|
return false;
|
|
1943
2043
|
}
|
|
1944
2044
|
const claimedRequester = extractClaimedRequester(request);
|
|
1945
|
-
if (claimedRequester) {
|
|
2045
|
+
if (claimedRequester && knownAgent !== null) {
|
|
1946
2046
|
const matchesAgentId = claimedRequester === agentId;
|
|
1947
|
-
const
|
|
1948
|
-
|
|
2047
|
+
const matchesDisplayName = knownAgent.display_name === claimedRequester;
|
|
2048
|
+
const matchesLegacyOwner = knownAgent.legacy_owner === claimedRequester;
|
|
2049
|
+
if (!matchesAgentId && !matchesDisplayName && !matchesLegacyOwner) {
|
|
1949
2050
|
await reply.code(401).send({ error: "Identity does not match requester" });
|
|
1950
2051
|
return false;
|
|
1951
2052
|
}
|
|
@@ -2439,14 +2540,16 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
|
|
|
2439
2540
|
throw new Error("Invalid consumer signature on escrow settle");
|
|
2440
2541
|
}
|
|
2441
2542
|
}
|
|
2442
|
-
const escrowRow = creditDb.prepare(
|
|
2543
|
+
const escrowRow = creditDb.prepare(
|
|
2544
|
+
"SELECT amount, owner FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
2545
|
+
).get(escrowId);
|
|
2443
2546
|
if (!escrowRow) {
|
|
2444
2547
|
throw new Error(`Escrow not found or already settled: ${escrowId}`);
|
|
2445
2548
|
}
|
|
2446
|
-
const
|
|
2549
|
+
const NETWORK_FEE_RATE2 = 0.05;
|
|
2447
2550
|
if (success) {
|
|
2448
2551
|
settleEscrow(creditDb, escrowId, providerAgentId);
|
|
2449
|
-
const networkFee = Math.floor(escrowRow.amount *
|
|
2552
|
+
const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE2);
|
|
2450
2553
|
const providerAmount = escrowRow.amount - networkFee;
|
|
2451
2554
|
return {
|
|
2452
2555
|
escrow_id: escrowId,
|
|
@@ -2770,7 +2873,16 @@ function handleJobRelayResponse(opts) {
|
|
|
2770
2873
|
// src/relay/websocket-relay.ts
|
|
2771
2874
|
var RATE_LIMIT_MAX = 60;
|
|
2772
2875
|
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
2773
|
-
var
|
|
2876
|
+
var RELAY_IDLE_TIMEOUT_MS = 3e4;
|
|
2877
|
+
var RELAY_HARD_TIMEOUT_MS = 3e5;
|
|
2878
|
+
var RELAY_DISCONNECT_GRACE_MS = RELAY_HARD_TIMEOUT_MS + 3e4;
|
|
2879
|
+
function readTimeoutOverride(envKey, fallbackMs) {
|
|
2880
|
+
const raw = process.env[envKey];
|
|
2881
|
+
if (!raw) return fallbackMs;
|
|
2882
|
+
const parsed = Number(raw);
|
|
2883
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallbackMs;
|
|
2884
|
+
return Math.floor(parsed);
|
|
2885
|
+
}
|
|
2774
2886
|
function registerWebSocketRelay(server, db, creditDb) {
|
|
2775
2887
|
const connections = /* @__PURE__ */ new Map();
|
|
2776
2888
|
const agentIdToOwner = /* @__PURE__ */ new Map();
|
|
@@ -2784,6 +2896,136 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2784
2896
|
if (connections.has(target)) return target;
|
|
2785
2897
|
return void 0;
|
|
2786
2898
|
}
|
|
2899
|
+
function clearPendingTimers(pending) {
|
|
2900
|
+
clearTimeout(pending.timeout);
|
|
2901
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
2902
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
2903
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
2904
|
+
}
|
|
2905
|
+
function setPendingTimer(pending, timerType, timer) {
|
|
2906
|
+
const existing = pending[timerType];
|
|
2907
|
+
if (existing) clearTimeout(existing);
|
|
2908
|
+
pending[timerType] = timer;
|
|
2909
|
+
pending.timeout = timer;
|
|
2910
|
+
}
|
|
2911
|
+
function scheduleIdleTimeout(requestId, pending) {
|
|
2912
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_IDLE_TIMEOUT_MS", RELAY_IDLE_TIMEOUT_MS);
|
|
2913
|
+
const timer = setTimeout(() => {
|
|
2914
|
+
const current = pendingRequests.get(requestId);
|
|
2915
|
+
if (!current || (current.lifecycle ?? "held") !== "held") return;
|
|
2916
|
+
pendingRequests.delete(requestId);
|
|
2917
|
+
clearPendingTimers(current);
|
|
2918
|
+
if (current.escrowId && creditDb) {
|
|
2919
|
+
try {
|
|
2920
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2921
|
+
} catch (e) {
|
|
2922
|
+
console.error("[relay] escrow release on idle timeout failed:", e);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
const originWs = connections.get(current.originOwner);
|
|
2926
|
+
if (originWs && originWs.readyState === 1) {
|
|
2927
|
+
sendMessage(originWs, {
|
|
2928
|
+
type: "response",
|
|
2929
|
+
id: requestId,
|
|
2930
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
}, timeoutMs);
|
|
2934
|
+
setPendingTimer(pending, "idleTimeout", timer);
|
|
2935
|
+
}
|
|
2936
|
+
function scheduleHardTimeout(requestId, pending) {
|
|
2937
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_HARD_TIMEOUT_MS", RELAY_HARD_TIMEOUT_MS);
|
|
2938
|
+
const timer = setTimeout(() => {
|
|
2939
|
+
const current = pendingRequests.get(requestId);
|
|
2940
|
+
if (!current || current.lifecycle === "abandoned") return;
|
|
2941
|
+
pendingRequests.delete(requestId);
|
|
2942
|
+
clearPendingTimers(current);
|
|
2943
|
+
if (current.escrowId && creditDb) {
|
|
2944
|
+
try {
|
|
2945
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2946
|
+
} catch (e) {
|
|
2947
|
+
console.error("[relay] escrow release on hard timeout failed:", e);
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
const originWs = connections.get(current.originOwner);
|
|
2951
|
+
if (originWs && originWs.readyState === 1) {
|
|
2952
|
+
sendMessage(originWs, {
|
|
2953
|
+
type: "response",
|
|
2954
|
+
id: requestId,
|
|
2955
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2958
|
+
}, timeoutMs);
|
|
2959
|
+
setPendingTimer(pending, "hardTimeout", timer);
|
|
2960
|
+
}
|
|
2961
|
+
function scheduleGraceTimeout(requestId, pending) {
|
|
2962
|
+
const timeoutMs = readTimeoutOverride(
|
|
2963
|
+
"AGENTBNB_RELAY_DISCONNECT_GRACE_MS",
|
|
2964
|
+
RELAY_DISCONNECT_GRACE_MS
|
|
2965
|
+
);
|
|
2966
|
+
const timer = setTimeout(() => {
|
|
2967
|
+
const current = pendingRequests.get(requestId);
|
|
2968
|
+
if (!current || current.lifecycle !== "abandoned") return;
|
|
2969
|
+
pendingRequests.delete(requestId);
|
|
2970
|
+
clearPendingTimers(current);
|
|
2971
|
+
if (current.escrowId && creditDb) {
|
|
2972
|
+
try {
|
|
2973
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2974
|
+
} catch (e) {
|
|
2975
|
+
console.error("[relay] escrow release after grace timeout failed:", e);
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
}, timeoutMs);
|
|
2979
|
+
setPendingTimer(pending, "graceTimeout", timer);
|
|
2980
|
+
}
|
|
2981
|
+
function transitionPendingToStarted(requestId, pending) {
|
|
2982
|
+
if (pending.lifecycle === "started" || pending.lifecycle === "progressing" || pending.lifecycle === "abandoned") {
|
|
2983
|
+
return;
|
|
2984
|
+
}
|
|
2985
|
+
pending.lifecycle = "started";
|
|
2986
|
+
pending.startedAt = Date.now();
|
|
2987
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
2988
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
2989
|
+
if (pending.escrowId && creditDb) {
|
|
2990
|
+
try {
|
|
2991
|
+
markEscrowStarted(creditDb, pending.escrowId);
|
|
2992
|
+
} catch (e) {
|
|
2993
|
+
console.error("[relay] escrow transition to started failed:", e);
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
scheduleHardTimeout(requestId, pending);
|
|
2997
|
+
}
|
|
2998
|
+
function transitionPendingToProgressing(requestId, pending) {
|
|
2999
|
+
if (pending.lifecycle === "abandoned") {
|
|
3000
|
+
return;
|
|
3001
|
+
}
|
|
3002
|
+
if ((pending.lifecycle ?? "held") === "held") {
|
|
3003
|
+
transitionPendingToStarted(requestId, pending);
|
|
3004
|
+
}
|
|
3005
|
+
pending.lifecycle = "progressing";
|
|
3006
|
+
if (pending.escrowId && creditDb) {
|
|
3007
|
+
try {
|
|
3008
|
+
markEscrowProgressing(creditDb, pending.escrowId);
|
|
3009
|
+
} catch (e) {
|
|
3010
|
+
console.error("[relay] escrow transition to progressing failed:", e);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
function transitionPendingToAbandoned(requestId, pending) {
|
|
3015
|
+
if (pending.lifecycle === "abandoned") return;
|
|
3016
|
+
pending.lifecycle = "abandoned";
|
|
3017
|
+
pending.abandonedAt = Date.now();
|
|
3018
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
3019
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
3020
|
+
if (pending.escrowId && creditDb) {
|
|
3021
|
+
try {
|
|
3022
|
+
markEscrowAbandoned(creditDb, pending.escrowId);
|
|
3023
|
+
} catch (e) {
|
|
3024
|
+
console.error("[relay] escrow transition to abandoned failed:", e);
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
scheduleGraceTimeout(requestId, pending);
|
|
3028
|
+
}
|
|
2787
3029
|
function checkRateLimit(owner) {
|
|
2788
3030
|
const now = Date.now();
|
|
2789
3031
|
const entry = rateLimits.get(owner);
|
|
@@ -2833,15 +3075,20 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2833
3075
|
} catch {
|
|
2834
3076
|
}
|
|
2835
3077
|
}
|
|
2836
|
-
function upsertCard(cardData, owner) {
|
|
2837
|
-
const parsed = AnyCardSchema.safeParse(
|
|
3078
|
+
function upsertCard(cardData, owner, agentId) {
|
|
3079
|
+
const parsed = AnyCardSchema.safeParse(
|
|
3080
|
+
agentId ? { ...cardData, agent_id: agentId } : cardData
|
|
3081
|
+
);
|
|
2838
3082
|
if (!parsed.success) {
|
|
2839
3083
|
throw new AgentBnBError(
|
|
2840
3084
|
`Card validation failed: ${parsed.error.message}`,
|
|
2841
3085
|
"VALIDATION_ERROR"
|
|
2842
3086
|
);
|
|
2843
3087
|
}
|
|
2844
|
-
const card =
|
|
3088
|
+
const card = attachCanonicalAgentId(db, {
|
|
3089
|
+
...parsed.data,
|
|
3090
|
+
availability: { ...parsed.data.availability, online: true }
|
|
3091
|
+
});
|
|
2845
3092
|
const cardId = card.id;
|
|
2846
3093
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2847
3094
|
const existing = db.prepare("SELECT id FROM capability_cards WHERE id = ?").get(cardId);
|
|
@@ -2895,7 +3142,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2895
3142
|
agentIdToOwner.set(agentEntry.agent_id, owner);
|
|
2896
3143
|
for (const agentCard of agentEntry.cards) {
|
|
2897
3144
|
try {
|
|
2898
|
-
upsertCard(agentCard, owner);
|
|
3145
|
+
upsertCard(agentCard, owner, agentEntry.agent_id);
|
|
2899
3146
|
} catch {
|
|
2900
3147
|
}
|
|
2901
3148
|
}
|
|
@@ -2909,7 +3156,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2909
3156
|
}
|
|
2910
3157
|
let cardId;
|
|
2911
3158
|
try {
|
|
2912
|
-
cardId = upsertCard(card, owner);
|
|
3159
|
+
cardId = upsertCard(card, owner, msg.agent_id);
|
|
2913
3160
|
} catch (err) {
|
|
2914
3161
|
console.error(`[relay] card validation failed for ${owner}:`, err instanceof Error ? err.message : err);
|
|
2915
3162
|
cardId = card.id ?? owner;
|
|
@@ -2919,7 +3166,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2919
3166
|
if (msg.cards && msg.cards.length > 0) {
|
|
2920
3167
|
for (const extraCard of msg.cards) {
|
|
2921
3168
|
try {
|
|
2922
|
-
upsertCard(extraCard, owner);
|
|
3169
|
+
upsertCard(extraCard, owner, msg.agent_id);
|
|
2923
3170
|
} catch {
|
|
2924
3171
|
}
|
|
2925
3172
|
}
|
|
@@ -2974,23 +3221,17 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2974
3221
|
console.error("[relay] credit hold error (non-fatal):", err);
|
|
2975
3222
|
}
|
|
2976
3223
|
}
|
|
2977
|
-
const
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
type: "response",
|
|
2989
|
-
id: msg.id,
|
|
2990
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
2991
|
-
});
|
|
2992
|
-
}, RELAY_TIMEOUT_MS);
|
|
2993
|
-
pendingRequests.set(msg.id, { originOwner: fromOwner, creditOwner, timeout, escrowId, targetOwner: msg.target_owner });
|
|
3224
|
+
const pending = {
|
|
3225
|
+
originOwner: fromOwner,
|
|
3226
|
+
creditOwner,
|
|
3227
|
+
timeout: setTimeout(() => void 0, 1),
|
|
3228
|
+
escrowId,
|
|
3229
|
+
targetOwner: targetKey ?? msg.target_owner,
|
|
3230
|
+
lifecycle: "held",
|
|
3231
|
+
createdAt: Date.now()
|
|
3232
|
+
};
|
|
3233
|
+
pendingRequests.set(msg.id, pending);
|
|
3234
|
+
scheduleIdleTimeout(msg.id, pending);
|
|
2994
3235
|
sendMessage(targetWs, {
|
|
2995
3236
|
type: "incoming_request",
|
|
2996
3237
|
id: msg.id,
|
|
@@ -3002,30 +3243,23 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3002
3243
|
escrow_receipt: msg.escrow_receipt
|
|
3003
3244
|
});
|
|
3004
3245
|
}
|
|
3246
|
+
function handleRelayStarted(msg) {
|
|
3247
|
+
const pending = pendingRequests.get(msg.id);
|
|
3248
|
+
if (!pending) return;
|
|
3249
|
+
transitionPendingToStarted(msg.id, pending);
|
|
3250
|
+
const originWs = connections.get(pending.originOwner);
|
|
3251
|
+
if (originWs && originWs.readyState === 1) {
|
|
3252
|
+
sendMessage(originWs, {
|
|
3253
|
+
type: "relay_started",
|
|
3254
|
+
id: msg.id,
|
|
3255
|
+
message: msg.message
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3005
3259
|
function handleRelayProgress(msg) {
|
|
3006
3260
|
const pending = pendingRequests.get(msg.id);
|
|
3007
3261
|
if (!pending) return;
|
|
3008
|
-
|
|
3009
|
-
const newTimeout = setTimeout(() => {
|
|
3010
|
-
const p = pendingRequests.get(msg.id);
|
|
3011
|
-
pendingRequests.delete(msg.id);
|
|
3012
|
-
if (p?.escrowId && creditDb) {
|
|
3013
|
-
try {
|
|
3014
|
-
releaseForRelay(creditDb, p.escrowId);
|
|
3015
|
-
} catch (e) {
|
|
3016
|
-
console.error("[relay] escrow release on progress timeout failed:", e);
|
|
3017
|
-
}
|
|
3018
|
-
}
|
|
3019
|
-
const originWs2 = connections.get(pending.originOwner);
|
|
3020
|
-
if (originWs2 && originWs2.readyState === 1) {
|
|
3021
|
-
sendMessage(originWs2, {
|
|
3022
|
-
type: "response",
|
|
3023
|
-
id: msg.id,
|
|
3024
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
3025
|
-
});
|
|
3026
|
-
}
|
|
3027
|
-
}, RELAY_TIMEOUT_MS);
|
|
3028
|
-
pending.timeout = newTimeout;
|
|
3262
|
+
transitionPendingToProgressing(msg.id, pending);
|
|
3029
3263
|
const originWs = connections.get(pending.originOwner);
|
|
3030
3264
|
if (originWs && originWs.readyState === 1) {
|
|
3031
3265
|
sendMessage(originWs, {
|
|
@@ -3039,7 +3273,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3039
3273
|
function handleRelayResponse(msg) {
|
|
3040
3274
|
const pending = pendingRequests.get(msg.id);
|
|
3041
3275
|
if (!pending) return;
|
|
3042
|
-
|
|
3276
|
+
clearPendingTimers(pending);
|
|
3043
3277
|
pendingRequests.delete(msg.id);
|
|
3044
3278
|
if (pending.jobId && creditDb) {
|
|
3045
3279
|
try {
|
|
@@ -3102,16 +3336,15 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3102
3336
|
connections.delete(owner);
|
|
3103
3337
|
rateLimits.delete(owner);
|
|
3104
3338
|
agentCapacities.delete(owner);
|
|
3105
|
-
for (const [agentId,
|
|
3106
|
-
if (
|
|
3339
|
+
for (const [agentId, mappedOwner] of Array.from(agentIdToOwner.entries())) {
|
|
3340
|
+
if (mappedOwner === owner) {
|
|
3107
3341
|
agentIdToOwner.delete(agentId);
|
|
3108
|
-
break;
|
|
3109
3342
|
}
|
|
3110
3343
|
}
|
|
3111
3344
|
markOwnerOffline(owner);
|
|
3112
3345
|
for (const [reqId, pending] of pendingRequests) {
|
|
3113
3346
|
if (pending.targetOwner === owner) {
|
|
3114
|
-
|
|
3347
|
+
clearPendingTimers(pending);
|
|
3115
3348
|
pendingRequests.delete(reqId);
|
|
3116
3349
|
if (pending.escrowId && creditDb) {
|
|
3117
3350
|
try {
|
|
@@ -3129,14 +3362,19 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3129
3362
|
});
|
|
3130
3363
|
}
|
|
3131
3364
|
} else if (pending.originOwner === owner) {
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3365
|
+
const lifecycle = pending.lifecycle ?? "held";
|
|
3366
|
+
if (lifecycle === "held") {
|
|
3367
|
+
clearPendingTimers(pending);
|
|
3368
|
+
pendingRequests.delete(reqId);
|
|
3369
|
+
if (pending.escrowId && creditDb) {
|
|
3370
|
+
try {
|
|
3371
|
+
releaseForRelay(creditDb, pending.escrowId);
|
|
3372
|
+
} catch (e) {
|
|
3373
|
+
console.error("[relay] escrow release on requester disconnect failed:", e);
|
|
3374
|
+
}
|
|
3139
3375
|
}
|
|
3376
|
+
} else {
|
|
3377
|
+
transitionPendingToAbandoned(reqId, pending);
|
|
3140
3378
|
}
|
|
3141
3379
|
}
|
|
3142
3380
|
}
|
|
@@ -3179,7 +3417,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3179
3417
|
return;
|
|
3180
3418
|
}
|
|
3181
3419
|
try {
|
|
3182
|
-
const escrow = creditDb.prepare(
|
|
3420
|
+
const escrow = creditDb.prepare(
|
|
3421
|
+
"SELECT card_id FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
3422
|
+
).get(msg.escrow_id);
|
|
3183
3423
|
if (!escrow) {
|
|
3184
3424
|
sendMessage(ws, { type: "error", code: "escrow_not_found", message: `Escrow not found: ${msg.escrow_id}`, request_id: msg.request_id });
|
|
3185
3425
|
return;
|
|
@@ -3276,6 +3516,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3276
3516
|
case "relay_response":
|
|
3277
3517
|
handleRelayResponse(msg);
|
|
3278
3518
|
break;
|
|
3519
|
+
case "relay_started":
|
|
3520
|
+
handleRelayStarted(msg);
|
|
3521
|
+
break;
|
|
3279
3522
|
case "relay_progress":
|
|
3280
3523
|
handleRelayProgress(msg);
|
|
3281
3524
|
break;
|
|
@@ -3322,7 +3565,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3322
3565
|
}
|
|
3323
3566
|
connections.clear();
|
|
3324
3567
|
for (const [, pending] of pendingRequests) {
|
|
3325
|
-
|
|
3568
|
+
clearPendingTimers(pending);
|
|
3326
3569
|
}
|
|
3327
3570
|
pendingRequests.clear();
|
|
3328
3571
|
rateLimits.clear();
|
|
@@ -4621,6 +4864,9 @@ function stripInternal(card) {
|
|
|
4621
4864
|
const { _internal: _, ...publicCard } = card;
|
|
4622
4865
|
return publicCard;
|
|
4623
4866
|
}
|
|
4867
|
+
function buildSqlPlaceholders(count) {
|
|
4868
|
+
return Array.from({ length: count }, () => "?").join(", ");
|
|
4869
|
+
}
|
|
4624
4870
|
function createRegistryServer(opts) {
|
|
4625
4871
|
const { registryDb: db, silent = false } = opts;
|
|
4626
4872
|
const server = Fastify2({ logger: !silent });
|
|
@@ -5030,11 +5276,11 @@ function createRegistryServer(opts) {
|
|
|
5030
5276
|
const card = result.data;
|
|
5031
5277
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5032
5278
|
if (card.spec_version === "2.0") {
|
|
5033
|
-
const cardWithTimestamps = {
|
|
5279
|
+
const cardWithTimestamps = attachCanonicalAgentId(db, {
|
|
5034
5280
|
...card,
|
|
5035
5281
|
created_at: card.created_at ?? now,
|
|
5036
5282
|
updated_at: now
|
|
5037
|
-
};
|
|
5283
|
+
});
|
|
5038
5284
|
db.prepare(
|
|
5039
5285
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
5040
5286
|
VALUES (?, ?, ?, ?, ?)`
|
|
@@ -5155,19 +5401,16 @@ function createRegistryServer(opts) {
|
|
|
5155
5401
|
if (ownerCards.length === 0) {
|
|
5156
5402
|
return reply.status(404).send({ error: "Agent not found" });
|
|
5157
5403
|
}
|
|
5158
|
-
const
|
|
5159
|
-
|
|
5404
|
+
const resolvedOwner = ownerCards[0]?.owner ?? owner;
|
|
5405
|
+
const ownerCardIds = ownerCards.map((card) => card.id);
|
|
5406
|
+
const cardIdPlaceholders = buildSqlPlaceholders(ownerCardIds.length);
|
|
5407
|
+
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();
|
|
5408
|
+
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;
|
|
5409
|
+
const lastActiveStmt = db.prepare(
|
|
5410
|
+
`SELECT MAX(created_at) as last_req FROM request_log WHERE card_id IN (${cardIdPlaceholders})`
|
|
5160
5411
|
);
|
|
5161
|
-
const
|
|
5162
|
-
const
|
|
5163
|
-
const lastActiveStmt = db.prepare(`
|
|
5164
|
-
SELECT MAX(rl.created_at) as last_req
|
|
5165
|
-
FROM request_log rl
|
|
5166
|
-
INNER JOIN capability_cards cc ON rl.card_id = cc.id
|
|
5167
|
-
WHERE cc.owner = ?
|
|
5168
|
-
`);
|
|
5169
|
-
const lastActiveRow = lastActiveStmt.get(owner);
|
|
5170
|
-
const lastActive = lastActiveRow?.last_req ?? memberRow?.latest ?? joinedAt;
|
|
5412
|
+
const lastActiveRow = lastActiveStmt.get(...ownerCardIds);
|
|
5413
|
+
const lastActive = lastActiveRow?.last_req ?? latestCardUpdate ?? joinedAt;
|
|
5171
5414
|
const metricsStmt = db.prepare(`
|
|
5172
5415
|
SELECT
|
|
5173
5416
|
SUM(CASE WHEN rl.failure_reason IS NULL OR rl.failure_reason IN ('bad_execution','auth_error')
|
|
@@ -5177,10 +5420,9 @@ function createRegistryServer(opts) {
|
|
|
5177
5420
|
COUNT(DISTINCT rl.requester) as unique_requesters,
|
|
5178
5421
|
COUNT(DISTINCT CASE WHEN rl.status = 'success' THEN rl.requester END) as repeat_success_requesters
|
|
5179
5422
|
FROM request_log rl
|
|
5180
|
-
|
|
5181
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5423
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5182
5424
|
`);
|
|
5183
|
-
const metricsRow = metricsStmt.get(
|
|
5425
|
+
const metricsRow = metricsStmt.get(...ownerCardIds);
|
|
5184
5426
|
const totalExec = metricsRow?.total ?? 0;
|
|
5185
5427
|
const successExec = metricsRow?.successes ?? 0;
|
|
5186
5428
|
const successRate = totalExec > 0 ? successExec / totalExec : 0;
|
|
@@ -5194,25 +5436,23 @@ function createRegistryServer(opts) {
|
|
|
5194
5436
|
COUNT(*) as count,
|
|
5195
5437
|
SUM(CASE WHEN rl.status = 'success' THEN 1 ELSE 0 END) as success
|
|
5196
5438
|
FROM request_log rl
|
|
5197
|
-
|
|
5198
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5439
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5199
5440
|
AND rl.created_at >= DATE('now', '-7 days')
|
|
5200
5441
|
GROUP BY DATE(rl.created_at)
|
|
5201
5442
|
ORDER BY day ASC
|
|
5202
5443
|
`);
|
|
5203
|
-
const trend_7d = trendStmt.all(
|
|
5444
|
+
const trend_7d = trendStmt.all(...ownerCardIds).map((r) => ({ date: r.day, count: r.count, success: r.success }));
|
|
5204
5445
|
let performanceTier = 0;
|
|
5205
5446
|
if (totalExec > 10) performanceTier = 1;
|
|
5206
5447
|
if (totalExec > 50 && successRate >= 0.85) performanceTier = 2;
|
|
5207
5448
|
const proofsStmt = db.prepare(`
|
|
5208
5449
|
SELECT rl.card_name, rl.status, rl.latency_ms, rl.id, rl.created_at
|
|
5209
5450
|
FROM request_log rl
|
|
5210
|
-
|
|
5211
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5451
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5212
5452
|
ORDER BY rl.created_at DESC
|
|
5213
5453
|
LIMIT 10
|
|
5214
5454
|
`);
|
|
5215
|
-
const proofRows = proofsStmt.all(
|
|
5455
|
+
const proofRows = proofsStmt.all(...ownerCardIds);
|
|
5216
5456
|
const statusToOutcomeClass = (s) => {
|
|
5217
5457
|
if (s === "success") return "completed";
|
|
5218
5458
|
if (s === "timeout") return "cancelled";
|
|
@@ -5238,22 +5478,20 @@ function createRegistryServer(opts) {
|
|
|
5238
5478
|
const activityStmt = db.prepare(`
|
|
5239
5479
|
SELECT rl.id, rl.card_name, rl.requester, rl.status, rl.credits_charged, rl.created_at
|
|
5240
5480
|
FROM request_log rl
|
|
5241
|
-
|
|
5242
|
-
WHERE cc.owner = ?
|
|
5481
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
5243
5482
|
ORDER BY rl.created_at DESC
|
|
5244
5483
|
LIMIT 10
|
|
5245
5484
|
`);
|
|
5246
|
-
const recentActivity = activityStmt.all(
|
|
5485
|
+
const recentActivity = activityStmt.all(...ownerCardIds);
|
|
5247
5486
|
const skillCount = ownerCards.reduce((sum, card) => sum + (card.skills?.length ?? 1), 0);
|
|
5248
5487
|
const creditsStmt = db.prepare(`
|
|
5249
|
-
SELECT SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END) as credits_earned
|
|
5250
|
-
FROM
|
|
5251
|
-
|
|
5252
|
-
WHERE cc.owner = ?
|
|
5488
|
+
SELECT COALESCE(SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END), 0) as credits_earned
|
|
5489
|
+
FROM request_log rl
|
|
5490
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
5253
5491
|
`);
|
|
5254
|
-
const creditsRow = creditsStmt.get(
|
|
5492
|
+
const creditsRow = creditsStmt.get(...ownerCardIds);
|
|
5255
5493
|
const response = {
|
|
5256
|
-
owner,
|
|
5494
|
+
owner: resolvedOwner,
|
|
5257
5495
|
agent_name: v2Card?.agent_name,
|
|
5258
5496
|
short_description: v2Card?.short_description,
|
|
5259
5497
|
joined_at: joinedAt,
|
|
@@ -5285,7 +5523,7 @@ function createRegistryServer(opts) {
|
|
|
5285
5523
|
return reply.send({
|
|
5286
5524
|
...response,
|
|
5287
5525
|
profile: {
|
|
5288
|
-
owner,
|
|
5526
|
+
owner: resolvedOwner,
|
|
5289
5527
|
skill_count: skillCount,
|
|
5290
5528
|
success_rate: successRate > 0 ? successRate : null,
|
|
5291
5529
|
total_earned: creditsRow?.credits_earned ?? 0,
|
|
@@ -5557,7 +5795,7 @@ function createRegistryServer(opts) {
|
|
|
5557
5795
|
return { card_id: target.cardId, skill_id: target.skillId };
|
|
5558
5796
|
}
|
|
5559
5797
|
if (!relayClient) {
|
|
5560
|
-
const { RelayClient: RelayClient2 } = await import("../../websocket-client-
|
|
5798
|
+
const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
|
|
5561
5799
|
relayClient = new RelayClient2({
|
|
5562
5800
|
registryUrl: relayRegistryUrl,
|
|
5563
5801
|
owner: relayRequesterOwner,
|
|
@@ -5579,7 +5817,7 @@ function createRegistryServer(opts) {
|
|
|
5579
5817
|
});
|
|
5580
5818
|
await relayClient.connect();
|
|
5581
5819
|
}
|
|
5582
|
-
const { requestViaRelay: requestViaRelay2 } = await import("../../client-
|
|
5820
|
+
const { requestViaRelay: requestViaRelay2 } = await import("../../client-OKJJ3UP2.js");
|
|
5583
5821
|
return requestViaRelay2(relayClient, {
|
|
5584
5822
|
targetOwner: target.owner,
|
|
5585
5823
|
cardId: target.cardId,
|
|
@@ -5835,7 +6073,7 @@ function createRegistryServer(opts) {
|
|
|
5835
6073
|
if (!opts.creditDb) {
|
|
5836
6074
|
return reply.code(404).send({ error: "Credit system not enabled" });
|
|
5837
6075
|
}
|
|
5838
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
6076
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
5839
6077
|
const metrics = getReliabilityMetrics(opts.creditDb, owner);
|
|
5840
6078
|
if (!metrics) {
|
|
5841
6079
|
return reply.code(404).send({ error: "No reliability data for this provider" });
|
|
@@ -5853,38 +6091,37 @@ function createRegistryServer(opts) {
|
|
|
5853
6091
|
}
|
|
5854
6092
|
}, async (request, reply) => {
|
|
5855
6093
|
const { owner } = request.params;
|
|
5856
|
-
const
|
|
5857
|
-
"SELECT id, data FROM capability_cards WHERE owner = ?"
|
|
5858
|
-
).all(owner);
|
|
6094
|
+
const cards = listCards(db, owner);
|
|
5859
6095
|
const agents = [];
|
|
5860
|
-
for (const
|
|
6096
|
+
for (const card of cards) {
|
|
5861
6097
|
try {
|
|
5862
|
-
const
|
|
6098
|
+
const rawCard = card;
|
|
6099
|
+
const providerIdentity = typeof card.agent_id === "string" && card.agent_id.length > 0 ? card.agent_id : card.owner;
|
|
5863
6100
|
let earnings = 0;
|
|
5864
6101
|
let spend = 0;
|
|
5865
6102
|
if (opts.creditDb) {
|
|
5866
6103
|
const earningRow = opts.creditDb.prepare(
|
|
5867
6104
|
"SELECT COALESCE(SUM(amount), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'settlement' AND amount > 0"
|
|
5868
|
-
).get(
|
|
6105
|
+
).get(providerIdentity);
|
|
5869
6106
|
earnings = earningRow.total;
|
|
5870
6107
|
const spendRow = opts.creditDb.prepare(
|
|
5871
6108
|
"SELECT COALESCE(SUM(ABS(amount)), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'escrow_hold'"
|
|
5872
|
-
).get(
|
|
6109
|
+
).get(providerIdentity);
|
|
5873
6110
|
spend = spendRow.total;
|
|
5874
6111
|
}
|
|
5875
6112
|
const successCount = db.prepare(
|
|
5876
6113
|
"SELECT COUNT(*) as cnt FROM request_log WHERE card_id = ? AND status = 'success' AND (action_type IS NULL OR action_type = 'auto_share')"
|
|
5877
|
-
).get(
|
|
6114
|
+
).get(card.id).cnt;
|
|
5878
6115
|
const failureCount = db.prepare(
|
|
5879
6116
|
"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')"
|
|
5880
|
-
).get(
|
|
6117
|
+
).get(card.id).cnt;
|
|
5881
6118
|
const totalExec = successCount + failureCount;
|
|
5882
6119
|
const successRate = totalExec > 0 ? successCount / totalExec : 0;
|
|
5883
6120
|
let failureBreakdown = {};
|
|
5884
6121
|
try {
|
|
5885
6122
|
const failureRows = db.prepare(
|
|
5886
6123
|
"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"
|
|
5887
|
-
).all(
|
|
6124
|
+
).all(card.id);
|
|
5888
6125
|
for (const fr of failureRows) {
|
|
5889
6126
|
failureBreakdown[fr.failure_reason] = fr.cnt;
|
|
5890
6127
|
}
|
|
@@ -5892,12 +6129,12 @@ function createRegistryServer(opts) {
|
|
|
5892
6129
|
}
|
|
5893
6130
|
let reliability = null;
|
|
5894
6131
|
if (opts.creditDb) {
|
|
5895
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
5896
|
-
reliability = getReliabilityMetrics(opts.creditDb,
|
|
6132
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
6133
|
+
reliability = getReliabilityMetrics(opts.creditDb, providerIdentity);
|
|
5897
6134
|
}
|
|
5898
6135
|
agents.push({
|
|
5899
|
-
id:
|
|
5900
|
-
name:
|
|
6136
|
+
id: card.id,
|
|
6137
|
+
name: (typeof rawCard["name"] === "string" ? rawCard["name"] : void 0) ?? (typeof rawCard["agent_name"] === "string" ? rawCard["agent_name"] : void 0) ?? card.owner,
|
|
5901
6138
|
online: card.availability?.online ?? false,
|
|
5902
6139
|
current_load: 0,
|
|
5903
6140
|
// Will be populated from relay heartbeat data in future
|
|
@@ -6175,6 +6412,32 @@ import { spawn as spawn2 } from "child_process";
|
|
|
6175
6412
|
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
6176
6413
|
import { join as join5 } from "path";
|
|
6177
6414
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
6415
|
+
function buildFallbackRelayCard(owner) {
|
|
6416
|
+
return {
|
|
6417
|
+
id: randomUUID8(),
|
|
6418
|
+
owner,
|
|
6419
|
+
name: owner,
|
|
6420
|
+
description: "Agent registered via CLI",
|
|
6421
|
+
spec_version: "1.0",
|
|
6422
|
+
level: 1,
|
|
6423
|
+
inputs: [],
|
|
6424
|
+
outputs: [],
|
|
6425
|
+
pricing: { credits_per_call: 1 },
|
|
6426
|
+
availability: { online: true }
|
|
6427
|
+
};
|
|
6428
|
+
}
|
|
6429
|
+
function buildRelayRegistrationCards(owner, localCards) {
|
|
6430
|
+
if (localCards.length === 0) {
|
|
6431
|
+
return {
|
|
6432
|
+
primaryCard: buildFallbackRelayCard(owner),
|
|
6433
|
+
additionalCards: []
|
|
6434
|
+
};
|
|
6435
|
+
}
|
|
6436
|
+
return {
|
|
6437
|
+
primaryCard: localCards[0],
|
|
6438
|
+
additionalCards: localCards.slice(1)
|
|
6439
|
+
};
|
|
6440
|
+
}
|
|
6178
6441
|
var ServiceCoordinator = class {
|
|
6179
6442
|
config;
|
|
6180
6443
|
guard;
|
|
@@ -6319,8 +6582,11 @@ var ServiceCoordinator = class {
|
|
|
6319
6582
|
console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
|
|
6320
6583
|
}
|
|
6321
6584
|
if (opts.conductorEnabled && this.config.conductor?.public) {
|
|
6322
|
-
const { buildConductorCard } = await import("../../card-
|
|
6323
|
-
const conductorCard =
|
|
6585
|
+
const { buildConductorCard } = await import("../../card-BN643ZOY.js");
|
|
6586
|
+
const conductorCard = attachCanonicalAgentId(
|
|
6587
|
+
this.runtime.registryDb,
|
|
6588
|
+
buildConductorCard(this.config.owner)
|
|
6589
|
+
);
|
|
6324
6590
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6325
6591
|
const existing = this.runtime.registryDb.prepare("SELECT id FROM capability_cards WHERE id = ?").get(conductorCard.id);
|
|
6326
6592
|
if (existing) {
|
|
@@ -6376,27 +6642,11 @@ var ServiceCoordinator = class {
|
|
|
6376
6642
|
}
|
|
6377
6643
|
}
|
|
6378
6644
|
if (opts.registryUrl && opts.relay) {
|
|
6379
|
-
const { RelayClient: RelayClient2 } = await import("../../websocket-client-
|
|
6380
|
-
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-
|
|
6381
|
-
const
|
|
6382
|
-
const
|
|
6383
|
-
id: randomUUID8(),
|
|
6384
|
-
owner: this.config.owner,
|
|
6385
|
-
name: this.config.owner,
|
|
6386
|
-
description: "Agent registered via CLI",
|
|
6387
|
-
spec_version: "1.0",
|
|
6388
|
-
level: 1,
|
|
6389
|
-
inputs: [],
|
|
6390
|
-
outputs: [],
|
|
6391
|
-
pricing: { credits_per_call: 1 },
|
|
6392
|
-
availability: { online: true }
|
|
6393
|
-
};
|
|
6394
|
-
const additionalCards = [];
|
|
6645
|
+
const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
|
|
6646
|
+
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-FZLQGIXB.js");
|
|
6647
|
+
const localCards = listCards(this.runtime.registryDb, this.config.owner);
|
|
6648
|
+
const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
|
|
6395
6649
|
if (this.config.conductor?.public) {
|
|
6396
|
-
const { buildConductorCard } = await import("../../card-EX2EYGCZ.js");
|
|
6397
|
-
additionalCards.push(
|
|
6398
|
-
buildConductorCard(this.config.owner)
|
|
6399
|
-
);
|
|
6400
6650
|
console.log("Conductor card will be published to registry (conductor.public: true)");
|
|
6401
6651
|
}
|
|
6402
6652
|
this.relayClient = new RelayClient2({
|
|
@@ -6404,9 +6654,10 @@ var ServiceCoordinator = class {
|
|
|
6404
6654
|
owner: this.config.owner,
|
|
6405
6655
|
agent_id: this.config.agent_id,
|
|
6406
6656
|
token: this.config.token,
|
|
6407
|
-
card,
|
|
6657
|
+
card: primaryCard,
|
|
6408
6658
|
cards: additionalCards.length > 0 ? additionalCards : void 0,
|
|
6409
6659
|
onRequest: async (req) => {
|
|
6660
|
+
this.relayClient?.sendStarted(req.id, "provider acknowledged");
|
|
6410
6661
|
const onProgress = (info) => {
|
|
6411
6662
|
this.relayClient.sendProgress(req.id, info);
|
|
6412
6663
|
};
|
|
@@ -6722,6 +6973,14 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
6722
6973
|
return { escrowId, receipt };
|
|
6723
6974
|
}
|
|
6724
6975
|
|
|
6976
|
+
// src/credit/settlement.ts
|
|
6977
|
+
function settleRequesterEscrow(requesterDb, escrowId) {
|
|
6978
|
+
confirmEscrowDebit(requesterDb, escrowId);
|
|
6979
|
+
}
|
|
6980
|
+
function releaseRequesterEscrow(requesterDb, escrowId) {
|
|
6981
|
+
releaseEscrow(requesterDb, escrowId);
|
|
6982
|
+
}
|
|
6983
|
+
|
|
6725
6984
|
// src/app/agentbnb-service.ts
|
|
6726
6985
|
var AgentBnBService = class {
|
|
6727
6986
|
coordinator;
|
|
@@ -7131,8 +7390,35 @@ var requestInputSchema = {
|
|
|
7131
7390
|
card_id: z10.string().optional().describe("Direct card ID to request (skips search)"),
|
|
7132
7391
|
skill_id: z10.string().optional().describe("Specific skill within a v2.0 card"),
|
|
7133
7392
|
params: z10.record(z10.unknown()).optional().describe("Input parameters for the capability"),
|
|
7134
|
-
max_cost: z10.number().optional().default(50).describe("Maximum credits to spend")
|
|
7393
|
+
max_cost: z10.number().optional().default(50).describe("Maximum credits to spend"),
|
|
7394
|
+
timeout_ms: z10.number().positive().optional().describe("Requester timeout override in milliseconds")
|
|
7135
7395
|
};
|
|
7396
|
+
function parsePositiveNumber(value) {
|
|
7397
|
+
return typeof value === "number" && value > 0 ? value : void 0;
|
|
7398
|
+
}
|
|
7399
|
+
function deriveTimeoutHintFromCard(remoteCard, skillId) {
|
|
7400
|
+
const topLevelHint = {
|
|
7401
|
+
expected_duration_ms: parsePositiveNumber(remoteCard["expected_duration_ms"]),
|
|
7402
|
+
hard_timeout_ms: parsePositiveNumber(remoteCard["hard_timeout_ms"])
|
|
7403
|
+
};
|
|
7404
|
+
const skills = remoteCard["skills"];
|
|
7405
|
+
if (!Array.isArray(skills)) {
|
|
7406
|
+
return topLevelHint.expected_duration_ms !== void 0 || topLevelHint.hard_timeout_ms !== void 0 ? topLevelHint : void 0;
|
|
7407
|
+
}
|
|
7408
|
+
const selectedSkill = skillId ? skills.find((candidate) => {
|
|
7409
|
+
if (!candidate || typeof candidate !== "object") return false;
|
|
7410
|
+
return candidate["id"] === skillId;
|
|
7411
|
+
}) : skills[0];
|
|
7412
|
+
if (!selectedSkill || typeof selectedSkill !== "object") {
|
|
7413
|
+
return topLevelHint.expected_duration_ms !== void 0 || topLevelHint.hard_timeout_ms !== void 0 ? topLevelHint : void 0;
|
|
7414
|
+
}
|
|
7415
|
+
const skillRecord = selectedSkill;
|
|
7416
|
+
const skillHint = {
|
|
7417
|
+
expected_duration_ms: parsePositiveNumber(skillRecord["expected_duration_ms"]) ?? topLevelHint.expected_duration_ms,
|
|
7418
|
+
hard_timeout_ms: parsePositiveNumber(skillRecord["hard_timeout_ms"]) ?? topLevelHint.hard_timeout_ms
|
|
7419
|
+
};
|
|
7420
|
+
return skillHint.expected_duration_ms !== void 0 || skillHint.hard_timeout_ms !== void 0 ? skillHint : void 0;
|
|
7421
|
+
}
|
|
7136
7422
|
async function handleRequest(args, ctx) {
|
|
7137
7423
|
try {
|
|
7138
7424
|
const maxCost = args.max_cost ?? 50;
|
|
@@ -7196,6 +7482,7 @@ async function handleRequest(args, ctx) {
|
|
|
7196
7482
|
token: ctx.config.token,
|
|
7197
7483
|
cardId,
|
|
7198
7484
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7485
|
+
timeoutMs: args.timeout_ms,
|
|
7199
7486
|
identity: identityAuth
|
|
7200
7487
|
});
|
|
7201
7488
|
return {
|
|
@@ -7224,7 +7511,9 @@ async function handleRequest(args, ctx) {
|
|
|
7224
7511
|
};
|
|
7225
7512
|
}
|
|
7226
7513
|
const targetOwner = remoteCard["owner"] ?? remoteCard["agent_name"];
|
|
7514
|
+
const targetAgentId = typeof remoteCard["agent_id"] === "string" ? remoteCard["agent_id"] : void 0;
|
|
7227
7515
|
const gatewayUrl = remoteCard["gateway_url"];
|
|
7516
|
+
const timeoutHint = deriveTimeoutHintFromCard(remoteCard, args.skill_id);
|
|
7228
7517
|
if (gatewayUrl) {
|
|
7229
7518
|
let remoteCost = 0;
|
|
7230
7519
|
const remoteSkills = remoteCard["skills"];
|
|
@@ -7236,43 +7525,33 @@ async function handleRequest(args, ctx) {
|
|
|
7236
7525
|
remoteCost = remotePricing?.credits_per_call ?? 0;
|
|
7237
7526
|
}
|
|
7238
7527
|
if (remoteCost > 0) {
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
const { escrowId, receipt } = createSignedEscrowReceipt(creditDb, keys.privateKey, keys.publicKey, {
|
|
7244
|
-
owner: ctx.config.owner,
|
|
7245
|
-
agent_id: ctx.identity.agent_id,
|
|
7246
|
-
amount: remoteCost,
|
|
7247
|
-
cardId,
|
|
7248
|
-
skillId: args.skill_id
|
|
7249
|
-
});
|
|
7250
|
-
try {
|
|
7251
|
-
const result = await requestCapability({
|
|
7252
|
-
gatewayUrl,
|
|
7253
|
-
token: ctx.config.token ?? "",
|
|
7254
|
-
cardId,
|
|
7255
|
-
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7256
|
-
identity: identityAuth,
|
|
7257
|
-
escrowReceipt: receipt
|
|
7258
|
-
});
|
|
7259
|
-
confirmEscrowDebit(creditDb, escrowId);
|
|
7260
|
-
return {
|
|
7261
|
-
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7262
|
-
};
|
|
7263
|
-
} catch (execErr) {
|
|
7264
|
-
releaseEscrow(creditDb, escrowId);
|
|
7265
|
-
throw execErr;
|
|
7266
|
-
}
|
|
7267
|
-
} finally {
|
|
7268
|
-
creditDb.close();
|
|
7528
|
+
if (!targetOwner) {
|
|
7529
|
+
return {
|
|
7530
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Paid remote request requires a target owner for relay routing" }) }]
|
|
7531
|
+
};
|
|
7269
7532
|
}
|
|
7533
|
+
const result = await requestViaTemporaryRelay({
|
|
7534
|
+
registryUrl: ctx.config.registry,
|
|
7535
|
+
owner: ctx.config.owner,
|
|
7536
|
+
token: ctx.config.token ?? "",
|
|
7537
|
+
targetOwner,
|
|
7538
|
+
targetAgentId,
|
|
7539
|
+
cardId,
|
|
7540
|
+
skillId: args.skill_id,
|
|
7541
|
+
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7542
|
+
timeoutMs: args.timeout_ms
|
|
7543
|
+
});
|
|
7544
|
+
return {
|
|
7545
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7546
|
+
};
|
|
7270
7547
|
} else {
|
|
7271
7548
|
const result = await requestCapability({
|
|
7272
7549
|
gatewayUrl,
|
|
7273
7550
|
token: ctx.config.token ?? "",
|
|
7274
7551
|
cardId,
|
|
7275
7552
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7553
|
+
timeoutMs: args.timeout_ms,
|
|
7554
|
+
timeoutHint,
|
|
7276
7555
|
identity: identityAuth
|
|
7277
7556
|
});
|
|
7278
7557
|
return {
|
|
@@ -7281,30 +7560,20 @@ async function handleRequest(args, ctx) {
|
|
|
7281
7560
|
}
|
|
7282
7561
|
}
|
|
7283
7562
|
if (targetOwner) {
|
|
7284
|
-
const
|
|
7563
|
+
const result = await requestViaTemporaryRelay({
|
|
7285
7564
|
registryUrl: ctx.config.registry,
|
|
7286
7565
|
owner: ctx.config.owner,
|
|
7287
7566
|
token: ctx.config.token ?? "",
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7567
|
+
targetOwner,
|
|
7568
|
+
targetAgentId,
|
|
7569
|
+
cardId,
|
|
7570
|
+
skillId: args.skill_id,
|
|
7571
|
+
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {} },
|
|
7572
|
+
timeoutMs: args.timeout_ms
|
|
7291
7573
|
});
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
targetOwner,
|
|
7296
|
-
cardId,
|
|
7297
|
-
skillId: args.skill_id,
|
|
7298
|
-
params: args.params ?? {},
|
|
7299
|
-
requester: ctx.config.owner,
|
|
7300
|
-
timeoutMs: 3e5
|
|
7301
|
-
});
|
|
7302
|
-
return {
|
|
7303
|
-
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7304
|
-
};
|
|
7305
|
-
} finally {
|
|
7306
|
-
relay.disconnect();
|
|
7307
|
-
}
|
|
7574
|
+
return {
|
|
7575
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7576
|
+
};
|
|
7308
7577
|
}
|
|
7309
7578
|
return {
|
|
7310
7579
|
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Remote card has no gateway_url and no owner for relay routing" }) }]
|
|
@@ -7381,17 +7650,24 @@ async function conductAction(task, opts) {
|
|
|
7381
7650
|
matchResults.map((m) => [m.subtask_id, m])
|
|
7382
7651
|
);
|
|
7383
7652
|
const resolveAgentUrl = (owner) => {
|
|
7384
|
-
const
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7653
|
+
const execDb = openDatabase(config.db_path);
|
|
7654
|
+
let matchingCards;
|
|
7655
|
+
try {
|
|
7656
|
+
matchingCards = listCards(execDb, owner);
|
|
7657
|
+
} finally {
|
|
7658
|
+
execDb.close();
|
|
7659
|
+
}
|
|
7660
|
+
const candidateNames = /* @__PURE__ */ new Set([owner.toLowerCase()]);
|
|
7661
|
+
for (const card of matchingCards) {
|
|
7662
|
+
candidateNames.add(card.owner.toLowerCase());
|
|
7663
|
+
if (typeof card.agent_id === "string" && card.agent_id.length > 0) {
|
|
7664
|
+
candidateNames.add(card.agent_id.toLowerCase());
|
|
7393
7665
|
}
|
|
7394
7666
|
}
|
|
7667
|
+
const peer = peers.find((p) => candidateNames.has(p.name.toLowerCase()));
|
|
7668
|
+
if (peer) {
|
|
7669
|
+
return { url: peer.url, cardId: matchingCards[0]?.id ?? owner };
|
|
7670
|
+
}
|
|
7395
7671
|
if (config.registry) {
|
|
7396
7672
|
let cardId = owner;
|
|
7397
7673
|
for (const m of matchMap.values()) {
|