agentbnb 8.2.2 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{card-EX2EYGCZ.js → card-BN643ZOY.js} +6 -2
- package/dist/card-T2XJZA5A.js +92 -0
- package/dist/{chunk-3LWBH7P3.js → chunk-4NFJ3VYZ.js} +20 -1
- package/dist/chunk-5AIYALBX.js +857 -0
- package/dist/chunk-6QMDJVMS.js +238 -0
- package/dist/{chunk-LKLKYXLV.js → chunk-74LZDEDT.js} +6 -4
- package/dist/{chunk-GKVTD4EZ.js → chunk-77KGEDH4.js} +1 -1
- package/dist/{chunk-QCGIG7WW.js → chunk-7IQE34QK.js} +14 -7
- package/dist/{chunk-QHZGOG3O.js → chunk-D242QZCR.js} +168 -41
- package/dist/chunk-EE3V3DXK.js +60 -0
- package/dist/{chunk-RYISHSHB.js → chunk-F3KIEVJ2.js} +207 -265
- package/dist/{chunk-XBGVQMQJ.js → chunk-FELGHDCA.js} +16 -39
- package/dist/{chunk-EJKW57ZV.js → chunk-GIEJVKZZ.js} +1 -1
- package/dist/{chunk-WVY2W7AA.js → chunk-I7KWA7OB.js} +20 -0
- package/dist/{chunk-4IPJJRTP.js → chunk-IGQNP3ZO.js} +5 -2
- package/dist/chunk-NQANA6WH.js +797 -0
- package/dist/{chunk-Z4MCGKTL.js → chunk-NX27AFPA.js} +15 -2
- package/dist/{chunk-Z2GEFFDO.js → chunk-O4Q7BRG6.js} +2 -2
- package/dist/{chunk-SSK653A6.js → chunk-PQIP7EXY.js} +6 -0
- package/dist/{chunk-EG6RS4JC.js → chunk-QFPXZITP.js} +20 -65
- package/dist/chunk-R4F4XII4.js +264 -0
- package/dist/{chunk-DYQOFGGI.js → chunk-RVBW2QXU.js} +178 -49
- package/dist/{chunk-CQFBNTGT.js → chunk-S7DZHKCG.js} +25 -12
- package/dist/chunk-U6LP4KWN.js +238 -0
- package/dist/{chunk-MWOXW7JQ.js → chunk-VJ7XBEY6.js} +24 -16
- package/dist/chunk-WTHMHNKC.js +129 -0
- package/dist/{chunk-OCSU2S6W.js → chunk-WX3GZVFG.js} +2 -1
- package/dist/{chunk-CKOOVZOI.js → chunk-YKMBFQC2.js} +37 -5
- package/dist/{chunk-S3V6R3EN.js → chunk-ZU2TP7CN.js} +70 -27
- package/dist/cli/index.js +211 -278
- package/dist/client-OKJJ3UP2.js +19 -0
- package/dist/client-UQBGCIPA.js +20 -0
- package/dist/conduct-4JDMWBQD.js +22 -0
- package/dist/{conduct-AZFLNUX3.js → conduct-VYYBCPHA.js} +14 -13
- package/dist/{conductor-mode-WKB42PYM.js → conductor-mode-OPGQJFLA.js} +12 -8
- package/dist/{conductor-mode-PLTB6MS3.js → conductor-mode-SBDCRIX6.js} +16 -11
- package/dist/execute-FZLQGIXB.js +14 -0
- package/dist/execute-TEZPQ5WP.js +15 -0
- package/dist/index.d.ts +172 -11
- package/dist/index.js +1529 -433
- package/dist/{process-guard-GH5LRNWO.js → process-guard-TNSUNHSR.js} +1 -1
- package/dist/{publish-capability-QDR2QIZ2.js → publish-capability-HVYILTPR.js} +4 -3
- package/dist/{reliability-metrics-QG7WC5QK.js → reliability-metrics-G7LPUYJD.js} +3 -1
- package/dist/reliability-metrics-RRUKJ4ME.js +20 -0
- package/dist/{request-NX7GSPIG.js → request-KJNKR27T.js} +96 -43
- package/dist/{serve-skill-E6EJQYAK.js → serve-skill-GC6NIQ5T.js} +10 -11
- package/dist/{server-VBCT32FC.js → server-YV3XPTX5.js} +11 -10
- package/dist/{service-coordinator-KMSA6BST.js → service-coordinator-RY5AKUZS.js} +420 -171
- package/dist/{skill-config-FETXPNVP.js → skill-config-5O2VR546.js} +1 -1
- package/dist/skills/agentbnb/bootstrap.js +550 -231
- package/dist/websocket-client-3U27WJUU.js +7 -0
- package/dist/{websocket-client-4Z5P54RU.js → websocket-client-SNDF3B6N.js} +1 -1
- package/package.json +18 -12
- package/skills/agentbnb/install.sh +0 -0
- package/dist/chunk-MCED4GDW.js +0 -1572
- package/dist/chunk-NWIQJ2CL.js +0 -108
- package/dist/chunk-WNXXLCV5.js +0 -32
- package/dist/client-XOLP5IUZ.js +0 -12
- package/dist/conduct-VPUYTNEA.js +0 -21
- package/dist/execute-NNDCXTN4.js +0 -13
- package/dist/execute-RIRHTIBU.js +0 -16
- package/dist/websocket-client-QOVARTRN.js +0 -7
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RelayClient,
|
|
3
|
-
RelayMessageSchema
|
|
4
|
-
} from "../../chunk-3LWBH7P3.js";
|
|
5
1
|
import {
|
|
6
2
|
AutoRequestor,
|
|
7
3
|
BudgetController,
|
|
@@ -16,29 +12,57 @@ 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,
|
|
37
41
|
computeReputation,
|
|
42
|
+
confirmEscrowDebit,
|
|
38
43
|
fetchRemoteCards,
|
|
39
44
|
filterCards,
|
|
40
|
-
getActivityFeed,
|
|
41
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,
|
|
42
66
|
getCard,
|
|
43
67
|
getCardsBySkillCapability,
|
|
44
68
|
getEvolutionHistory,
|
|
@@ -47,41 +71,23 @@ import {
|
|
|
47
71
|
getLatestEvolution,
|
|
48
72
|
getRequestLog,
|
|
49
73
|
getSkillRequestCount,
|
|
50
|
-
getTransactions,
|
|
51
|
-
holdEscrow,
|
|
52
74
|
insertCard,
|
|
53
75
|
insertEvolution,
|
|
54
76
|
insertFeedback,
|
|
55
77
|
insertRequestLog,
|
|
56
78
|
listCards,
|
|
57
|
-
lookupAgent,
|
|
58
|
-
mergeResults,
|
|
59
|
-
migrateOwner,
|
|
60
|
-
openCreditDb,
|
|
61
79
|
openDatabase,
|
|
62
|
-
releaseEscrow,
|
|
63
|
-
searchCards,
|
|
64
|
-
settleEscrow,
|
|
65
80
|
updateCard,
|
|
66
81
|
updateSkillAvailability,
|
|
67
82
|
updateSkillIdleRate
|
|
68
|
-
} from "../../chunk-
|
|
69
|
-
import "../../chunk-NWIQJ2CL.js";
|
|
83
|
+
} from "../../chunk-ZU2TP7CN.js";
|
|
70
84
|
import {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
saveKeyPair,
|
|
74
|
-
signEscrowReceipt,
|
|
75
|
-
verifyEscrowReceipt
|
|
76
|
-
} from "../../chunk-EJKW57ZV.js";
|
|
77
|
-
import {
|
|
78
|
-
getConfigDir,
|
|
79
|
-
loadConfig
|
|
80
|
-
} from "../../chunk-IVOYM3WG.js";
|
|
85
|
+
lookupAgent
|
|
86
|
+
} from "../../chunk-EE3V3DXK.js";
|
|
81
87
|
import {
|
|
82
88
|
AgentBnBError,
|
|
83
89
|
AnyCardSchema
|
|
84
|
-
} from "../../chunk-
|
|
90
|
+
} from "../../chunk-I7KWA7OB.js";
|
|
85
91
|
|
|
86
92
|
// skills/agentbnb/bootstrap.ts
|
|
87
93
|
import { join as join7, basename as basename2, dirname as dirname3 } from "path";
|
|
@@ -264,6 +270,9 @@ function isPidFileContent(value) {
|
|
|
264
270
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
265
271
|
|
|
266
272
|
// src/skills/executor.ts
|
|
273
|
+
function buildTimeoutError(skillId, timeoutMs) {
|
|
274
|
+
return `Skill "${skillId}" timed out after ${timeoutMs}ms`;
|
|
275
|
+
}
|
|
267
276
|
var SkillExecutor = class {
|
|
268
277
|
skillMap;
|
|
269
278
|
modeMap;
|
|
@@ -322,7 +331,20 @@ var SkillExecutor = class {
|
|
|
322
331
|
this.concurrencyGuard.acquire(skillId);
|
|
323
332
|
}
|
|
324
333
|
try {
|
|
325
|
-
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
|
+
});
|
|
326
348
|
return {
|
|
327
349
|
...modeResult,
|
|
328
350
|
latency_ms: Date.now() - startTime
|
|
@@ -393,7 +415,8 @@ var CapabilityDeclarationSchema = {
|
|
|
393
415
|
description: z.string().optional(),
|
|
394
416
|
capability_types: z.array(z.string()).optional(),
|
|
395
417
|
requires_capabilities: z.array(z.string()).optional(),
|
|
396
|
-
visibility: z.enum(["public", "private"]).optional()
|
|
418
|
+
visibility: z.enum(["public", "private"]).optional(),
|
|
419
|
+
expected_duration_ms: z.number().positive().optional()
|
|
397
420
|
};
|
|
398
421
|
var ApiSkillConfigSchema = z.object({
|
|
399
422
|
id: z.string().min(1),
|
|
@@ -677,6 +700,15 @@ var ApiExecutor = class {
|
|
|
677
700
|
import { execFile } from "child_process";
|
|
678
701
|
import { promisify } from "util";
|
|
679
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
|
+
}
|
|
680
712
|
function shellEscape(value) {
|
|
681
713
|
return "'" + value.replace(/'/g, "'\\''") + "'";
|
|
682
714
|
}
|
|
@@ -728,6 +760,8 @@ var PipelineExecutor = class {
|
|
|
728
760
|
async execute(config, params, onProgress) {
|
|
729
761
|
const pipelineConfig = config;
|
|
730
762
|
const steps = pipelineConfig.steps ?? [];
|
|
763
|
+
const pipelineTimeoutMs = pipelineConfig.timeout_ms;
|
|
764
|
+
const deadline = typeof pipelineTimeoutMs === "number" ? Date.now() + pipelineTimeoutMs : void 0;
|
|
731
765
|
if (steps.length === 0) {
|
|
732
766
|
return { success: true, result: null };
|
|
733
767
|
}
|
|
@@ -749,11 +783,41 @@ var PipelineExecutor = class {
|
|
|
749
783
|
context
|
|
750
784
|
);
|
|
751
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
|
+
};
|
|
752
807
|
if ("skill_id" in step && step.skill_id) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
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
|
+
}
|
|
757
821
|
if (!subResult.success) {
|
|
758
822
|
return {
|
|
759
823
|
success: false,
|
|
@@ -767,10 +831,16 @@ var PipelineExecutor = class {
|
|
|
767
831
|
context
|
|
768
832
|
);
|
|
769
833
|
try {
|
|
770
|
-
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
|
+
});
|
|
771
841
|
stepResult = stdout.trim();
|
|
772
842
|
} catch (err) {
|
|
773
|
-
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);
|
|
774
844
|
return {
|
|
775
845
|
success: false,
|
|
776
846
|
error: `Step ${i} failed: ${message}`
|
|
@@ -857,17 +927,43 @@ function executeProcess(config, payload) {
|
|
|
857
927
|
error: `Invalid agent name: "${config.agent_name}" (only alphanumeric, hyphens, underscores, dots allowed)`
|
|
858
928
|
};
|
|
859
929
|
}
|
|
860
|
-
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"}`;
|
|
861
942
|
try {
|
|
862
|
-
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
|
+
], {
|
|
863
952
|
timeout: timeoutMs
|
|
864
953
|
});
|
|
865
954
|
const text = stdout.toString().trim();
|
|
866
|
-
|
|
867
|
-
|
|
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
|
+
}
|
|
868
964
|
} catch (err) {
|
|
869
|
-
const
|
|
870
|
-
return { success: false, error:
|
|
965
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
966
|
+
return { success: false, error: message2 };
|
|
871
967
|
}
|
|
872
968
|
}
|
|
873
969
|
async function executeTelegram(config, payload) {
|
|
@@ -1276,23 +1372,27 @@ var AgentRuntime = class {
|
|
|
1276
1372
|
}
|
|
1277
1373
|
const modes = /* @__PURE__ */ new Map();
|
|
1278
1374
|
if (this.conductorEnabled) {
|
|
1279
|
-
const { ConductorMode } = await import("../../conductor-mode-
|
|
1280
|
-
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");
|
|
1281
1377
|
const { loadPeers: loadPeers2 } = await import("../../peers-CJ7T4RJO.js");
|
|
1282
1378
|
registerConductorCard(this.registryDb);
|
|
1283
1379
|
const resolveAgentUrl = (owner) => {
|
|
1284
1380
|
const peers = loadPeers2();
|
|
1285
|
-
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()));
|
|
1286
1390
|
if (!peer) {
|
|
1287
1391
|
throw new Error(
|
|
1288
1392
|
`No peer found for agent owner "${owner}". Add with: agentbnb connect ${owner} <url> <token>`
|
|
1289
1393
|
);
|
|
1290
1394
|
}
|
|
1291
|
-
const
|
|
1292
|
-
"SELECT id FROM capability_cards WHERE owner = ? LIMIT 1"
|
|
1293
|
-
);
|
|
1294
|
-
const row = stmt.get(owner);
|
|
1295
|
-
const cardId = row?.id ?? owner;
|
|
1395
|
+
const cardId = matchingCards[0]?.id ?? owner;
|
|
1296
1396
|
return { url: peer.url, cardId };
|
|
1297
1397
|
};
|
|
1298
1398
|
const conductorMode = new ConductorMode({
|
|
@@ -1334,7 +1434,8 @@ var AgentRuntime = class {
|
|
|
1334
1434
|
}
|
|
1335
1435
|
/**
|
|
1336
1436
|
* Recovers orphaned escrows by releasing them.
|
|
1337
|
-
* 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.
|
|
1338
1439
|
* Errors during individual release are swallowed (escrow may have settled between query and release).
|
|
1339
1440
|
*/
|
|
1340
1441
|
async recoverOrphanedEscrows() {
|
|
@@ -1342,7 +1443,7 @@ var AgentRuntime = class {
|
|
|
1342
1443
|
Date.now() - this.orphanedEscrowAgeMinutes * 60 * 1e3
|
|
1343
1444
|
).toISOString();
|
|
1344
1445
|
const orphaned = this.creditDb.prepare(
|
|
1345
|
-
"SELECT id FROM credit_escrow WHERE status
|
|
1446
|
+
"SELECT id FROM credit_escrow WHERE status IN ('held', 'abandoned') AND created_at < ?"
|
|
1346
1447
|
).all(cutoff);
|
|
1347
1448
|
for (const row of orphaned) {
|
|
1348
1449
|
try {
|
|
@@ -2438,14 +2539,16 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
|
|
|
2438
2539
|
throw new Error("Invalid consumer signature on escrow settle");
|
|
2439
2540
|
}
|
|
2440
2541
|
}
|
|
2441
|
-
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);
|
|
2442
2545
|
if (!escrowRow) {
|
|
2443
2546
|
throw new Error(`Escrow not found or already settled: ${escrowId}`);
|
|
2444
2547
|
}
|
|
2445
|
-
const
|
|
2548
|
+
const NETWORK_FEE_RATE2 = 0.05;
|
|
2446
2549
|
if (success) {
|
|
2447
2550
|
settleEscrow(creditDb, escrowId, providerAgentId);
|
|
2448
|
-
const networkFee = Math.floor(escrowRow.amount *
|
|
2551
|
+
const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE2);
|
|
2449
2552
|
const providerAmount = escrowRow.amount - networkFee;
|
|
2450
2553
|
return {
|
|
2451
2554
|
escrow_id: escrowId,
|
|
@@ -2769,7 +2872,16 @@ function handleJobRelayResponse(opts) {
|
|
|
2769
2872
|
// src/relay/websocket-relay.ts
|
|
2770
2873
|
var RATE_LIMIT_MAX = 60;
|
|
2771
2874
|
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
2772
|
-
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
|
+
}
|
|
2773
2885
|
function registerWebSocketRelay(server, db, creditDb) {
|
|
2774
2886
|
const connections = /* @__PURE__ */ new Map();
|
|
2775
2887
|
const agentIdToOwner = /* @__PURE__ */ new Map();
|
|
@@ -2783,6 +2895,136 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2783
2895
|
if (connections.has(target)) return target;
|
|
2784
2896
|
return void 0;
|
|
2785
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
|
+
}
|
|
2786
3028
|
function checkRateLimit(owner) {
|
|
2787
3029
|
const now = Date.now();
|
|
2788
3030
|
const entry = rateLimits.get(owner);
|
|
@@ -2832,15 +3074,20 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2832
3074
|
} catch {
|
|
2833
3075
|
}
|
|
2834
3076
|
}
|
|
2835
|
-
function upsertCard(cardData, owner) {
|
|
2836
|
-
const parsed = AnyCardSchema.safeParse(
|
|
3077
|
+
function upsertCard(cardData, owner, agentId) {
|
|
3078
|
+
const parsed = AnyCardSchema.safeParse(
|
|
3079
|
+
agentId ? { ...cardData, agent_id: agentId } : cardData
|
|
3080
|
+
);
|
|
2837
3081
|
if (!parsed.success) {
|
|
2838
3082
|
throw new AgentBnBError(
|
|
2839
3083
|
`Card validation failed: ${parsed.error.message}`,
|
|
2840
3084
|
"VALIDATION_ERROR"
|
|
2841
3085
|
);
|
|
2842
3086
|
}
|
|
2843
|
-
const card =
|
|
3087
|
+
const card = attachCanonicalAgentId(db, {
|
|
3088
|
+
...parsed.data,
|
|
3089
|
+
availability: { ...parsed.data.availability, online: true }
|
|
3090
|
+
});
|
|
2844
3091
|
const cardId = card.id;
|
|
2845
3092
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2846
3093
|
const existing = db.prepare("SELECT id FROM capability_cards WHERE id = ?").get(cardId);
|
|
@@ -2894,7 +3141,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2894
3141
|
agentIdToOwner.set(agentEntry.agent_id, owner);
|
|
2895
3142
|
for (const agentCard of agentEntry.cards) {
|
|
2896
3143
|
try {
|
|
2897
|
-
upsertCard(agentCard, owner);
|
|
3144
|
+
upsertCard(agentCard, owner, agentEntry.agent_id);
|
|
2898
3145
|
} catch {
|
|
2899
3146
|
}
|
|
2900
3147
|
}
|
|
@@ -2908,7 +3155,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2908
3155
|
}
|
|
2909
3156
|
let cardId;
|
|
2910
3157
|
try {
|
|
2911
|
-
cardId = upsertCard(card, owner);
|
|
3158
|
+
cardId = upsertCard(card, owner, msg.agent_id);
|
|
2912
3159
|
} catch (err) {
|
|
2913
3160
|
console.error(`[relay] card validation failed for ${owner}:`, err instanceof Error ? err.message : err);
|
|
2914
3161
|
cardId = card.id ?? owner;
|
|
@@ -2918,7 +3165,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2918
3165
|
if (msg.cards && msg.cards.length > 0) {
|
|
2919
3166
|
for (const extraCard of msg.cards) {
|
|
2920
3167
|
try {
|
|
2921
|
-
upsertCard(extraCard, owner);
|
|
3168
|
+
upsertCard(extraCard, owner, msg.agent_id);
|
|
2922
3169
|
} catch {
|
|
2923
3170
|
}
|
|
2924
3171
|
}
|
|
@@ -2973,23 +3220,17 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
2973
3220
|
console.error("[relay] credit hold error (non-fatal):", err);
|
|
2974
3221
|
}
|
|
2975
3222
|
}
|
|
2976
|
-
const
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
type: "response",
|
|
2988
|
-
id: msg.id,
|
|
2989
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
2990
|
-
});
|
|
2991
|
-
}, RELAY_TIMEOUT_MS);
|
|
2992
|
-
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);
|
|
2993
3234
|
sendMessage(targetWs, {
|
|
2994
3235
|
type: "incoming_request",
|
|
2995
3236
|
id: msg.id,
|
|
@@ -3001,30 +3242,23 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3001
3242
|
escrow_receipt: msg.escrow_receipt
|
|
3002
3243
|
});
|
|
3003
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
|
+
}
|
|
3004
3258
|
function handleRelayProgress(msg) {
|
|
3005
3259
|
const pending = pendingRequests.get(msg.id);
|
|
3006
3260
|
if (!pending) return;
|
|
3007
|
-
|
|
3008
|
-
const newTimeout = setTimeout(() => {
|
|
3009
|
-
const p = pendingRequests.get(msg.id);
|
|
3010
|
-
pendingRequests.delete(msg.id);
|
|
3011
|
-
if (p?.escrowId && creditDb) {
|
|
3012
|
-
try {
|
|
3013
|
-
releaseForRelay(creditDb, p.escrowId);
|
|
3014
|
-
} catch (e) {
|
|
3015
|
-
console.error("[relay] escrow release on progress timeout failed:", e);
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
const originWs2 = connections.get(pending.originOwner);
|
|
3019
|
-
if (originWs2 && originWs2.readyState === 1) {
|
|
3020
|
-
sendMessage(originWs2, {
|
|
3021
|
-
type: "response",
|
|
3022
|
-
id: msg.id,
|
|
3023
|
-
error: { code: -32603, message: "Relay request timeout" }
|
|
3024
|
-
});
|
|
3025
|
-
}
|
|
3026
|
-
}, RELAY_TIMEOUT_MS);
|
|
3027
|
-
pending.timeout = newTimeout;
|
|
3261
|
+
transitionPendingToProgressing(msg.id, pending);
|
|
3028
3262
|
const originWs = connections.get(pending.originOwner);
|
|
3029
3263
|
if (originWs && originWs.readyState === 1) {
|
|
3030
3264
|
sendMessage(originWs, {
|
|
@@ -3038,7 +3272,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3038
3272
|
function handleRelayResponse(msg) {
|
|
3039
3273
|
const pending = pendingRequests.get(msg.id);
|
|
3040
3274
|
if (!pending) return;
|
|
3041
|
-
|
|
3275
|
+
clearPendingTimers(pending);
|
|
3042
3276
|
pendingRequests.delete(msg.id);
|
|
3043
3277
|
if (pending.jobId && creditDb) {
|
|
3044
3278
|
try {
|
|
@@ -3101,16 +3335,15 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3101
3335
|
connections.delete(owner);
|
|
3102
3336
|
rateLimits.delete(owner);
|
|
3103
3337
|
agentCapacities.delete(owner);
|
|
3104
|
-
for (const [agentId,
|
|
3105
|
-
if (
|
|
3338
|
+
for (const [agentId, mappedOwner] of Array.from(agentIdToOwner.entries())) {
|
|
3339
|
+
if (mappedOwner === owner) {
|
|
3106
3340
|
agentIdToOwner.delete(agentId);
|
|
3107
|
-
break;
|
|
3108
3341
|
}
|
|
3109
3342
|
}
|
|
3110
3343
|
markOwnerOffline(owner);
|
|
3111
3344
|
for (const [reqId, pending] of pendingRequests) {
|
|
3112
3345
|
if (pending.targetOwner === owner) {
|
|
3113
|
-
|
|
3346
|
+
clearPendingTimers(pending);
|
|
3114
3347
|
pendingRequests.delete(reqId);
|
|
3115
3348
|
if (pending.escrowId && creditDb) {
|
|
3116
3349
|
try {
|
|
@@ -3128,14 +3361,19 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3128
3361
|
});
|
|
3129
3362
|
}
|
|
3130
3363
|
} else if (pending.originOwner === owner) {
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
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
|
+
}
|
|
3138
3374
|
}
|
|
3375
|
+
} else {
|
|
3376
|
+
transitionPendingToAbandoned(reqId, pending);
|
|
3139
3377
|
}
|
|
3140
3378
|
}
|
|
3141
3379
|
}
|
|
@@ -3178,7 +3416,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3178
3416
|
return;
|
|
3179
3417
|
}
|
|
3180
3418
|
try {
|
|
3181
|
-
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);
|
|
3182
3422
|
if (!escrow) {
|
|
3183
3423
|
sendMessage(ws, { type: "error", code: "escrow_not_found", message: `Escrow not found: ${msg.escrow_id}`, request_id: msg.request_id });
|
|
3184
3424
|
return;
|
|
@@ -3275,6 +3515,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3275
3515
|
case "relay_response":
|
|
3276
3516
|
handleRelayResponse(msg);
|
|
3277
3517
|
break;
|
|
3518
|
+
case "relay_started":
|
|
3519
|
+
handleRelayStarted(msg);
|
|
3520
|
+
break;
|
|
3278
3521
|
case "relay_progress":
|
|
3279
3522
|
handleRelayProgress(msg);
|
|
3280
3523
|
break;
|
|
@@ -3321,7 +3564,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
3321
3564
|
}
|
|
3322
3565
|
connections.clear();
|
|
3323
3566
|
for (const [, pending] of pendingRequests) {
|
|
3324
|
-
|
|
3567
|
+
clearPendingTimers(pending);
|
|
3325
3568
|
}
|
|
3326
3569
|
pendingRequests.clear();
|
|
3327
3570
|
rateLimits.clear();
|
|
@@ -4620,6 +4863,9 @@ function stripInternal(card) {
|
|
|
4620
4863
|
const { _internal: _, ...publicCard } = card;
|
|
4621
4864
|
return publicCard;
|
|
4622
4865
|
}
|
|
4866
|
+
function buildSqlPlaceholders(count) {
|
|
4867
|
+
return Array.from({ length: count }, () => "?").join(", ");
|
|
4868
|
+
}
|
|
4623
4869
|
function createRegistryServer(opts) {
|
|
4624
4870
|
const { registryDb: db, silent = false } = opts;
|
|
4625
4871
|
const server = Fastify2({ logger: !silent });
|
|
@@ -5029,11 +5275,11 @@ function createRegistryServer(opts) {
|
|
|
5029
5275
|
const card = result.data;
|
|
5030
5276
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5031
5277
|
if (card.spec_version === "2.0") {
|
|
5032
|
-
const cardWithTimestamps = {
|
|
5278
|
+
const cardWithTimestamps = attachCanonicalAgentId(db, {
|
|
5033
5279
|
...card,
|
|
5034
5280
|
created_at: card.created_at ?? now,
|
|
5035
5281
|
updated_at: now
|
|
5036
|
-
};
|
|
5282
|
+
});
|
|
5037
5283
|
db.prepare(
|
|
5038
5284
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
5039
5285
|
VALUES (?, ?, ?, ?, ?)`
|
|
@@ -5154,19 +5400,16 @@ function createRegistryServer(opts) {
|
|
|
5154
5400
|
if (ownerCards.length === 0) {
|
|
5155
5401
|
return reply.status(404).send({ error: "Agent not found" });
|
|
5156
5402
|
}
|
|
5157
|
-
const
|
|
5158
|
-
|
|
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})`
|
|
5159
5410
|
);
|
|
5160
|
-
const
|
|
5161
|
-
const
|
|
5162
|
-
const lastActiveStmt = db.prepare(`
|
|
5163
|
-
SELECT MAX(rl.created_at) as last_req
|
|
5164
|
-
FROM request_log rl
|
|
5165
|
-
INNER JOIN capability_cards cc ON rl.card_id = cc.id
|
|
5166
|
-
WHERE cc.owner = ?
|
|
5167
|
-
`);
|
|
5168
|
-
const lastActiveRow = lastActiveStmt.get(owner);
|
|
5169
|
-
const lastActive = lastActiveRow?.last_req ?? memberRow?.latest ?? joinedAt;
|
|
5411
|
+
const lastActiveRow = lastActiveStmt.get(...ownerCardIds);
|
|
5412
|
+
const lastActive = lastActiveRow?.last_req ?? latestCardUpdate ?? joinedAt;
|
|
5170
5413
|
const metricsStmt = db.prepare(`
|
|
5171
5414
|
SELECT
|
|
5172
5415
|
SUM(CASE WHEN rl.failure_reason IS NULL OR rl.failure_reason IN ('bad_execution','auth_error')
|
|
@@ -5176,10 +5419,9 @@ function createRegistryServer(opts) {
|
|
|
5176
5419
|
COUNT(DISTINCT rl.requester) as unique_requesters,
|
|
5177
5420
|
COUNT(DISTINCT CASE WHEN rl.status = 'success' THEN rl.requester END) as repeat_success_requesters
|
|
5178
5421
|
FROM request_log rl
|
|
5179
|
-
|
|
5180
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5422
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5181
5423
|
`);
|
|
5182
|
-
const metricsRow = metricsStmt.get(
|
|
5424
|
+
const metricsRow = metricsStmt.get(...ownerCardIds);
|
|
5183
5425
|
const totalExec = metricsRow?.total ?? 0;
|
|
5184
5426
|
const successExec = metricsRow?.successes ?? 0;
|
|
5185
5427
|
const successRate = totalExec > 0 ? successExec / totalExec : 0;
|
|
@@ -5193,25 +5435,23 @@ function createRegistryServer(opts) {
|
|
|
5193
5435
|
COUNT(*) as count,
|
|
5194
5436
|
SUM(CASE WHEN rl.status = 'success' THEN 1 ELSE 0 END) as success
|
|
5195
5437
|
FROM request_log rl
|
|
5196
|
-
|
|
5197
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5438
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5198
5439
|
AND rl.created_at >= DATE('now', '-7 days')
|
|
5199
5440
|
GROUP BY DATE(rl.created_at)
|
|
5200
5441
|
ORDER BY day ASC
|
|
5201
5442
|
`);
|
|
5202
|
-
const trend_7d = trendStmt.all(
|
|
5443
|
+
const trend_7d = trendStmt.all(...ownerCardIds).map((r) => ({ date: r.day, count: r.count, success: r.success }));
|
|
5203
5444
|
let performanceTier = 0;
|
|
5204
5445
|
if (totalExec > 10) performanceTier = 1;
|
|
5205
5446
|
if (totalExec > 50 && successRate >= 0.85) performanceTier = 2;
|
|
5206
5447
|
const proofsStmt = db.prepare(`
|
|
5207
5448
|
SELECT rl.card_name, rl.status, rl.latency_ms, rl.id, rl.created_at
|
|
5208
5449
|
FROM request_log rl
|
|
5209
|
-
|
|
5210
|
-
WHERE cc.owner = ? AND rl.action_type IS NULL
|
|
5450
|
+
WHERE rl.card_id IN (${cardIdPlaceholders}) AND rl.action_type IS NULL
|
|
5211
5451
|
ORDER BY rl.created_at DESC
|
|
5212
5452
|
LIMIT 10
|
|
5213
5453
|
`);
|
|
5214
|
-
const proofRows = proofsStmt.all(
|
|
5454
|
+
const proofRows = proofsStmt.all(...ownerCardIds);
|
|
5215
5455
|
const statusToOutcomeClass = (s) => {
|
|
5216
5456
|
if (s === "success") return "completed";
|
|
5217
5457
|
if (s === "timeout") return "cancelled";
|
|
@@ -5237,22 +5477,20 @@ function createRegistryServer(opts) {
|
|
|
5237
5477
|
const activityStmt = db.prepare(`
|
|
5238
5478
|
SELECT rl.id, rl.card_name, rl.requester, rl.status, rl.credits_charged, rl.created_at
|
|
5239
5479
|
FROM request_log rl
|
|
5240
|
-
|
|
5241
|
-
WHERE cc.owner = ?
|
|
5480
|
+
WHERE rl.card_id IN (${cardIdPlaceholders})
|
|
5242
5481
|
ORDER BY rl.created_at DESC
|
|
5243
5482
|
LIMIT 10
|
|
5244
5483
|
`);
|
|
5245
|
-
const recentActivity = activityStmt.all(
|
|
5484
|
+
const recentActivity = activityStmt.all(...ownerCardIds);
|
|
5246
5485
|
const skillCount = ownerCards.reduce((sum, card) => sum + (card.skills?.length ?? 1), 0);
|
|
5247
5486
|
const creditsStmt = db.prepare(`
|
|
5248
|
-
SELECT SUM(CASE WHEN rl.status = 'success' THEN rl.credits_charged ELSE 0 END) as credits_earned
|
|
5249
|
-
FROM
|
|
5250
|
-
|
|
5251
|
-
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})
|
|
5252
5490
|
`);
|
|
5253
|
-
const creditsRow = creditsStmt.get(
|
|
5491
|
+
const creditsRow = creditsStmt.get(...ownerCardIds);
|
|
5254
5492
|
const response = {
|
|
5255
|
-
owner,
|
|
5493
|
+
owner: resolvedOwner,
|
|
5256
5494
|
agent_name: v2Card?.agent_name,
|
|
5257
5495
|
short_description: v2Card?.short_description,
|
|
5258
5496
|
joined_at: joinedAt,
|
|
@@ -5284,7 +5522,7 @@ function createRegistryServer(opts) {
|
|
|
5284
5522
|
return reply.send({
|
|
5285
5523
|
...response,
|
|
5286
5524
|
profile: {
|
|
5287
|
-
owner,
|
|
5525
|
+
owner: resolvedOwner,
|
|
5288
5526
|
skill_count: skillCount,
|
|
5289
5527
|
success_rate: successRate > 0 ? successRate : null,
|
|
5290
5528
|
total_earned: creditsRow?.credits_earned ?? 0,
|
|
@@ -5556,7 +5794,7 @@ function createRegistryServer(opts) {
|
|
|
5556
5794
|
return { card_id: target.cardId, skill_id: target.skillId };
|
|
5557
5795
|
}
|
|
5558
5796
|
if (!relayClient) {
|
|
5559
|
-
const { RelayClient: RelayClient2 } = await import("../../websocket-client-
|
|
5797
|
+
const { RelayClient: RelayClient2 } = await import("../../websocket-client-SNDF3B6N.js");
|
|
5560
5798
|
relayClient = new RelayClient2({
|
|
5561
5799
|
registryUrl: relayRegistryUrl,
|
|
5562
5800
|
owner: relayRequesterOwner,
|
|
@@ -5578,7 +5816,7 @@ function createRegistryServer(opts) {
|
|
|
5578
5816
|
});
|
|
5579
5817
|
await relayClient.connect();
|
|
5580
5818
|
}
|
|
5581
|
-
const { requestViaRelay: requestViaRelay2 } = await import("../../client-
|
|
5819
|
+
const { requestViaRelay: requestViaRelay2 } = await import("../../client-OKJJ3UP2.js");
|
|
5582
5820
|
return requestViaRelay2(relayClient, {
|
|
5583
5821
|
targetOwner: target.owner,
|
|
5584
5822
|
cardId: target.cardId,
|
|
@@ -5834,7 +6072,7 @@ function createRegistryServer(opts) {
|
|
|
5834
6072
|
if (!opts.creditDb) {
|
|
5835
6073
|
return reply.code(404).send({ error: "Credit system not enabled" });
|
|
5836
6074
|
}
|
|
5837
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
6075
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
5838
6076
|
const metrics = getReliabilityMetrics(opts.creditDb, owner);
|
|
5839
6077
|
if (!metrics) {
|
|
5840
6078
|
return reply.code(404).send({ error: "No reliability data for this provider" });
|
|
@@ -5852,38 +6090,37 @@ function createRegistryServer(opts) {
|
|
|
5852
6090
|
}
|
|
5853
6091
|
}, async (request, reply) => {
|
|
5854
6092
|
const { owner } = request.params;
|
|
5855
|
-
const
|
|
5856
|
-
"SELECT id, data FROM capability_cards WHERE owner = ?"
|
|
5857
|
-
).all(owner);
|
|
6093
|
+
const cards = listCards(db, owner);
|
|
5858
6094
|
const agents = [];
|
|
5859
|
-
for (const
|
|
6095
|
+
for (const card of cards) {
|
|
5860
6096
|
try {
|
|
5861
|
-
const
|
|
6097
|
+
const rawCard = card;
|
|
6098
|
+
const providerIdentity = typeof card.agent_id === "string" && card.agent_id.length > 0 ? card.agent_id : card.owner;
|
|
5862
6099
|
let earnings = 0;
|
|
5863
6100
|
let spend = 0;
|
|
5864
6101
|
if (opts.creditDb) {
|
|
5865
6102
|
const earningRow = opts.creditDb.prepare(
|
|
5866
6103
|
"SELECT COALESCE(SUM(amount), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'settlement' AND amount > 0"
|
|
5867
|
-
).get(
|
|
6104
|
+
).get(providerIdentity);
|
|
5868
6105
|
earnings = earningRow.total;
|
|
5869
6106
|
const spendRow = opts.creditDb.prepare(
|
|
5870
6107
|
"SELECT COALESCE(SUM(ABS(amount)), 0) as total FROM credit_transactions WHERE owner = ? AND reason = 'escrow_hold'"
|
|
5871
|
-
).get(
|
|
6108
|
+
).get(providerIdentity);
|
|
5872
6109
|
spend = spendRow.total;
|
|
5873
6110
|
}
|
|
5874
6111
|
const successCount = db.prepare(
|
|
5875
6112
|
"SELECT COUNT(*) as cnt FROM request_log WHERE card_id = ? AND status = 'success' AND (action_type IS NULL OR action_type = 'auto_share')"
|
|
5876
|
-
).get(
|
|
6113
|
+
).get(card.id).cnt;
|
|
5877
6114
|
const failureCount = db.prepare(
|
|
5878
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')"
|
|
5879
|
-
).get(
|
|
6116
|
+
).get(card.id).cnt;
|
|
5880
6117
|
const totalExec = successCount + failureCount;
|
|
5881
6118
|
const successRate = totalExec > 0 ? successCount / totalExec : 0;
|
|
5882
6119
|
let failureBreakdown = {};
|
|
5883
6120
|
try {
|
|
5884
6121
|
const failureRows = db.prepare(
|
|
5885
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"
|
|
5886
|
-
).all(
|
|
6123
|
+
).all(card.id);
|
|
5887
6124
|
for (const fr of failureRows) {
|
|
5888
6125
|
failureBreakdown[fr.failure_reason] = fr.cnt;
|
|
5889
6126
|
}
|
|
@@ -5891,12 +6128,12 @@ function createRegistryServer(opts) {
|
|
|
5891
6128
|
}
|
|
5892
6129
|
let reliability = null;
|
|
5893
6130
|
if (opts.creditDb) {
|
|
5894
|
-
const { getReliabilityMetrics } = await import("../../reliability-metrics-
|
|
5895
|
-
reliability = getReliabilityMetrics(opts.creditDb,
|
|
6131
|
+
const { getReliabilityMetrics } = await import("../../reliability-metrics-G7LPUYJD.js");
|
|
6132
|
+
reliability = getReliabilityMetrics(opts.creditDb, providerIdentity);
|
|
5896
6133
|
}
|
|
5897
6134
|
agents.push({
|
|
5898
|
-
id:
|
|
5899
|
-
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,
|
|
5900
6137
|
online: card.availability?.online ?? false,
|
|
5901
6138
|
current_load: 0,
|
|
5902
6139
|
// Will be populated from relay heartbeat data in future
|
|
@@ -6174,6 +6411,32 @@ import { spawn as spawn2 } from "child_process";
|
|
|
6174
6411
|
import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
|
|
6175
6412
|
import { join as join5 } from "path";
|
|
6176
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
|
+
}
|
|
6177
6440
|
var ServiceCoordinator = class {
|
|
6178
6441
|
config;
|
|
6179
6442
|
guard;
|
|
@@ -6318,8 +6581,11 @@ var ServiceCoordinator = class {
|
|
|
6318
6581
|
console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
|
|
6319
6582
|
}
|
|
6320
6583
|
if (opts.conductorEnabled && this.config.conductor?.public) {
|
|
6321
|
-
const { buildConductorCard } = await import("../../card-
|
|
6322
|
-
const conductorCard =
|
|
6584
|
+
const { buildConductorCard } = await import("../../card-BN643ZOY.js");
|
|
6585
|
+
const conductorCard = attachCanonicalAgentId(
|
|
6586
|
+
this.runtime.registryDb,
|
|
6587
|
+
buildConductorCard(this.config.owner)
|
|
6588
|
+
);
|
|
6323
6589
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6324
6590
|
const existing = this.runtime.registryDb.prepare("SELECT id FROM capability_cards WHERE id = ?").get(conductorCard.id);
|
|
6325
6591
|
if (existing) {
|
|
@@ -6375,27 +6641,11 @@ var ServiceCoordinator = class {
|
|
|
6375
6641
|
}
|
|
6376
6642
|
}
|
|
6377
6643
|
if (opts.registryUrl && opts.relay) {
|
|
6378
|
-
const { RelayClient: RelayClient2 } = await import("../../websocket-client-
|
|
6379
|
-
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-
|
|
6380
|
-
const
|
|
6381
|
-
const
|
|
6382
|
-
id: randomUUID8(),
|
|
6383
|
-
owner: this.config.owner,
|
|
6384
|
-
name: this.config.owner,
|
|
6385
|
-
description: "Agent registered via CLI",
|
|
6386
|
-
spec_version: "1.0",
|
|
6387
|
-
level: 1,
|
|
6388
|
-
inputs: [],
|
|
6389
|
-
outputs: [],
|
|
6390
|
-
pricing: { credits_per_call: 1 },
|
|
6391
|
-
availability: { online: true }
|
|
6392
|
-
};
|
|
6393
|
-
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);
|
|
6394
6648
|
if (this.config.conductor?.public) {
|
|
6395
|
-
const { buildConductorCard } = await import("../../card-EX2EYGCZ.js");
|
|
6396
|
-
additionalCards.push(
|
|
6397
|
-
buildConductorCard(this.config.owner)
|
|
6398
|
-
);
|
|
6399
6649
|
console.log("Conductor card will be published to registry (conductor.public: true)");
|
|
6400
6650
|
}
|
|
6401
6651
|
this.relayClient = new RelayClient2({
|
|
@@ -6403,9 +6653,10 @@ var ServiceCoordinator = class {
|
|
|
6403
6653
|
owner: this.config.owner,
|
|
6404
6654
|
agent_id: this.config.agent_id,
|
|
6405
6655
|
token: this.config.token,
|
|
6406
|
-
card,
|
|
6656
|
+
card: primaryCard,
|
|
6407
6657
|
cards: additionalCards.length > 0 ? additionalCards : void 0,
|
|
6408
6658
|
onRequest: async (req) => {
|
|
6659
|
+
this.relayClient?.sendStarted(req.id, "provider acknowledged");
|
|
6409
6660
|
const onProgress = (info) => {
|
|
6410
6661
|
this.relayClient.sendProgress(req.id, info);
|
|
6411
6662
|
};
|
|
@@ -6721,6 +6972,14 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
6721
6972
|
return { escrowId, receipt };
|
|
6722
6973
|
}
|
|
6723
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
|
+
|
|
6724
6983
|
// src/app/agentbnb-service.ts
|
|
6725
6984
|
var AgentBnBService = class {
|
|
6726
6985
|
coordinator;
|
|
@@ -7130,8 +7389,35 @@ var requestInputSchema = {
|
|
|
7130
7389
|
card_id: z10.string().optional().describe("Direct card ID to request (skips search)"),
|
|
7131
7390
|
skill_id: z10.string().optional().describe("Specific skill within a v2.0 card"),
|
|
7132
7391
|
params: z10.record(z10.unknown()).optional().describe("Input parameters for the capability"),
|
|
7133
|
-
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")
|
|
7134
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
|
+
}
|
|
7135
7421
|
async function handleRequest(args, ctx) {
|
|
7136
7422
|
try {
|
|
7137
7423
|
const maxCost = args.max_cost ?? 50;
|
|
@@ -7195,6 +7481,7 @@ async function handleRequest(args, ctx) {
|
|
|
7195
7481
|
token: ctx.config.token,
|
|
7196
7482
|
cardId,
|
|
7197
7483
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7484
|
+
timeoutMs: args.timeout_ms,
|
|
7198
7485
|
identity: identityAuth
|
|
7199
7486
|
});
|
|
7200
7487
|
return {
|
|
@@ -7223,45 +7510,70 @@ async function handleRequest(args, ctx) {
|
|
|
7223
7510
|
};
|
|
7224
7511
|
}
|
|
7225
7512
|
const targetOwner = remoteCard["owner"] ?? remoteCard["agent_name"];
|
|
7513
|
+
const targetAgentId = typeof remoteCard["agent_id"] === "string" ? remoteCard["agent_id"] : void 0;
|
|
7226
7514
|
const gatewayUrl = remoteCard["gateway_url"];
|
|
7515
|
+
const timeoutHint = deriveTimeoutHintFromCard(remoteCard, args.skill_id);
|
|
7227
7516
|
if (gatewayUrl) {
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
});
|
|
7248
|
-
try {
|
|
7249
|
-
await relay.connect();
|
|
7250
|
-
const result = await relay.request({
|
|
7517
|
+
let remoteCost = 0;
|
|
7518
|
+
const remoteSkills = remoteCard["skills"];
|
|
7519
|
+
if (Array.isArray(remoteSkills)) {
|
|
7520
|
+
const matchedSkill = args.skill_id ? remoteSkills.find((s) => s.id === args.skill_id) : remoteSkills[0];
|
|
7521
|
+
remoteCost = matchedSkill?.pricing?.credits_per_call ?? 0;
|
|
7522
|
+
} else {
|
|
7523
|
+
const remotePricing = remoteCard["pricing"];
|
|
7524
|
+
remoteCost = remotePricing?.credits_per_call ?? 0;
|
|
7525
|
+
}
|
|
7526
|
+
if (remoteCost > 0) {
|
|
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
|
+
};
|
|
7531
|
+
}
|
|
7532
|
+
const result = await requestViaTemporaryRelay({
|
|
7533
|
+
registryUrl: ctx.config.registry,
|
|
7534
|
+
owner: ctx.config.owner,
|
|
7535
|
+
token: ctx.config.token ?? "",
|
|
7251
7536
|
targetOwner,
|
|
7537
|
+
targetAgentId,
|
|
7252
7538
|
cardId,
|
|
7253
7539
|
skillId: args.skill_id,
|
|
7254
|
-
params: args.params ?? {},
|
|
7255
|
-
|
|
7256
|
-
|
|
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
|
+
};
|
|
7546
|
+
} else {
|
|
7547
|
+
const result = await requestCapability({
|
|
7548
|
+
gatewayUrl,
|
|
7549
|
+
token: ctx.config.token ?? "",
|
|
7550
|
+
cardId,
|
|
7551
|
+
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7552
|
+
timeoutMs: args.timeout_ms,
|
|
7553
|
+
timeoutHint,
|
|
7554
|
+
identity: identityAuth
|
|
7257
7555
|
});
|
|
7258
7556
|
return {
|
|
7259
7557
|
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7260
7558
|
};
|
|
7261
|
-
} finally {
|
|
7262
|
-
relay.disconnect();
|
|
7263
7559
|
}
|
|
7264
7560
|
}
|
|
7561
|
+
if (targetOwner) {
|
|
7562
|
+
const result = await requestViaTemporaryRelay({
|
|
7563
|
+
registryUrl: ctx.config.registry,
|
|
7564
|
+
owner: ctx.config.owner,
|
|
7565
|
+
token: ctx.config.token ?? "",
|
|
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
|
|
7572
|
+
});
|
|
7573
|
+
return {
|
|
7574
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, result }, null, 2) }]
|
|
7575
|
+
};
|
|
7576
|
+
}
|
|
7265
7577
|
return {
|
|
7266
7578
|
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Remote card has no gateway_url and no owner for relay routing" }) }]
|
|
7267
7579
|
};
|
|
@@ -7337,17 +7649,24 @@ async function conductAction(task, opts) {
|
|
|
7337
7649
|
matchResults.map((m) => [m.subtask_id, m])
|
|
7338
7650
|
);
|
|
7339
7651
|
const resolveAgentUrl = (owner) => {
|
|
7340
|
-
const
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
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());
|
|
7349
7664
|
}
|
|
7350
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
|
+
}
|
|
7351
7670
|
if (config.registry) {
|
|
7352
7671
|
let cardId = owner;
|
|
7353
7672
|
for (const m of matchMap.values()) {
|