agentbnb 8.2.3 → 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 +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-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 +528 -253
- 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 {
|
|
@@ -2439,14 +2539,16 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
|
|
|
2439
2539
|
throw new Error("Invalid consumer signature on escrow settle");
|
|
2440
2540
|
}
|
|
2441
2541
|
}
|
|
2442
|
-
const escrowRow = creditDb.prepare(
|
|
2542
|
+
const escrowRow = creditDb.prepare(
|
|
2543
|
+
"SELECT amount, owner FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
2544
|
+
).get(escrowId);
|
|
2443
2545
|
if (!escrowRow) {
|
|
2444
2546
|
throw new Error(`Escrow not found or already settled: ${escrowId}`);
|
|
2445
2547
|
}
|
|
2446
|
-
const
|
|
2548
|
+
const NETWORK_FEE_RATE2 = 0.05;
|
|
2447
2549
|
if (success) {
|
|
2448
2550
|
settleEscrow(creditDb, escrowId, providerAgentId);
|
|
2449
|
-
const networkFee = Math.floor(escrowRow.amount *
|
|
2551
|
+
const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE2);
|
|
2450
2552
|
const providerAmount = escrowRow.amount - networkFee;
|
|
2451
2553
|
return {
|
|
2452
2554
|
escrow_id: escrowId,
|
|
@@ -2770,7 +2872,16 @@ function handleJobRelayResponse(opts) {
|
|
|
2770
2872
|
// src/relay/websocket-relay.ts
|
|
2771
2873
|
var RATE_LIMIT_MAX = 60;
|
|
2772
2874
|
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
2773
|
-
var
|
|
2875
|
+
var RELAY_IDLE_TIMEOUT_MS = 3e4;
|
|
2876
|
+
var RELAY_HARD_TIMEOUT_MS = 3e5;
|
|
2877
|
+
var RELAY_DISCONNECT_GRACE_MS = RELAY_HARD_TIMEOUT_MS + 3e4;
|
|
2878
|
+
function readTimeoutOverride(envKey, fallbackMs) {
|
|
2879
|
+
const raw = process.env[envKey];
|
|
2880
|
+
if (!raw) return fallbackMs;
|
|
2881
|
+
const parsed = Number(raw);
|
|
2882
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallbackMs;
|
|
2883
|
+
return Math.floor(parsed);
|
|
2884
|
+
}
|
|
2774
2885
|
function registerWebSocketRelay(server, db, creditDb) {
|
|
2775
2886
|
const connections = /* @__PURE__ */ new Map();
|
|
2776
2887
|
const agentIdToOwner = /* @__PURE__ */ new Map();
|
|
@@ -2784,6 +2895,136 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2784
2895
|
if (connections.has(target)) return target;
|
|
2785
2896
|
return void 0;
|
|
2786
2897
|
}
|
|
2898
|
+
function clearPendingTimers(pending) {
|
|
2899
|
+
clearTimeout(pending.timeout);
|
|
2900
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
2901
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
2902
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
2903
|
+
}
|
|
2904
|
+
function setPendingTimer(pending, timerType, timer) {
|
|
2905
|
+
const existing = pending[timerType];
|
|
2906
|
+
if (existing) clearTimeout(existing);
|
|
2907
|
+
pending[timerType] = timer;
|
|
2908
|
+
pending.timeout = timer;
|
|
2909
|
+
}
|
|
2910
|
+
function scheduleIdleTimeout(requestId, pending) {
|
|
2911
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_IDLE_TIMEOUT_MS", RELAY_IDLE_TIMEOUT_MS);
|
|
2912
|
+
const timer = setTimeout(() => {
|
|
2913
|
+
const current = pendingRequests.get(requestId);
|
|
2914
|
+
if (!current || (current.lifecycle ?? "held") !== "held") return;
|
|
2915
|
+
pendingRequests.delete(requestId);
|
|
2916
|
+
clearPendingTimers(current);
|
|
2917
|
+
if (current.escrowId && creditDb) {
|
|
2918
|
+
try {
|
|
2919
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2920
|
+
} catch (e) {
|
|
2921
|
+
console.error("[relay] escrow release on idle timeout failed:", e);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
const originWs = connections.get(current.originOwner);
|
|
2925
|
+
if (originWs && originWs.readyState === 1) {
|
|
2926
|
+
sendMessage(originWs, {
|
|
2927
|
+
type: "response",
|
|
2928
|
+
id: requestId,
|
|
2929
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2932
|
+
}, timeoutMs);
|
|
2933
|
+
setPendingTimer(pending, "idleTimeout", timer);
|
|
2934
|
+
}
|
|
2935
|
+
function scheduleHardTimeout(requestId, pending) {
|
|
2936
|
+
const timeoutMs = readTimeoutOverride("AGENTBNB_RELAY_HARD_TIMEOUT_MS", RELAY_HARD_TIMEOUT_MS);
|
|
2937
|
+
const timer = setTimeout(() => {
|
|
2938
|
+
const current = pendingRequests.get(requestId);
|
|
2939
|
+
if (!current || current.lifecycle === "abandoned") return;
|
|
2940
|
+
pendingRequests.delete(requestId);
|
|
2941
|
+
clearPendingTimers(current);
|
|
2942
|
+
if (current.escrowId && creditDb) {
|
|
2943
|
+
try {
|
|
2944
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2945
|
+
} catch (e) {
|
|
2946
|
+
console.error("[relay] escrow release on hard timeout failed:", e);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
const originWs = connections.get(current.originOwner);
|
|
2950
|
+
if (originWs && originWs.readyState === 1) {
|
|
2951
|
+
sendMessage(originWs, {
|
|
2952
|
+
type: "response",
|
|
2953
|
+
id: requestId,
|
|
2954
|
+
error: { code: -32603, message: "Relay request timeout" }
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
}, timeoutMs);
|
|
2958
|
+
setPendingTimer(pending, "hardTimeout", timer);
|
|
2959
|
+
}
|
|
2960
|
+
function scheduleGraceTimeout(requestId, pending) {
|
|
2961
|
+
const timeoutMs = readTimeoutOverride(
|
|
2962
|
+
"AGENTBNB_RELAY_DISCONNECT_GRACE_MS",
|
|
2963
|
+
RELAY_DISCONNECT_GRACE_MS
|
|
2964
|
+
);
|
|
2965
|
+
const timer = setTimeout(() => {
|
|
2966
|
+
const current = pendingRequests.get(requestId);
|
|
2967
|
+
if (!current || current.lifecycle !== "abandoned") return;
|
|
2968
|
+
pendingRequests.delete(requestId);
|
|
2969
|
+
clearPendingTimers(current);
|
|
2970
|
+
if (current.escrowId && creditDb) {
|
|
2971
|
+
try {
|
|
2972
|
+
releaseForRelay(creditDb, current.escrowId);
|
|
2973
|
+
} catch (e) {
|
|
2974
|
+
console.error("[relay] escrow release after grace timeout failed:", e);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
}, timeoutMs);
|
|
2978
|
+
setPendingTimer(pending, "graceTimeout", timer);
|
|
2979
|
+
}
|
|
2980
|
+
function transitionPendingToStarted(requestId, pending) {
|
|
2981
|
+
if (pending.lifecycle === "started" || pending.lifecycle === "progressing" || pending.lifecycle === "abandoned") {
|
|
2982
|
+
return;
|
|
2983
|
+
}
|
|
2984
|
+
pending.lifecycle = "started";
|
|
2985
|
+
pending.startedAt = Date.now();
|
|
2986
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
2987
|
+
if (pending.graceTimeout) clearTimeout(pending.graceTimeout);
|
|
2988
|
+
if (pending.escrowId && creditDb) {
|
|
2989
|
+
try {
|
|
2990
|
+
markEscrowStarted(creditDb, pending.escrowId);
|
|
2991
|
+
} catch (e) {
|
|
2992
|
+
console.error("[relay] escrow transition to started failed:", e);
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
scheduleHardTimeout(requestId, pending);
|
|
2996
|
+
}
|
|
2997
|
+
function transitionPendingToProgressing(requestId, pending) {
|
|
2998
|
+
if (pending.lifecycle === "abandoned") {
|
|
2999
|
+
return;
|
|
3000
|
+
}
|
|
3001
|
+
if ((pending.lifecycle ?? "held") === "held") {
|
|
3002
|
+
transitionPendingToStarted(requestId, pending);
|
|
3003
|
+
}
|
|
3004
|
+
pending.lifecycle = "progressing";
|
|
3005
|
+
if (pending.escrowId && creditDb) {
|
|
3006
|
+
try {
|
|
3007
|
+
markEscrowProgressing(creditDb, pending.escrowId);
|
|
3008
|
+
} catch (e) {
|
|
3009
|
+
console.error("[relay] escrow transition to progressing failed:", e);
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
function transitionPendingToAbandoned(requestId, pending) {
|
|
3014
|
+
if (pending.lifecycle === "abandoned") return;
|
|
3015
|
+
pending.lifecycle = "abandoned";
|
|
3016
|
+
pending.abandonedAt = Date.now();
|
|
3017
|
+
if (pending.idleTimeout) clearTimeout(pending.idleTimeout);
|
|
3018
|
+
if (pending.hardTimeout) clearTimeout(pending.hardTimeout);
|
|
3019
|
+
if (pending.escrowId && creditDb) {
|
|
3020
|
+
try {
|
|
3021
|
+
markEscrowAbandoned(creditDb, pending.escrowId);
|
|
3022
|
+
} catch (e) {
|
|
3023
|
+
console.error("[relay] escrow transition to abandoned failed:", e);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
scheduleGraceTimeout(requestId, pending);
|
|
3027
|
+
}
|
|
2787
3028
|
function checkRateLimit(owner) {
|
|
2788
3029
|
const now = Date.now();
|
|
2789
3030
|
const entry = rateLimits.get(owner);
|
|
@@ -2833,15 +3074,20 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2833
3074
|
} catch {
|
|
2834
3075
|
}
|
|
2835
3076
|
}
|
|
2836
|
-
function upsertCard(cardData, owner) {
|
|
2837
|
-
const parsed = AnyCardSchema.safeParse(
|
|
3077
|
+
function upsertCard(cardData, owner, agentId) {
|
|
3078
|
+
const parsed = AnyCardSchema.safeParse(
|
|
3079
|
+
agentId ? { ...cardData, agent_id: agentId } : cardData
|
|
3080
|
+
);
|
|
2838
3081
|
if (!parsed.success) {
|
|
2839
3082
|
throw new AgentBnBError(
|
|
2840
3083
|
`Card validation failed: ${parsed.error.message}`,
|
|
2841
3084
|
"VALIDATION_ERROR"
|
|
2842
3085
|
);
|
|
2843
3086
|
}
|
|
2844
|
-
const card =
|
|
3087
|
+
const card = attachCanonicalAgentId(db, {
|
|
3088
|
+
...parsed.data,
|
|
3089
|
+
availability: { ...parsed.data.availability, online: true }
|
|
3090
|
+
});
|
|
2845
3091
|
const cardId = card.id;
|
|
2846
3092
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2847
3093
|
const existing = db.prepare("SELECT id FROM capability_cards WHERE id = ?").get(cardId);
|
|
@@ -2895,7 +3141,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2895
3141
|
agentIdToOwner.set(agentEntry.agent_id, owner);
|
|
2896
3142
|
for (const agentCard of agentEntry.cards) {
|
|
2897
3143
|
try {
|
|
2898
|
-
upsertCard(agentCard, owner);
|
|
3144
|
+
upsertCard(agentCard, owner, agentEntry.agent_id);
|
|
2899
3145
|
} catch {
|
|
2900
3146
|
}
|
|
2901
3147
|
}
|
|
@@ -2909,7 +3155,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2909
3155
|
}
|
|
2910
3156
|
let cardId;
|
|
2911
3157
|
try {
|
|
2912
|
-
cardId = upsertCard(card, owner);
|
|
3158
|
+
cardId = upsertCard(card, owner, msg.agent_id);
|
|
2913
3159
|
} catch (err) {
|
|
2914
3160
|
console.error(`[relay] card validation failed for ${owner}:`, err instanceof Error ? err.message : err);
|
|
2915
3161
|
cardId = card.id ?? owner;
|
|
@@ -2919,7 +3165,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2919
3165
|
if (msg.cards && msg.cards.length > 0) {
|
|
2920
3166
|
for (const extraCard of msg.cards) {
|
|
2921
3167
|
try {
|
|
2922
|
-
upsertCard(extraCard, owner);
|
|
3168
|
+
upsertCard(extraCard, owner, msg.agent_id);
|
|
2923
3169
|
} catch {
|
|
2924
3170
|
}
|
|
2925
3171
|
}
|
|
@@ -2974,23 +3220,17 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2974
3220
|
console.error("[relay] credit hold error (non-fatal):", err);
|
|
2975
3221
|
}
|
|
2976
3222
|
}
|
|
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 });
|
|
3223
|
+
const pending = {
|
|
3224
|
+
originOwner: fromOwner,
|
|
3225
|
+
creditOwner,
|
|
3226
|
+
timeout: setTimeout(() => void 0, 1),
|
|
3227
|
+
escrowId,
|
|
3228
|
+
targetOwner: targetKey ?? msg.target_owner,
|
|
3229
|
+
lifecycle: "held",
|
|
3230
|
+
createdAt: Date.now()
|
|
3231
|
+
};
|
|
3232
|
+
pendingRequests.set(msg.id, pending);
|
|
3233
|
+
scheduleIdleTimeout(msg.id, pending);
|
|
2994
3234
|
sendMessage(targetWs, {
|
|
2995
3235
|
type: "incoming_request",
|
|
2996
3236
|
id: msg.id,
|
|
@@ -3002,30 +3242,23 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3002
3242
|
escrow_receipt: msg.escrow_receipt
|
|
3003
3243
|
});
|
|
3004
3244
|
}
|
|
3245
|
+
function handleRelayStarted(msg) {
|
|
3246
|
+
const pending = pendingRequests.get(msg.id);
|
|
3247
|
+
if (!pending) return;
|
|
3248
|
+
transitionPendingToStarted(msg.id, pending);
|
|
3249
|
+
const originWs = connections.get(pending.originOwner);
|
|
3250
|
+
if (originWs && originWs.readyState === 1) {
|
|
3251
|
+
sendMessage(originWs, {
|
|
3252
|
+
type: "relay_started",
|
|
3253
|
+
id: msg.id,
|
|
3254
|
+
message: msg.message
|
|
3255
|
+
});
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3005
3258
|
function handleRelayProgress(msg) {
|
|
3006
3259
|
const pending = pendingRequests.get(msg.id);
|
|
3007
3260
|
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;
|
|
3261
|
+
transitionPendingToProgressing(msg.id, pending);
|
|
3029
3262
|
const originWs = connections.get(pending.originOwner);
|
|
3030
3263
|
if (originWs && originWs.readyState === 1) {
|
|
3031
3264
|
sendMessage(originWs, {
|
|
@@ -3039,7 +3272,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3039
3272
|
function handleRelayResponse(msg) {
|
|
3040
3273
|
const pending = pendingRequests.get(msg.id);
|
|
3041
3274
|
if (!pending) return;
|
|
3042
|
-
|
|
3275
|
+
clearPendingTimers(pending);
|
|
3043
3276
|
pendingRequests.delete(msg.id);
|
|
3044
3277
|
if (pending.jobId && creditDb) {
|
|
3045
3278
|
try {
|
|
@@ -3102,16 +3335,15 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3102
3335
|
connections.delete(owner);
|
|
3103
3336
|
rateLimits.delete(owner);
|
|
3104
3337
|
agentCapacities.delete(owner);
|
|
3105
|
-
for (const [agentId,
|
|
3106
|
-
if (
|
|
3338
|
+
for (const [agentId, mappedOwner] of Array.from(agentIdToOwner.entries())) {
|
|
3339
|
+
if (mappedOwner === owner) {
|
|
3107
3340
|
agentIdToOwner.delete(agentId);
|
|
3108
|
-
break;
|
|
3109
3341
|
}
|
|
3110
3342
|
}
|
|
3111
3343
|
markOwnerOffline(owner);
|
|
3112
3344
|
for (const [reqId, pending] of pendingRequests) {
|
|
3113
3345
|
if (pending.targetOwner === owner) {
|
|
3114
|
-
|
|
3346
|
+
clearPendingTimers(pending);
|
|
3115
3347
|
pendingRequests.delete(reqId);
|
|
3116
3348
|
if (pending.escrowId && creditDb) {
|
|
3117
3349
|
try {
|
|
@@ -3129,14 +3361,19 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3129
3361
|
});
|
|
3130
3362
|
}
|
|
3131
3363
|
} else if (pending.originOwner === owner) {
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3364
|
+
const lifecycle = pending.lifecycle ?? "held";
|
|
3365
|
+
if (lifecycle === "held") {
|
|
3366
|
+
clearPendingTimers(pending);
|
|
3367
|
+
pendingRequests.delete(reqId);
|
|
3368
|
+
if (pending.escrowId && creditDb) {
|
|
3369
|
+
try {
|
|
3370
|
+
releaseForRelay(creditDb, pending.escrowId);
|
|
3371
|
+
} catch (e) {
|
|
3372
|
+
console.error("[relay] escrow release on requester disconnect failed:", e);
|
|
3373
|
+
}
|
|
3139
3374
|
}
|
|
3375
|
+
} else {
|
|
3376
|
+
transitionPendingToAbandoned(reqId, pending);
|
|
3140
3377
|
}
|
|
3141
3378
|
}
|
|
3142
3379
|
}
|
|
@@ -3179,7 +3416,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3179
3416
|
return;
|
|
3180
3417
|
}
|
|
3181
3418
|
try {
|
|
3182
|
-
const escrow = creditDb.prepare(
|
|
3419
|
+
const escrow = creditDb.prepare(
|
|
3420
|
+
"SELECT card_id FROM credit_escrow WHERE id = ? AND status IN ('held', 'started', 'progressing', 'abandoned')"
|
|
3421
|
+
).get(msg.escrow_id);
|
|
3183
3422
|
if (!escrow) {
|
|
3184
3423
|
sendMessage(ws, { type: "error", code: "escrow_not_found", message: `Escrow not found: ${msg.escrow_id}`, request_id: msg.request_id });
|
|
3185
3424
|
return;
|
|
@@ -3276,6 +3515,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3276
3515
|
case "relay_response":
|
|
3277
3516
|
handleRelayResponse(msg);
|
|
3278
3517
|
break;
|
|
3518
|
+
case "relay_started":
|
|
3519
|
+
handleRelayStarted(msg);
|
|
3520
|
+
break;
|
|
3279
3521
|
case "relay_progress":
|
|
3280
3522
|
handleRelayProgress(msg);
|
|
3281
3523
|
break;
|
|
@@ -3322,7 +3564,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3322
3564
|
}
|
|
3323
3565
|
connections.clear();
|
|
3324
3566
|
for (const [, pending] of pendingRequests) {
|
|
3325
|
-
|
|
3567
|
+
clearPendingTimers(pending);
|
|
3326
3568
|
}
|
|
3327
3569
|
pendingRequests.clear();
|
|
3328
3570
|
rateLimits.clear();
|
|
@@ -4621,6 +4863,9 @@ function stripInternal(card) {
|
|
|
4621
4863
|
const { _internal: _, ...publicCard } = card;
|
|
4622
4864
|
return publicCard;
|
|
4623
4865
|
}
|
|
4866
|
+
function buildSqlPlaceholders(count) {
|
|
4867
|
+
return Array.from({ length: count }, () => "?").join(", ");
|
|
4868
|
+
}
|
|
4624
4869
|
function createRegistryServer(opts) {
|
|
4625
4870
|
const { registryDb: db, silent = false } = opts;
|
|
4626
4871
|
const server = Fastify2({ logger: !silent });
|
|
@@ -5030,11 +5275,11 @@ function createRegistryServer(opts) {
|
|
|
5030
5275
|
const card = result.data;
|
|
5031
5276
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5032
5277
|
if (card.spec_version === "2.0") {
|
|
5033
|
-
const cardWithTimestamps = {
|
|
5278
|
+
const cardWithTimestamps = attachCanonicalAgentId(db, {
|
|
5034
5279
|
...card,
|
|
5035
5280
|
created_at: card.created_at ?? now,
|
|
5036
5281
|
updated_at: now
|
|
5037
|
-
};
|
|
5282
|
+
});
|
|
5038
5283
|
db.prepare(
|
|
5039
5284
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
5040
5285
|
VALUES (?, ?, ?, ?, ?)`
|
|
@@ -5155,19 +5400,16 @@ function createRegistryServer(opts) {
|
|
|
5155
5400
|
if (ownerCards.length === 0) {
|
|
5156
5401
|
return reply.status(404).send({ error: "Agent not found" });
|
|
5157
5402
|
}
|
|
5158
|
-
const
|
|
5159
|
-
|
|
5403
|
+
const resolvedOwner = ownerCards[0]?.owner ?? owner;
|
|
5404
|
+
const ownerCardIds = ownerCards.map((card) => card.id);
|
|
5405
|
+
const cardIdPlaceholders = buildSqlPlaceholders(ownerCardIds.length);
|
|
5406
|
+
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();
|
|
5407
|
+
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;
|
|
5408
|
+
const lastActiveStmt = db.prepare(
|
|
5409
|
+
`SELECT MAX(created_at) as last_req FROM request_log WHERE card_id IN (${cardIdPlaceholders})`
|
|
5160
5410
|
);
|
|
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;
|
|
5411
|
+
const lastActiveRow = lastActiveStmt.get(...ownerCardIds);
|
|
5412
|
+
const lastActive = lastActiveRow?.last_req ?? latestCardUpdate ?? joinedAt;
|
|
5171
5413
|
const metricsStmt = db.prepare(`
|
|
5172
5414
|
SELECT
|
|
5173
5415
|
SUM(CASE WHEN rl.failure_reason IS NULL OR rl.failure_reason IN ('bad_execution','auth_error')
|
|
@@ -5177,10 +5419,9 @@ function createRegistryServer(opts) {
|
|
|
5177
5419
|
COUNT(DISTINCT rl.requester) as unique_requesters,
|
|
5178
5420
|
COUNT(DISTINCT CASE WHEN rl.status = 'success' THEN rl.requester END) as repeat_success_requesters
|
|
5179
5421
|
FROM request_log rl
|
|
5180
|
-
|
|
5181
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5422
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5182
5423
|
`);
|
|
5183
|
-
const metricsRow = metricsStmt.get(
|
|
5424
|
+
const metricsRow = metricsStmt.get(...ownerCardIds);
|
|
5184
5425
|
const totalExec = metricsRow?.total ?? 0;
|
|
5185
5426
|
const successExec = metricsRow?.successes ?? 0;
|
|
5186
5427
|
const successRate = totalExec > 0 ? successExec / totalExec : 0;
|
|
@@ -5194,25 +5435,23 @@ function createRegistryServer(opts) {
|
|
|
5194
5435
|
COUNT(*) as count,
|
|
5195
5436
|
SUM(CASE WHEN rl.status = 'success' THEN 1 ELSE 0 END) as success
|
|
5196
5437
|
FROM request_log rl
|
|
5197
|
-
|
|
5198
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5438
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5199
5439
|
AND rl.created_at >= DATE('now', '-7 days')
|
|
5200
5440
|
GROUP BY DATE(rl.created_at)
|
|
5201
5441
|
ORDER BY day ASC
|
|
5202
5442
|
`);
|
|
5203
|
-
const trend_7d = trendStmt.all(
|
|
5443
|
+
const trend_7d = trendStmt.all(...ownerCardIds).map((r) => ({ date: r.day, count: r.count, success: r.success }));
|
|
5204
5444
|
let performanceTier = 0;
|
|
5205
5445
|
if (totalExec > 10) performanceTier = 1;
|
|
5206
5446
|
if (totalExec > 50 && successRate >= 0.85) performanceTier = 2;
|
|
5207
5447
|
const proofsStmt = db.prepare(`
|
|
5208
5448
|
SELECT rl.card_name, rl.status, rl.latency_ms, rl.id, rl.created_at
|
|
5209
5449
|
FROM request_log rl
|
|
5210
|
-
|
|
5211
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5450
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5212
5451
|
ORDER BY rl.created_at DESC
|
|
5213
5452
|
LIMIT 10
|
|
5214
5453
|
`);
|
|
5215
|
-
const proofRows = proofsStmt.all(
|
|
5454
|
+
const proofRows = proofsStmt.all(...ownerCardIds);
|
|
5216
5455
|
const statusToOutcomeClass = (s) => {
|
|
5217
5456
|
if (s === "success") return "completed";
|
|
5218
5457
|
if (s === "timeout") return "cancelled";
|
|
@@ -5238,22 +5477,20 @@ function createRegistryServer(opts) {
|
|
|
5238
5477
|
const activityStmt = db.prepare(`
|
|
5239
5478
|
SELECT rl.id, rl.card_name, rl.requester, rl.status, rl.credits_charged, rl.created_at
|
|
5240
5479
|
FROM request_log rl
|
|
5241
|
-
|
|
5242
|
-
WHERE cc.owner = ?
|
|
5480
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
5243
5481
|
ORDER BY rl.created_at DESC
|
|
5244
5482
|
LIMIT 10
|
|
5245
5483
|
`);
|
|
5246
|
-
const recentActivity = activityStmt.all(
|
|
5484
|
+
const recentActivity = activityStmt.all(...ownerCardIds);
|
|
5247
5485
|
const skillCount = ownerCards.reduce((sum, card) => sum + (card.skills?.length ?? 1), 0);
|
|
5248
5486
|
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 = ?
|
|
5487
|
+
SELECT COALESCE(SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END), 0) as credits_earned
|
|
5488
|
+
FROM request_log rl
|
|
5489
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
5253
5490
|
`);
|
|
5254
|
-
const creditsRow = creditsStmt.get(
|
|
5491
|
+
const creditsRow = creditsStmt.get(...ownerCardIds);
|
|
5255
5492
|
const response = {
|
|
5256
|
-
owner,
|
|
5493
|
+
owner: resolvedOwner,
|
|
5257
5494
|
agent_name: v2Card?.agent_name,
|
|
5258
5495
|
short_description: v2Card?.short_description,
|
|
5259
5496
|
joined_at: joinedAt,
|
|
@@ -5285,7 +5522,7 @@ function createRegistryServer(opts) {
|
|
|
5285
5522
|
return reply.send({
|
|
5286
5523
|
...response,
|
|
5287
5524
|
profile: {
|
|
5288
|
-
owner,
|
|
5525
|
+
owner: resolvedOwner,
|
|
5289
5526
|
skill_count: skillCount,
|
|
5290
5527
|
success_rate: successRate > 0 ? successRate : null,
|
|
5291
5528
|
total_earned: creditsRow?.credits_earned ?? 0,
|
|
@@ -5557,7 +5794,7 @@ function createRegistryServer(opts) {
|
|
|
5557
5794
|
return { card_id: target.cardId, skill_id: target.skillId };
|
|
5558
5795
|
}
|
|
5559
5796
|
if (!relayClient) {
|
|
5560
|
-
const { RelayClient: RelayClient2 } = await import("../../websocket-client-
|
|
5797
|
+
const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
|
|
5561
5798
|
relayClient = new RelayClient2({
|
|
5562
5799
|
registryUrl: relayRegistryUrl,
|
|
5563
5800
|
owner: relayRequesterOwner,
|
|
@@ -5579,7 +5816,7 @@ function createRegistryServer(opts) {
|
|
|
5579
5816
|
});
|
|
5580
5817
|
await relayClient.connect();
|
|
5581
5818
|
}
|
|
5582
|
-
const { requestViaRelay: requestViaRelay2 } = await import("../../client-
|
|
5819
|
+
const { requestViaRelay: requestViaRelay2 } = await import("../../client-OKJJ3UP2.js");
|
|
5583
5820
|
return requestViaRelay2(relayClient, {
|
|
5584
5821
|
targetOwner: target.owner,
|
|
5585
5822
|
cardId: target.cardId,
|
|
@@ -5835,7 +6072,7 @@ function createRegistryServer(opts) {
|
|
|
5835
6072
|
if (!opts.creditDb) {
|
|
5836
6073
|
return reply.code(404).send({ error: "Credit system not enabled" });
|
|
5837
6074
|
}
|
|
5838
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
6075
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
5839
6076
|
const metrics = getReliabilityMetrics(opts.creditDb, owner);
|
|
5840
6077
|
if (!metrics) {
|
|
5841
6078
|
return reply.code(404).send({ error: "No reliability data for this provider" });
|
|
@@ -5853,38 +6090,37 @@ function createRegistryServer(opts) {
|
|
|
5853
6090
|
}
|
|
5854
6091
|
}, async (request, reply) => {
|
|
5855
6092
|
const { owner } = request.params;
|
|
5856
|
-
const
|
|
5857
|
-
"SELECT id, data FROM capability_cards WHERE owner = ?"
|
|
5858
|
-
).all(owner);
|
|
6093
|
+
const cards = listCards(db, owner);
|
|
5859
6094
|
const agents = [];
|
|
5860
|
-
for (const
|
|
6095
|
+
for (const card of cards) {
|
|
5861
6096
|
try {
|
|
5862
|
-
const
|
|
6097
|
+
const rawCard = card;
|
|
6098
|
+
const providerIdentity = typeof card.agent_id === "string" && card.agent_id.length > 0 ? card.agent_id : card.owner;
|
|
5863
6099
|
let earnings = 0;
|
|
5864
6100
|
let spend = 0;
|
|
5865
6101
|
if (opts.creditDb) {
|
|
5866
6102
|
const earningRow = opts.creditDb.prepare(
|
|
5867
6103
|
"SELECT COALESCE(SUM(amount), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'settlement' AND amount > 0"
|
|
5868
|
-
).get(
|
|
6104
|
+
).get(providerIdentity);
|
|
5869
6105
|
earnings = earningRow.total;
|
|
5870
6106
|
const spendRow = opts.creditDb.prepare(
|
|
5871
6107
|
"SELECT COALESCE(SUM(ABS(amount)), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'escrow_hold'"
|
|
5872
|
-
).get(
|
|
6108
|
+
).get(providerIdentity);
|
|
5873
6109
|
spend = spendRow.total;
|
|
5874
6110
|
}
|
|
5875
6111
|
const successCount = db.prepare(
|
|
5876
6112
|
"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(
|
|
6113
|
+
).get(card.id).cnt;
|
|
5878
6114
|
const failureCount = db.prepare(
|
|
5879
6115
|
"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(
|
|
6116
|
+
).get(card.id).cnt;
|
|
5881
6117
|
const totalExec = successCount + failureCount;
|
|
5882
6118
|
const successRate = totalExec > 0 ? successCount / totalExec : 0;
|
|
5883
6119
|
let failureBreakdown = {};
|
|
5884
6120
|
try {
|
|
5885
6121
|
const failureRows = db.prepare(
|
|
5886
6122
|
"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(
|
|
6123
|
+
).all(card.id);
|
|
5888
6124
|
for (const fr of failureRows) {
|
|
5889
6125
|
failureBreakdown[fr.failure_reason] = fr.cnt;
|
|
5890
6126
|
}
|
|
@@ -5892,12 +6128,12 @@ function createRegistryServer(opts) {
|
|
|
5892
6128
|
}
|
|
5893
6129
|
let reliability = null;
|
|
5894
6130
|
if (opts.creditDb) {
|
|
5895
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
5896
|
-
reliability = getReliabilityMetrics(opts.creditDb,
|
|
6131
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
6132
|
+
reliability = getReliabilityMetrics(opts.creditDb, providerIdentity);
|
|
5897
6133
|
}
|
|
5898
6134
|
agents.push({
|
|
5899
|
-
id:
|
|
5900
|
-
name:
|
|
6135
|
+
id: card.id,
|
|
6136
|
+
name: (typeof rawCard["name"] === "string" ? rawCard["name"] : void 0) ?? (typeof rawCard["agent_name"] === "string" ? rawCard["agent_name"] : void 0) ?? card.owner,
|
|
5901
6137
|
online: card.availability?.online ?? false,
|
|
5902
6138
|
current_load: 0,
|
|
5903
6139
|
// Will be populated from relay heartbeat data in future
|
|
@@ -6175,6 +6411,32 @@ import { spawn as spawn2 } from "child_process";
|
|
|
6175
6411
|
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
6176
6412
|
import { join as join5 } from "path";
|
|
6177
6413
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
6414
|
+
function buildFallbackRelayCard(owner) {
|
|
6415
|
+
return {
|
|
6416
|
+
id: randomUUID8(),
|
|
6417
|
+
owner,
|
|
6418
|
+
name: owner,
|
|
6419
|
+
description: "Agent registered via CLI",
|
|
6420
|
+
spec_version: "1.0",
|
|
6421
|
+
level: 1,
|
|
6422
|
+
inputs: [],
|
|
6423
|
+
outputs: [],
|
|
6424
|
+
pricing: { credits_per_call: 1 },
|
|
6425
|
+
availability: { online: true }
|
|
6426
|
+
};
|
|
6427
|
+
}
|
|
6428
|
+
function buildRelayRegistrationCards(owner, localCards) {
|
|
6429
|
+
if (localCards.length === 0) {
|
|
6430
|
+
return {
|
|
6431
|
+
primaryCard: buildFallbackRelayCard(owner),
|
|
6432
|
+
additionalCards: []
|
|
6433
|
+
};
|
|
6434
|
+
}
|
|
6435
|
+
return {
|
|
6436
|
+
primaryCard: localCards[0],
|
|
6437
|
+
additionalCards: localCards.slice(1)
|
|
6438
|
+
};
|
|
6439
|
+
}
|
|
6178
6440
|
var ServiceCoordinator = class {
|
|
6179
6441
|
config;
|
|
6180
6442
|
guard;
|
|
@@ -6319,8 +6581,11 @@ var ServiceCoordinator = class {
|
|
|
6319
6581
|
console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
|
|
6320
6582
|
}
|
|
6321
6583
|
if (opts.conductorEnabled && this.config.conductor?.public) {
|
|
6322
|
-
const { buildConductorCard } = await import("../../card-
|
|
6323
|
-
const conductorCard =
|
|
6584
|
+
const { buildConductorCard } = await import("../../card-BN643ZOY.js");
|
|
6585
|
+
const conductorCard = attachCanonicalAgentId(
|
|
6586
|
+
this.runtime.registryDb,
|
|
6587
|
+
buildConductorCard(this.config.owner)
|
|
6588
|
+
);
|
|
6324
6589
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6325
6590
|
const existing = this.runtime.registryDb.prepare("SELECT id FROM capability_cards WHERE id = ?").get(conductorCard.id);
|
|
6326
6591
|
if (existing) {
|
|
@@ -6376,27 +6641,11 @@ var ServiceCoordinator = class {
|
|
|
6376
6641
|
}
|
|
6377
6642
|
}
|
|
6378
6643
|
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 = [];
|
|
6644
|
+
const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
|
|
6645
|
+
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-FZLQGIXB.js");
|
|
6646
|
+
const localCards = listCards(this.runtime.registryDb, this.config.owner);
|
|
6647
|
+
const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
|
|
6395
6648
|
if (this.config.conductor?.public) {
|
|
6396
|
-
const { buildConductorCard } = await import("../../card-EX2EYGCZ.js");
|
|
6397
|
-
additionalCards.push(
|
|
6398
|
-
buildConductorCard(this.config.owner)
|
|
6399
|
-
);
|
|
6400
6649
|
console.log("Conductor card will be published to registry (conductor.public: true)");
|
|
6401
6650
|
}
|
|
6402
6651
|
this.relayClient = new RelayClient2({
|
|
@@ -6404,9 +6653,10 @@ var ServiceCoordinator = class {
|
|
|
6404
6653
|
owner: this.config.owner,
|
|
6405
6654
|
agent_id: this.config.agent_id,
|
|
6406
6655
|
token: this.config.token,
|
|
6407
|
-
card,
|
|
6656
|
+
card: primaryCard,
|
|
6408
6657
|
cards: additionalCards.length > 0 ? additionalCards : void 0,
|
|
6409
6658
|
onRequest: async (req) => {
|
|
6659
|
+
this.relayClient?.sendStarted(req.id, "provider acknowledged");
|
|
6410
6660
|
const onProgress = (info) => {
|
|
6411
6661
|
this.relayClient.sendProgress(req.id, info);
|
|
6412
6662
|
};
|
|
@@ -6722,6 +6972,14 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
6722
6972
|
return { escrowId, receipt };
|
|
6723
6973
|
}
|
|
6724
6974
|
|
|
6975
|
+
// src/credit/settlement.ts
|
|
6976
|
+
function settleRequesterEscrow(requesterDb, escrowId) {
|
|
6977
|
+
confirmEscrowDebit(requesterDb, escrowId);
|
|
6978
|
+
}
|
|
6979
|
+
function releaseRequesterEscrow(requesterDb, escrowId) {
|
|
6980
|
+
releaseEscrow(requesterDb, escrowId);
|
|
6981
|
+
}
|
|
6982
|
+
|
|
6725
6983
|
// src/app/agentbnb-service.ts
|
|
6726
6984
|
var AgentBnBService = class {
|
|
6727
6985
|
coordinator;
|
|
@@ -7131,8 +7389,35 @@ var requestInputSchema = {
|
|
|
7131
7389
|
card_id: z10.string().optional().describe("Direct card ID to request (skips search)"),
|
|
7132
7390
|
skill_id: z10.string().optional().describe("Specific skill within a v2.0 card"),
|
|
7133
7391
|
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")
|
|
7392
|
+
max_cost: z10.number().optional().default(50).describe("Maximum credits to spend"),
|
|
7393
|
+
timeout_ms: z10.number().positive().optional().describe("Requester timeout override in milliseconds")
|
|
7135
7394
|
};
|
|
7395
|
+
function parsePositiveNumber(value) {
|
|
7396
|
+
return typeof value === "number" && value > 0 ? value : void 0;
|
|
7397
|
+
}
|
|
7398
|
+
function deriveTimeoutHintFromCard(remoteCard, skillId) {
|
|
7399
|
+
const topLevelHint = {
|
|
7400
|
+
expected_duration_ms: parsePositiveNumber(remoteCard["expected_duration_ms"]),
|
|
7401
|
+
hard_timeout_ms: parsePositiveNumber(remoteCard["hard_timeout_ms"])
|
|
7402
|
+
};
|
|
7403
|
+
const skills = remoteCard["skills"];
|
|
7404
|
+
if (!Array.isArray(skills)) {
|
|
7405
|
+
return topLevelHint.expected_duration_ms !== void 0 || topLevelHint.hard_timeout_ms !== void 0 ? topLevelHint : void 0;
|
|
7406
|
+
}
|
|
7407
|
+
const selectedSkill = skillId ? skills.find((candidate) => {
|
|
7408
|
+
if (!candidate || typeof candidate !== "object") return false;
|
|
7409
|
+
return candidate["id"] === skillId;
|
|
7410
|
+
}) : skills[0];
|
|
7411
|
+
if (!selectedSkill || typeof selectedSkill !== "object") {
|
|
7412
|
+
return topLevelHint.expected_duration_ms !== void 0 || topLevelHint.hard_timeout_ms !== void 0 ? topLevelHint : void 0;
|
|
7413
|
+
}
|
|
7414
|
+
const skillRecord = selectedSkill;
|
|
7415
|
+
const skillHint = {
|
|
7416
|
+
expected_duration_ms: parsePositiveNumber(skillRecord["expected_duration_ms"]) ?? topLevelHint.expected_duration_ms,
|
|
7417
|
+
hard_timeout_ms: parsePositiveNumber(skillRecord["hard_timeout_ms"]) ?? topLevelHint.hard_timeout_ms
|
|
7418
|
+
};
|
|
7419
|
+
return skillHint.expected_duration_ms !== void 0 || skillHint.hard_timeout_ms !== void 0 ? skillHint : void 0;
|
|
7420
|
+
}
|
|
7136
7421
|
async function handleRequest(args, ctx) {
|
|
7137
7422
|
try {
|
|
7138
7423
|
const maxCost = args.max_cost ?? 50;
|
|
@@ -7196,6 +7481,7 @@ async function handleRequest(args, ctx) {
|
|
|
7196
7481
|
token: ctx.config.token,
|
|
7197
7482
|
cardId,
|
|
7198
7483
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7484
|
+
timeoutMs: args.timeout_ms,
|
|
7199
7485
|
identity: identityAuth
|
|
7200
7486
|
});
|
|
7201
7487
|
return {
|
|
@@ -7224,7 +7510,9 @@ async function handleRequest(args, ctx) {
|
|
|
7224
7510
|
};
|
|
7225
7511
|
}
|
|
7226
7512
|
const targetOwner = remoteCard["owner"] ?? remoteCard["agent_name"];
|
|
7513
|
+
const targetAgentId = typeof remoteCard["agent_id"] === "string" ? remoteCard["agent_id"] : void 0;
|
|
7227
7514
|
const gatewayUrl = remoteCard["gateway_url"];
|
|
7515
|
+
const timeoutHint = deriveTimeoutHintFromCard(remoteCard, args.skill_id);
|
|
7228
7516
|
if (gatewayUrl) {
|
|
7229
7517
|
let remoteCost = 0;
|
|
7230
7518
|
const remoteSkills = remoteCard["skills"];
|
|
@@ -7236,43 +7524,33 @@ async function handleRequest(args, ctx) {
|
|
|
7236
7524
|
remoteCost = remotePricing?.credits_per_call ?? 0;
|
|
7237
7525
|
}
|
|
7238
7526
|
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();
|
|
7527
|
+
if (!targetOwner) {
|
|
7528
|
+
return {
|
|
7529
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Paid remote request requires a target owner for relay routing" }) }]
|
|
7530
|
+
};
|
|
7269
7531
|
}
|
|
7532
|
+
const result = await requestViaTemporaryRelay({
|
|
7533
|
+
registryUrl: ctx.config.registry,
|
|
7534
|
+
owner: ctx.config.owner,
|
|
7535
|
+
token: ctx.config.token ?? "",
|
|
7536
|
+
targetOwner,
|
|
7537
|
+
targetAgentId,
|
|
7538
|
+
cardId,
|
|
7539
|
+
skillId: args.skill_id,
|
|
7540
|
+
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7541
|
+
timeoutMs: args.timeout_ms
|
|
7542
|
+
});
|
|
7543
|
+
return {
|
|
7544
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7545
|
+
};
|
|
7270
7546
|
} else {
|
|
7271
7547
|
const result = await requestCapability({
|
|
7272
7548
|
gatewayUrl,
|
|
7273
7549
|
token: ctx.config.token ?? "",
|
|
7274
7550
|
cardId,
|
|
7275
7551
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7552
|
+
timeoutMs: args.timeout_ms,
|
|
7553
|
+
timeoutHint,
|
|
7276
7554
|
identity: identityAuth
|
|
7277
7555
|
});
|
|
7278
7556
|
return {
|
|
@@ -7281,30 +7559,20 @@ async function handleRequest(args, ctx) {
|
|
|
7281
7559
|
}
|
|
7282
7560
|
}
|
|
7283
7561
|
if (targetOwner) {
|
|
7284
|
-
const
|
|
7562
|
+
const result = await requestViaTemporaryRelay({
|
|
7285
7563
|
registryUrl: ctx.config.registry,
|
|
7286
7564
|
owner: ctx.config.owner,
|
|
7287
7565
|
token: ctx.config.token ?? "",
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7566
|
+
targetOwner,
|
|
7567
|
+
targetAgentId,
|
|
7568
|
+
cardId,
|
|
7569
|
+
skillId: args.skill_id,
|
|
7570
|
+
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {} },
|
|
7571
|
+
timeoutMs: args.timeout_ms
|
|
7291
7572
|
});
|
|
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
|
-
}
|
|
7573
|
+
return {
|
|
7574
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7575
|
+
};
|
|
7308
7576
|
}
|
|
7309
7577
|
return {
|
|
7310
7578
|
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Remote card has no gateway_url and no owner for relay routing" }) }]
|
|
@@ -7381,17 +7649,24 @@ async function conductAction(task, opts) {
|
|
|
7381
7649
|
matchResults.map((m) => [m.subtask_id, m])
|
|
7382
7650
|
);
|
|
7383
7651
|
const resolveAgentUrl = (owner) => {
|
|
7384
|
-
const
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7652
|
+
const execDb = openDatabase(config.db_path);
|
|
7653
|
+
let matchingCards;
|
|
7654
|
+
try {
|
|
7655
|
+
matchingCards = listCards(execDb, owner);
|
|
7656
|
+
} finally {
|
|
7657
|
+
execDb.close();
|
|
7658
|
+
}
|
|
7659
|
+
const candidateNames = /* @__PURE__ */ new Set([owner.toLowerCase()]);
|
|
7660
|
+
for (const card of matchingCards) {
|
|
7661
|
+
candidateNames.add(card.owner.toLowerCase());
|
|
7662
|
+
if (typeof card.agent_id === "string" && card.agent_id.length > 0) {
|
|
7663
|
+
candidateNames.add(card.agent_id.toLowerCase());
|
|
7393
7664
|
}
|
|
7394
7665
|
}
|
|
7666
|
+
const peer = peers.find((p) => candidateNames.has(p.name.toLowerCase()));
|
|
7667
|
+
if (peer) {
|
|
7668
|
+
return { url: peer.url, cardId: matchingCards[0]?.id ?? owner };
|
|
7669
|
+
}
|
|
7395
7670
|
if (config.registry) {
|
|
7396
7671
|
let cardId = owner;
|
|
7397
7672
|
for (const m of matchMap.values()) {
|