agentbnb 9.0.2 → 9.1.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-NKQFB3HD.js → card-NQHAGTQQ.js} +3 -1
- package/dist/{card-6KL6L4GF.js → card-VVT3XBOI.js} +3 -1
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-76YORWFJ.js → chunk-3Y76PHEY.js} +62 -5
- package/dist/{chunk-QEDVPJKP.js → chunk-4DBSSFHG.js} +20 -16
- package/dist/chunk-4HLGFR72.js +155 -0
- package/dist/{chunk-ERT77HKY.js → chunk-4M6IAIVK.js} +2 -2
- package/dist/{chunk-FUGWPKXN.js → chunk-4UIUIHST.js} +1 -1
- package/dist/chunk-4XTYT4JW.js +147 -0
- package/dist/{chunk-2SOHHB2O.js → chunk-AR7Z3EQB.js} +34 -11
- package/dist/{chunk-Z4IDXMSP.js → chunk-D7NH6YLM.js} +6 -1
- package/dist/{chunk-SLZBE2I5.js → chunk-DBO2335D.js} +17 -12
- package/dist/{chunk-N3TXLBGK.js → chunk-GAZCZCAZ.js} +1 -1
- package/dist/{chunk-UQCQ2JCG.js → chunk-JJHQAZWE.js} +4 -4
- package/dist/{chunk-NLQCHO7N.js → chunk-JKD6QRUD.js} +3 -134
- package/dist/{chunk-74OZGLIT.js → chunk-LENX5NUW.js} +1 -1
- package/dist/{chunk-I3RRMAAD.js → chunk-PIO2FMX4.js} +5 -5
- package/dist/{chunk-77HAL2ZL.js → chunk-PYZGF5QH.js} +60 -3
- package/dist/chunk-Q5OFZ2JR.js +292 -0
- package/dist/{chunk-YJ3RGKPU.js → chunk-QG2LLVXP.js} +6 -2
- package/dist/chunk-QXRNW4OJ.js +35 -0
- package/dist/{chunk-UR3MISL2.js → chunk-UPNREF4L.js} +1 -1
- package/dist/{chunk-SMQDT7CT.js → chunk-UXL7DV7P.js} +7 -3
- package/dist/{chunk-PG3CLSAH.js → chunk-VJ2Q33AP.js} +3 -134
- package/dist/{chunk-DYJ7YGBM.js → chunk-WOVESOQ7.js} +237 -124
- package/dist/{chunk-BNS76U6K.js → chunk-XL5XD3IG.js} +23 -17
- package/dist/{chunk-FMKBCO2Q.js → chunk-ZYOMPJGG.js} +2 -2
- package/dist/cli/index.js +133 -59
- package/dist/{client-YB3IYO3S.js → client-XOSXFC7Q.js} +1 -0
- package/dist/{conduct-URYWMA5T.js → conduct-6C6JWZKZ.js} +13 -10
- package/dist/conduct-VSSHJHVH.js +29 -0
- package/dist/{conductor-mode-NRSVP2AU.js → conductor-mode-KKPSNN7V.js} +9 -6
- package/dist/{conductor-mode-2UFN6BUL.js → conductor-mode-NKHIZG4N.js} +17 -14
- package/dist/{config-IRWLG6IW.js → config-ZFWBAGDU.js} +1 -0
- package/dist/{credits-action-24EPLUHG.js → credits-action-N3WB4WSI.js} +5 -3
- package/dist/{daemon-A7DXZIQW.js → daemon-OM2K3U7J.js} +1 -0
- package/dist/{did-action-MQLDT4RF.js → did-action-3PNFYLX2.js} +1 -0
- package/dist/{execute-DNRNU3HM.js → execute-IEQ3RV7I.js} +6 -3
- package/dist/{execute-2Z3XIUHR.js → execute-QHP4KUV2.js} +10 -7
- package/dist/index.d.ts +412 -275
- package/dist/index.js +886 -282
- package/dist/{openclaw-setup-WA625DZA.js → openclaw-setup-PKGFB4IH.js} +19 -16
- package/dist/{openclaw-skills-76ZWXHFM.js → openclaw-skills-5VJDA6SX.js} +7 -6
- package/dist/{peers-F2EWUMVQ.js → peers-7BMU2775.js} +1 -0
- package/dist/{peers-CJ7T4RJO.js → peers-IOVCBWAI.js} +1 -0
- package/dist/{process-guard-QDBIOLY4.js → process-guard-6324CZDC.js} +1 -0
- package/dist/{publish-capability-FOCHYNYE.js → publish-capability-CHMPZ6W3.js} +4 -2
- package/dist/{reliability-metrics-JSOY3PNW.js → reliability-metrics-22JTZGB4.js} +1 -0
- package/dist/{reliability-metrics-KKUFFVB6.js → reliability-metrics-MIJ3TJWL.js} +1 -0
- package/dist/{request-KPKWBL5W.js → request-6TBVP3GR.js} +12 -9
- package/dist/request-log-2D253WML.js +17 -0
- package/dist/request-log-SIGTGOFA.js +16 -0
- package/dist/{scanner-GP4AOCW6.js → scanner-EFU6NBEJ.js} +1 -0
- package/dist/{schema-7BSSLZ4S.js → schema-FABVZKSI.js} +1 -0
- package/dist/{serve-skill-QSUIK3ZF.js → serve-skill-BRUHUDRA.js} +12 -9
- package/dist/{server-TGV2OPUM.js → server-N4BJW4TS.js} +15 -8
- package/dist/{service-coordinator-4JAUUNUL.js → service-coordinator-M2CBDEUQ.js} +539 -50
- package/dist/session-5AIRM7YF.js +144 -0
- package/dist/session-action-67J57636.js +131 -0
- package/dist/{skill-config-5O2VR546.js → skill-config-VYNF7BCY.js} +1 -0
- package/dist/skill-wrap-IAZHOYM4.js +365 -0
- package/dist/skills/agentbnb/bootstrap.js +564 -75
- package/dist/{store-S22F3I7G.js → store-A4YPEHDV.js} +3 -1
- package/dist/{vc-action-SUD7TMN2.js → vc-action-TSAIABUM.js} +1 -0
- package/dist/websocket-client-FCPZOE4S.js +9 -0
- package/dist/websocket-client-RT4KLJL4.js +8 -0
- package/dist/{writer-4QJ3U3WE.js → writer-V7JBWKKZ.js} +1 -0
- package/package.json +1 -1
- package/dist/chunk-3466S65P.js +0 -179
- package/dist/conduct-UAEEMVFD.js +0 -26
- package/dist/websocket-client-5CRE36Z5.js +0 -7
- package/dist/websocket-client-WHEHIYIZ.js +0 -6
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require,
|
|
3
|
+
createRequestLogTable,
|
|
4
|
+
insertRequestLog
|
|
5
|
+
} from "./chunk-4HLGFR72.js";
|
|
6
|
+
|
|
1
7
|
// src/types/index.ts
|
|
2
8
|
import { z } from "zod";
|
|
3
9
|
var IOSchemaSchema = z.object({
|
|
@@ -213,76 +219,6 @@ var AgentBnBError = class extends Error {
|
|
|
213
219
|
// src/registry/store.ts
|
|
214
220
|
import Database from "better-sqlite3";
|
|
215
221
|
|
|
216
|
-
// src/registry/request-log.ts
|
|
217
|
-
function createRequestLogTable(db) {
|
|
218
|
-
db.exec(`
|
|
219
|
-
CREATE TABLE IF NOT EXISTS request_log (
|
|
220
|
-
id TEXT PRIMARY KEY,
|
|
221
|
-
card_id TEXT NOT NULL,
|
|
222
|
-
card_name TEXT NOT NULL,
|
|
223
|
-
requester TEXT NOT NULL,
|
|
224
|
-
status TEXT NOT NULL CHECK(status IN ('success', 'failure', 'timeout')),
|
|
225
|
-
latency_ms INTEGER NOT NULL,
|
|
226
|
-
credits_charged INTEGER NOT NULL,
|
|
227
|
-
created_at TEXT NOT NULL
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
CREATE INDEX IF NOT EXISTS request_log_created_at_idx
|
|
231
|
-
ON request_log (created_at DESC);
|
|
232
|
-
`);
|
|
233
|
-
try {
|
|
234
|
-
db.exec("ALTER TABLE request_log ADD COLUMN skill_id TEXT");
|
|
235
|
-
} catch {
|
|
236
|
-
}
|
|
237
|
-
try {
|
|
238
|
-
db.exec("ALTER TABLE request_log ADD COLUMN action_type TEXT");
|
|
239
|
-
} catch {
|
|
240
|
-
}
|
|
241
|
-
try {
|
|
242
|
-
db.exec("ALTER TABLE request_log ADD COLUMN tier_invoked INTEGER");
|
|
243
|
-
} catch {
|
|
244
|
-
}
|
|
245
|
-
try {
|
|
246
|
-
db.exec("ALTER TABLE request_log ADD COLUMN failure_reason TEXT");
|
|
247
|
-
} catch {
|
|
248
|
-
}
|
|
249
|
-
try {
|
|
250
|
-
db.exec("ALTER TABLE request_log ADD COLUMN team_id TEXT");
|
|
251
|
-
} catch {
|
|
252
|
-
}
|
|
253
|
-
try {
|
|
254
|
-
db.exec("ALTER TABLE request_log ADD COLUMN role TEXT");
|
|
255
|
-
} catch {
|
|
256
|
-
}
|
|
257
|
-
try {
|
|
258
|
-
db.exec("ALTER TABLE request_log ADD COLUMN capability_type TEXT");
|
|
259
|
-
} catch {
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
function insertRequestLog(db, entry) {
|
|
263
|
-
const stmt = db.prepare(`
|
|
264
|
-
INSERT INTO request_log (id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked, failure_reason, team_id, role, capability_type)
|
|
265
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
266
|
-
`);
|
|
267
|
-
stmt.run(
|
|
268
|
-
entry.id,
|
|
269
|
-
entry.card_id,
|
|
270
|
-
entry.card_name,
|
|
271
|
-
entry.requester,
|
|
272
|
-
entry.status,
|
|
273
|
-
entry.latency_ms,
|
|
274
|
-
entry.credits_charged,
|
|
275
|
-
entry.created_at,
|
|
276
|
-
entry.skill_id ?? null,
|
|
277
|
-
entry.action_type ?? null,
|
|
278
|
-
entry.tier_invoked ?? null,
|
|
279
|
-
entry.failure_reason ?? null,
|
|
280
|
-
entry.team_id ?? null,
|
|
281
|
-
entry.role ?? null,
|
|
282
|
-
entry.capability_type ?? null
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
222
|
// src/feedback/store.ts
|
|
287
223
|
import { randomUUID } from "crypto";
|
|
288
224
|
function initFeedbackTable(db) {
|
|
@@ -858,28 +794,57 @@ function getCardsBySkillCapability(db, capabilityType) {
|
|
|
858
794
|
});
|
|
859
795
|
}
|
|
860
796
|
|
|
797
|
+
// src/core-config.ts
|
|
798
|
+
import { readFileSync } from "fs";
|
|
799
|
+
import { join } from "path";
|
|
800
|
+
var coreBasePath = null;
|
|
801
|
+
var coreResolved = false;
|
|
802
|
+
function resolveCoreBase() {
|
|
803
|
+
if (coreResolved) return coreBasePath;
|
|
804
|
+
coreResolved = true;
|
|
805
|
+
try {
|
|
806
|
+
const pkgPath = __require.resolve("@agentbnb/core/package.json");
|
|
807
|
+
coreBasePath = join(pkgPath, "..");
|
|
808
|
+
return coreBasePath;
|
|
809
|
+
} catch {
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
function loadCoreConfig(configName) {
|
|
814
|
+
const base = resolveCoreBase();
|
|
815
|
+
if (!base) return null;
|
|
816
|
+
try {
|
|
817
|
+
const filePath = join(base, "config", `${configName}.json`);
|
|
818
|
+
const raw = readFileSync(filePath, "utf8");
|
|
819
|
+
return JSON.parse(raw);
|
|
820
|
+
} catch {
|
|
821
|
+
return null;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
861
825
|
// src/feedback/reputation.ts
|
|
826
|
+
var coreReputation = loadCoreConfig("reputation");
|
|
862
827
|
var QUALITY_SCORES = {
|
|
863
|
-
excellent: 1,
|
|
864
|
-
good: 0.8,
|
|
865
|
-
acceptable: 0.6,
|
|
866
|
-
poor: 0.3,
|
|
867
|
-
failed: 0
|
|
828
|
+
excellent: coreReputation?.quality_scores?.["excellent"] ?? 1,
|
|
829
|
+
good: coreReputation?.quality_scores?.["good"] ?? 0.8,
|
|
830
|
+
acceptable: coreReputation?.quality_scores?.["acceptable"] ?? 0.6,
|
|
831
|
+
poor: coreReputation?.quality_scores?.["poor"] ?? 0.3,
|
|
832
|
+
failed: coreReputation?.quality_scores?.["failed"] ?? 0
|
|
868
833
|
};
|
|
869
834
|
var COST_VALUE_SCORES = {
|
|
870
|
-
great: 1,
|
|
871
|
-
fair: 0.6,
|
|
872
|
-
overpriced: 0.2
|
|
835
|
+
great: coreReputation?.cost_value_scores?.["great"] ?? 1,
|
|
836
|
+
fair: coreReputation?.cost_value_scores?.["fair"] ?? 0.6,
|
|
837
|
+
overpriced: coreReputation?.cost_value_scores?.["overpriced"] ?? 0.2
|
|
873
838
|
};
|
|
874
|
-
var DECAY_DAYS = 30;
|
|
839
|
+
var DECAY_DAYS = coreReputation?.decay_days ?? 30;
|
|
875
840
|
var WEIGHTS = {
|
|
876
|
-
rating: 0.4,
|
|
877
|
-
quality: 0.3,
|
|
878
|
-
would_reuse: 0.2,
|
|
879
|
-
cost_value: 0.1
|
|
841
|
+
rating: coreReputation?.weights?.["rating"] ?? 0.4,
|
|
842
|
+
quality: coreReputation?.weights?.["quality"] ?? 0.3,
|
|
843
|
+
would_reuse: coreReputation?.weights?.["would_reuse"] ?? 0.2,
|
|
844
|
+
cost_value: coreReputation?.weights?.["cost_value"] ?? 0.1
|
|
880
845
|
};
|
|
881
846
|
function computeReputation(feedbacks) {
|
|
882
|
-
if (feedbacks.length === 0) return 0.5;
|
|
847
|
+
if (feedbacks.length === 0) return coreReputation?.cold_start_score ?? 0.5;
|
|
883
848
|
const now = Date.now();
|
|
884
849
|
let weightedSum = 0;
|
|
885
850
|
let totalWeight = 0;
|
|
@@ -895,7 +860,7 @@ function computeReputation(feedbacks) {
|
|
|
895
860
|
weightedSum += recencyWeight * componentScore;
|
|
896
861
|
totalWeight += recencyWeight;
|
|
897
862
|
}
|
|
898
|
-
if (totalWeight === 0) return 0.5;
|
|
863
|
+
if (totalWeight === 0) return coreReputation?.cold_start_score ?? 0.5;
|
|
899
864
|
const raw = weightedSum / totalWeight;
|
|
900
865
|
return Math.max(0, Math.min(1, raw));
|
|
901
866
|
}
|
|
@@ -1372,7 +1337,8 @@ import { randomUUID as randomUUID5 } from "crypto";
|
|
|
1372
1337
|
|
|
1373
1338
|
// src/credit/escrow.ts
|
|
1374
1339
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
1375
|
-
var
|
|
1340
|
+
var coreEconomics = loadCoreConfig("economics");
|
|
1341
|
+
var NETWORK_FEE_RATE = coreEconomics?.network_fee_rate ?? 0.05;
|
|
1376
1342
|
var FINALIZABLE_ESCROW_STATUSES = /* @__PURE__ */ new Set([
|
|
1377
1343
|
"held",
|
|
1378
1344
|
"started",
|
|
@@ -1559,20 +1525,20 @@ function confirmEscrowDebit(db, escrowId) {
|
|
|
1559
1525
|
}
|
|
1560
1526
|
|
|
1561
1527
|
// src/cli/config.ts
|
|
1562
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
1528
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
1563
1529
|
import { homedir } from "os";
|
|
1564
|
-
import { join } from "path";
|
|
1530
|
+
import { join as join2 } from "path";
|
|
1565
1531
|
function getConfigDir() {
|
|
1566
|
-
return process.env["AGENTBNB_DIR"] ??
|
|
1532
|
+
return process.env["AGENTBNB_DIR"] ?? join2(homedir(), ".agentbnb");
|
|
1567
1533
|
}
|
|
1568
1534
|
function getConfigPath() {
|
|
1569
|
-
return
|
|
1535
|
+
return join2(getConfigDir(), "config.json");
|
|
1570
1536
|
}
|
|
1571
1537
|
function loadConfig() {
|
|
1572
1538
|
const configPath = getConfigPath();
|
|
1573
1539
|
if (!existsSync(configPath)) return null;
|
|
1574
1540
|
try {
|
|
1575
|
-
const raw =
|
|
1541
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
1576
1542
|
return JSON.parse(raw);
|
|
1577
1543
|
} catch {
|
|
1578
1544
|
return null;
|
|
@@ -1582,13 +1548,13 @@ function loadConfig() {
|
|
|
1582
1548
|
// src/identity/identity.ts
|
|
1583
1549
|
import { z as z2 } from "zod";
|
|
1584
1550
|
import { createHash, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
|
|
1585
|
-
import { readFileSync as
|
|
1586
|
-
import { join as
|
|
1551
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
1552
|
+
import { join as join4 } from "path";
|
|
1587
1553
|
|
|
1588
1554
|
// src/credit/signing.ts
|
|
1589
1555
|
import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
|
|
1590
|
-
import { writeFileSync as writeFileSync2, readFileSync as
|
|
1591
|
-
import { join as
|
|
1556
|
+
import { writeFileSync as writeFileSync2, readFileSync as readFileSync3, existsSync as existsSync2, chmodSync } from "fs";
|
|
1557
|
+
import { join as join3 } from "path";
|
|
1592
1558
|
function generateKeyPair() {
|
|
1593
1559
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
|
|
1594
1560
|
publicKeyEncoding: { type: "spki", format: "der" },
|
|
@@ -1600,21 +1566,21 @@ function generateKeyPair() {
|
|
|
1600
1566
|
};
|
|
1601
1567
|
}
|
|
1602
1568
|
function saveKeyPair(configDir, keys) {
|
|
1603
|
-
const privatePath =
|
|
1604
|
-
const publicPath =
|
|
1569
|
+
const privatePath = join3(configDir, "private.key");
|
|
1570
|
+
const publicPath = join3(configDir, "public.key");
|
|
1605
1571
|
writeFileSync2(privatePath, keys.privateKey);
|
|
1606
1572
|
chmodSync(privatePath, 384);
|
|
1607
1573
|
writeFileSync2(publicPath, keys.publicKey);
|
|
1608
1574
|
}
|
|
1609
1575
|
function loadKeyPair(configDir) {
|
|
1610
|
-
const privatePath =
|
|
1611
|
-
const publicPath =
|
|
1576
|
+
const privatePath = join3(configDir, "private.key");
|
|
1577
|
+
const publicPath = join3(configDir, "public.key");
|
|
1612
1578
|
if (!existsSync2(privatePath) || !existsSync2(publicPath)) {
|
|
1613
1579
|
throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
|
|
1614
1580
|
}
|
|
1615
1581
|
return {
|
|
1616
|
-
publicKey:
|
|
1617
|
-
privateKey:
|
|
1582
|
+
publicKey: readFileSync3(publicPath),
|
|
1583
|
+
privateKey: readFileSync3(privatePath)
|
|
1618
1584
|
};
|
|
1619
1585
|
}
|
|
1620
1586
|
function canonicalJson(data) {
|
|
@@ -1738,10 +1704,10 @@ function createIdentity(configDir, owner) {
|
|
|
1738
1704
|
return identity;
|
|
1739
1705
|
}
|
|
1740
1706
|
function loadIdentity(configDir) {
|
|
1741
|
-
const filePath =
|
|
1707
|
+
const filePath = join4(configDir, IDENTITY_FILENAME);
|
|
1742
1708
|
if (!existsSync3(filePath)) return null;
|
|
1743
1709
|
try {
|
|
1744
|
-
const raw =
|
|
1710
|
+
const raw = readFileSync4(filePath, "utf-8");
|
|
1745
1711
|
return AgentIdentitySchema.parse(JSON.parse(raw));
|
|
1746
1712
|
} catch {
|
|
1747
1713
|
return null;
|
|
@@ -1751,16 +1717,16 @@ function saveIdentity(configDir, identity) {
|
|
|
1751
1717
|
if (!existsSync3(configDir)) {
|
|
1752
1718
|
mkdirSync2(configDir, { recursive: true });
|
|
1753
1719
|
}
|
|
1754
|
-
const filePath =
|
|
1720
|
+
const filePath = join4(configDir, IDENTITY_FILENAME);
|
|
1755
1721
|
writeFileSync3(filePath, JSON.stringify(identity, null, 2), "utf-8");
|
|
1756
1722
|
}
|
|
1757
1723
|
function loadOrRepairIdentity(configDir, ownerHint) {
|
|
1758
1724
|
if (!existsSync3(configDir)) {
|
|
1759
1725
|
mkdirSync2(configDir, { recursive: true });
|
|
1760
1726
|
}
|
|
1761
|
-
const identityPath =
|
|
1762
|
-
const privateKeyPath =
|
|
1763
|
-
const publicKeyPath =
|
|
1727
|
+
const identityPath = join4(configDir, IDENTITY_FILENAME);
|
|
1728
|
+
const privateKeyPath = join4(configDir, PRIVATE_KEY_FILENAME);
|
|
1729
|
+
const publicKeyPath = join4(configDir, PUBLIC_KEY_FILENAME);
|
|
1764
1730
|
const hasIdentity = existsSync3(identityPath);
|
|
1765
1731
|
const hasPrivateKey = existsSync3(privateKeyPath);
|
|
1766
1732
|
const hasPublicKey = existsSync3(publicKeyPath);
|
|
@@ -2325,6 +2291,26 @@ async function notifyTelegramSkillFailed(opts) {
|
|
|
2325
2291
|
body: JSON.stringify({ chat_id: chatId, text })
|
|
2326
2292
|
});
|
|
2327
2293
|
}
|
|
2294
|
+
async function notifyTelegramSkillReceived(opts) {
|
|
2295
|
+
const cfg = loadConfig();
|
|
2296
|
+
if (cfg?.provider_gate !== "notify") return;
|
|
2297
|
+
const token = cfg.telegram_bot_token ?? process.env["TELEGRAM_BOT_TOKEN"];
|
|
2298
|
+
const chatId = cfg.telegram_chat_id ?? process.env["TELEGRAM_CHAT_ID"];
|
|
2299
|
+
if (!token || !chatId) return;
|
|
2300
|
+
const skillLabel = opts.skillId ? `${opts.skillName} (${opts.skillId})` : opts.skillName;
|
|
2301
|
+
const text = [
|
|
2302
|
+
"\u{1F4E5} [AgentBnB] Incoming rental request",
|
|
2303
|
+
`Skill: ${skillLabel}`,
|
|
2304
|
+
`Requester: ${opts.requester}`,
|
|
2305
|
+
`Cost: ${opts.cost} credits`,
|
|
2306
|
+
`Status: Executing...`
|
|
2307
|
+
].join("\n");
|
|
2308
|
+
await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
|
|
2309
|
+
method: "POST",
|
|
2310
|
+
headers: { "Content-Type": "application/json" },
|
|
2311
|
+
body: JSON.stringify({ chat_id: chatId, text })
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2328
2314
|
async function executeCapabilityRequest(opts) {
|
|
2329
2315
|
const {
|
|
2330
2316
|
registryDb,
|
|
@@ -2416,6 +2402,41 @@ async function executeCapabilityRequest(opts) {
|
|
|
2416
2402
|
return { success: false, error: { code: -32603, message: msg } };
|
|
2417
2403
|
}
|
|
2418
2404
|
}
|
|
2405
|
+
const providerCfg = loadConfig();
|
|
2406
|
+
const providerWhitelist = providerCfg?.provider_whitelist ?? [];
|
|
2407
|
+
const isWhitelisted = providerWhitelist.includes(requester);
|
|
2408
|
+
if (providerCfg?.provider_accepting === false && !isWhitelisted) {
|
|
2409
|
+
if (escrowId) releaseEscrow(creditDb, escrowId);
|
|
2410
|
+
return { success: false, error: { code: -32098, message: "Provider is not accepting requests" } };
|
|
2411
|
+
}
|
|
2412
|
+
if (!isWhitelisted) {
|
|
2413
|
+
const blacklist = providerCfg?.provider_blacklist ?? [];
|
|
2414
|
+
if (blacklist.includes(requester)) {
|
|
2415
|
+
if (escrowId) releaseEscrow(creditDb, escrowId);
|
|
2416
|
+
return { success: false, error: { code: -32097, message: "Requester is blocked by provider" } };
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
if (!isWhitelisted) {
|
|
2420
|
+
const dailyLimit = providerCfg?.provider_daily_limit ?? 0;
|
|
2421
|
+
if (dailyLimit > 0) {
|
|
2422
|
+
const { countTodayExecutions } = await import("./request-log-SIGTGOFA.js");
|
|
2423
|
+
const todayCount = countTodayExecutions(registryDb);
|
|
2424
|
+
if (todayCount >= dailyLimit) {
|
|
2425
|
+
if (escrowId) releaseEscrow(creditDb, escrowId);
|
|
2426
|
+
return {
|
|
2427
|
+
success: false,
|
|
2428
|
+
error: { code: -32099, message: `Provider daily execution limit reached (${dailyLimit}/day)` }
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
notifyTelegramSkillReceived({
|
|
2434
|
+
skillName: cardName,
|
|
2435
|
+
skillId: resolvedSkillId ?? null,
|
|
2436
|
+
requester,
|
|
2437
|
+
cost: creditsNeeded
|
|
2438
|
+
}).catch(() => {
|
|
2439
|
+
});
|
|
2419
2440
|
const startMs = Date.now();
|
|
2420
2441
|
const handleFailure = (status, latencyMs, message, failureReason = "bad_execution") => {
|
|
2421
2442
|
if (escrowId) releaseEscrow(creditDb, escrowId);
|
|
@@ -3590,9 +3611,42 @@ var PipelineExecutor = class {
|
|
|
3590
3611
|
};
|
|
3591
3612
|
|
|
3592
3613
|
// src/skills/openclaw-bridge.ts
|
|
3593
|
-
import {
|
|
3614
|
+
import { spawnSync } from "child_process";
|
|
3594
3615
|
var DEFAULT_BASE_URL = "http://localhost:3000";
|
|
3595
3616
|
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
3617
|
+
function isOpenClawJsonResponse(value) {
|
|
3618
|
+
return typeof value === "object" && value !== null && "payloads" in value && Array.isArray(value.payloads) && "meta" in value;
|
|
3619
|
+
}
|
|
3620
|
+
function parseOpenClawResponse(raw) {
|
|
3621
|
+
if (!isOpenClawJsonResponse(raw)) {
|
|
3622
|
+
return raw;
|
|
3623
|
+
}
|
|
3624
|
+
const { payloads, meta } = raw;
|
|
3625
|
+
const texts = payloads.map((p) => p.text).filter((t) => typeof t === "string" && t.length > 0);
|
|
3626
|
+
const mediaUrls = payloads.map((p) => p.mediaUrl).filter((u) => typeof u === "string" && u.length > 0);
|
|
3627
|
+
const openclawMeta = {
|
|
3628
|
+
duration_ms: meta.durationMs,
|
|
3629
|
+
model: meta.agentMeta?.model,
|
|
3630
|
+
provider: meta.agentMeta?.provider
|
|
3631
|
+
};
|
|
3632
|
+
if (texts.length === 0) {
|
|
3633
|
+
return { text: "", media_urls: mediaUrls, _openclaw_meta: openclawMeta };
|
|
3634
|
+
}
|
|
3635
|
+
const lastText = texts[texts.length - 1];
|
|
3636
|
+
try {
|
|
3637
|
+
const structured = JSON.parse(lastText);
|
|
3638
|
+
if (typeof structured === "object" && structured !== null) {
|
|
3639
|
+
return { ...structured, _openclaw_meta: openclawMeta };
|
|
3640
|
+
}
|
|
3641
|
+
return { result: structured, _openclaw_meta: openclawMeta };
|
|
3642
|
+
} catch {
|
|
3643
|
+
return {
|
|
3644
|
+
text: texts.join("\n\n"),
|
|
3645
|
+
media_urls: mediaUrls.length > 0 ? mediaUrls : void 0,
|
|
3646
|
+
_openclaw_meta: openclawMeta
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3596
3650
|
function buildPayload(config, params) {
|
|
3597
3651
|
return {
|
|
3598
3652
|
task: config.name,
|
|
@@ -3659,7 +3713,7 @@ Do NOT include explanations, markdown formatting, or code blocks.
|
|
|
3659
3713
|
The JSON should contain the output fields specified in your SKILL.md.
|
|
3660
3714
|
If you cannot complete the task, return: {"error": "reason"}`;
|
|
3661
3715
|
try {
|
|
3662
|
-
const
|
|
3716
|
+
const proc = spawnSync("openclaw", [
|
|
3663
3717
|
"agent",
|
|
3664
3718
|
"--agent",
|
|
3665
3719
|
config.agent_name,
|
|
@@ -3668,21 +3722,37 @@ If you cannot complete the task, return: {"error": "reason"}`;
|
|
|
3668
3722
|
"--json",
|
|
3669
3723
|
"--local"
|
|
3670
3724
|
], {
|
|
3671
|
-
timeout: timeoutMs
|
|
3725
|
+
timeout: timeoutMs,
|
|
3726
|
+
maxBuffer: 10 * 1024 * 1024
|
|
3727
|
+
// 10 MB
|
|
3672
3728
|
});
|
|
3673
|
-
|
|
3729
|
+
if (proc.error) {
|
|
3730
|
+
return { success: false, error: proc.error.message };
|
|
3731
|
+
}
|
|
3732
|
+
const stderrText = proc.stderr?.toString() ?? "";
|
|
3733
|
+
const stdoutText = proc.stdout?.toString() ?? "";
|
|
3734
|
+
const text = (stderrText || stdoutText).trim();
|
|
3735
|
+
if (!text) {
|
|
3736
|
+
return {
|
|
3737
|
+
success: false,
|
|
3738
|
+
error: `OpenClaw process channel returned empty output (exit code ${proc.status})`
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3741
|
+
const jsonStart = text.lastIndexOf("\n{");
|
|
3742
|
+
const jsonText = jsonStart >= 0 ? text.slice(jsonStart + 1) : text;
|
|
3674
3743
|
try {
|
|
3675
|
-
const parsed = JSON.parse(
|
|
3676
|
-
|
|
3744
|
+
const parsed = JSON.parse(jsonText);
|
|
3745
|
+
const result = parseOpenClawResponse(parsed);
|
|
3746
|
+
return { success: true, result };
|
|
3677
3747
|
} catch {
|
|
3678
3748
|
return {
|
|
3679
3749
|
success: false,
|
|
3680
|
-
error: `OpenClaw process channel returned invalid JSON: ${
|
|
3750
|
+
error: `OpenClaw process channel returned invalid JSON: ${jsonText.slice(0, 500)}`
|
|
3681
3751
|
};
|
|
3682
3752
|
}
|
|
3683
3753
|
} catch (err) {
|
|
3684
|
-
const
|
|
3685
|
-
return { success: false, error:
|
|
3754
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3755
|
+
return { success: false, error: errMsg };
|
|
3686
3756
|
}
|
|
3687
3757
|
}
|
|
3688
3758
|
async function executeTelegram(config, payload) {
|
|
@@ -4446,163 +4516,261 @@ import WebSocket from "ws";
|
|
|
4446
4516
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
4447
4517
|
|
|
4448
4518
|
// src/relay/types.ts
|
|
4519
|
+
import { z as z5 } from "zod";
|
|
4520
|
+
|
|
4521
|
+
// src/session/session-types.ts
|
|
4449
4522
|
import { z as z4 } from "zod";
|
|
4450
|
-
var
|
|
4451
|
-
|
|
4452
|
-
|
|
4523
|
+
var DEFAULT_SESSION_CONFIG = {
|
|
4524
|
+
pricing: {
|
|
4525
|
+
default_model: "per_message",
|
|
4526
|
+
per_message_base_rate: 2,
|
|
4527
|
+
per_minute_base_rate: 1,
|
|
4528
|
+
per_session_flat_rate: 10,
|
|
4529
|
+
max_messages_per_session: 50,
|
|
4530
|
+
max_minutes_per_session: 30
|
|
4531
|
+
},
|
|
4532
|
+
timeouts: {
|
|
4533
|
+
idle_timeout_ms: 12e4,
|
|
4534
|
+
max_session_duration_ms: 18e5,
|
|
4535
|
+
message_timeout_ms: 9e4
|
|
4536
|
+
},
|
|
4537
|
+
abuse: {
|
|
4538
|
+
max_concurrent_sessions_per_agent: 5,
|
|
4539
|
+
max_sessions_per_hour: 20,
|
|
4540
|
+
min_message_interval_ms: 1e3
|
|
4541
|
+
},
|
|
4542
|
+
quality: {
|
|
4543
|
+
min_provider_reputation_for_session: 0.5,
|
|
4544
|
+
auto_refund_on_timeout: true,
|
|
4545
|
+
partial_refund_ratio: 0.5
|
|
4546
|
+
}
|
|
4547
|
+
};
|
|
4548
|
+
function loadSessionConfig() {
|
|
4549
|
+
const core = loadCoreConfig("session");
|
|
4550
|
+
if (!core) return DEFAULT_SESSION_CONFIG;
|
|
4551
|
+
return {
|
|
4552
|
+
pricing: { ...DEFAULT_SESSION_CONFIG.pricing, ...core.pricing },
|
|
4553
|
+
timeouts: { ...DEFAULT_SESSION_CONFIG.timeouts, ...core.timeouts },
|
|
4554
|
+
abuse: { ...DEFAULT_SESSION_CONFIG.abuse, ...core.abuse },
|
|
4555
|
+
quality: { ...DEFAULT_SESSION_CONFIG.quality, ...core.quality }
|
|
4556
|
+
};
|
|
4557
|
+
}
|
|
4558
|
+
var SessionPricingModelSchema = z4.enum(["per_message", "per_minute", "per_session"]);
|
|
4559
|
+
var SessionOpenMessageSchema = z4.object({
|
|
4560
|
+
type: z4.literal("session_open"),
|
|
4561
|
+
session_id: z4.string().uuid(),
|
|
4562
|
+
requester_id: z4.string().min(1),
|
|
4563
|
+
provider_id: z4.string().min(1),
|
|
4564
|
+
card_id: z4.string().min(1),
|
|
4565
|
+
skill_id: z4.string().min(1),
|
|
4566
|
+
budget: z4.number().positive(),
|
|
4567
|
+
pricing_model: SessionPricingModelSchema.default("per_message"),
|
|
4568
|
+
initial_message: z4.string().min(1),
|
|
4569
|
+
ucan_token: z4.string().optional()
|
|
4570
|
+
});
|
|
4571
|
+
var SessionAckMessageSchema = z4.object({
|
|
4572
|
+
type: z4.literal("session_ack"),
|
|
4573
|
+
session_id: z4.string(),
|
|
4574
|
+
escrow_id: z4.string(),
|
|
4575
|
+
status: z4.literal("open")
|
|
4576
|
+
});
|
|
4577
|
+
var SessionMessageMessageSchema = z4.object({
|
|
4578
|
+
type: z4.literal("session_message"),
|
|
4579
|
+
session_id: z4.string().uuid(),
|
|
4580
|
+
sender: z4.enum(["requester", "provider"]),
|
|
4581
|
+
content: z4.string().min(1),
|
|
4582
|
+
metadata: z4.object({
|
|
4583
|
+
model: z4.string().optional(),
|
|
4584
|
+
latency_ms: z4.number().optional(),
|
|
4585
|
+
tokens_used: z4.number().optional()
|
|
4586
|
+
}).optional()
|
|
4587
|
+
});
|
|
4588
|
+
var SessionEndMessageSchema = z4.object({
|
|
4589
|
+
type: z4.literal("session_end"),
|
|
4590
|
+
session_id: z4.string().uuid(),
|
|
4591
|
+
reason: z4.enum(["completed", "timeout", "budget_exhausted", "error", "cancelled"]).default("completed"),
|
|
4592
|
+
summary: z4.string().optional()
|
|
4593
|
+
});
|
|
4594
|
+
var SessionSettledMessageSchema = z4.object({
|
|
4595
|
+
type: z4.literal("session_settled"),
|
|
4596
|
+
session_id: z4.string(),
|
|
4597
|
+
total_cost: z4.number(),
|
|
4598
|
+
messages_count: z4.number(),
|
|
4599
|
+
duration_seconds: z4.number(),
|
|
4600
|
+
refunded: z4.number()
|
|
4601
|
+
});
|
|
4602
|
+
var SessionErrorMessageSchema = z4.object({
|
|
4603
|
+
type: z4.literal("session_error"),
|
|
4604
|
+
session_id: z4.string(),
|
|
4605
|
+
code: z4.string(),
|
|
4606
|
+
message: z4.string()
|
|
4607
|
+
});
|
|
4608
|
+
var SESSION_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
4609
|
+
"session_open",
|
|
4610
|
+
"session_ack",
|
|
4611
|
+
"session_message",
|
|
4612
|
+
"session_end",
|
|
4613
|
+
"session_settled",
|
|
4614
|
+
"session_error"
|
|
4615
|
+
]);
|
|
4616
|
+
|
|
4617
|
+
// src/relay/types.ts
|
|
4618
|
+
var RegisterMessageSchema = z5.object({
|
|
4619
|
+
type: z5.literal("register"),
|
|
4620
|
+
owner: z5.string().min(1),
|
|
4453
4621
|
/** V8: Cryptographic agent identity. When present, used as the canonical key. */
|
|
4454
|
-
agent_id:
|
|
4622
|
+
agent_id: z5.string().optional(),
|
|
4455
4623
|
/** V8 Phase 3: Server identifier for multi-agent delegation. */
|
|
4456
|
-
server_id:
|
|
4457
|
-
token:
|
|
4458
|
-
card:
|
|
4624
|
+
server_id: z5.string().optional(),
|
|
4625
|
+
token: z5.string().min(1),
|
|
4626
|
+
card: z5.record(z5.unknown()),
|
|
4459
4627
|
// CapabilityCard (validated separately)
|
|
4460
|
-
cards:
|
|
4628
|
+
cards: z5.array(z5.record(z5.unknown())).optional(),
|
|
4461
4629
|
// Additional cards (e.g., conductor card)
|
|
4462
4630
|
/** V8 Phase 3: Additional agents served by this server (multi-agent registration). */
|
|
4463
|
-
agents:
|
|
4464
|
-
agent_id:
|
|
4465
|
-
display_name:
|
|
4466
|
-
cards:
|
|
4467
|
-
delegation_token:
|
|
4631
|
+
agents: z5.array(z5.object({
|
|
4632
|
+
agent_id: z5.string().min(1),
|
|
4633
|
+
display_name: z5.string().min(1),
|
|
4634
|
+
cards: z5.array(z5.record(z5.unknown())),
|
|
4635
|
+
delegation_token: z5.record(z5.unknown()).optional()
|
|
4468
4636
|
})).optional()
|
|
4469
4637
|
});
|
|
4470
|
-
var RegisteredMessageSchema =
|
|
4471
|
-
type:
|
|
4472
|
-
agent_id:
|
|
4638
|
+
var RegisteredMessageSchema = z5.object({
|
|
4639
|
+
type: z5.literal("registered"),
|
|
4640
|
+
agent_id: z5.string()
|
|
4473
4641
|
});
|
|
4474
|
-
var RelayRequestMessageSchema =
|
|
4475
|
-
type:
|
|
4476
|
-
id:
|
|
4477
|
-
target_owner:
|
|
4642
|
+
var RelayRequestMessageSchema = z5.object({
|
|
4643
|
+
type: z5.literal("relay_request"),
|
|
4644
|
+
id: z5.string().uuid(),
|
|
4645
|
+
target_owner: z5.string().min(1),
|
|
4478
4646
|
/** V8: Target agent's cryptographic identity. Preferred over target_owner. */
|
|
4479
|
-
target_agent_id:
|
|
4480
|
-
card_id:
|
|
4481
|
-
skill_id:
|
|
4482
|
-
params:
|
|
4483
|
-
requester:
|
|
4484
|
-
escrow_receipt:
|
|
4647
|
+
target_agent_id: z5.string().optional(),
|
|
4648
|
+
card_id: z5.string(),
|
|
4649
|
+
skill_id: z5.string().optional(),
|
|
4650
|
+
params: z5.record(z5.unknown()).default({}),
|
|
4651
|
+
requester: z5.string().optional(),
|
|
4652
|
+
escrow_receipt: z5.record(z5.unknown()).optional(),
|
|
4485
4653
|
/** Optional UCAN token for capability delegation. */
|
|
4486
|
-
ucan_token:
|
|
4654
|
+
ucan_token: z5.string().optional()
|
|
4487
4655
|
});
|
|
4488
|
-
var IncomingRequestMessageSchema =
|
|
4489
|
-
type:
|
|
4490
|
-
id:
|
|
4491
|
-
from_owner:
|
|
4492
|
-
card_id:
|
|
4493
|
-
skill_id:
|
|
4494
|
-
params:
|
|
4495
|
-
requester:
|
|
4496
|
-
escrow_receipt:
|
|
4656
|
+
var IncomingRequestMessageSchema = z5.object({
|
|
4657
|
+
type: z5.literal("incoming_request"),
|
|
4658
|
+
id: z5.string().uuid(),
|
|
4659
|
+
from_owner: z5.string().min(1),
|
|
4660
|
+
card_id: z5.string(),
|
|
4661
|
+
skill_id: z5.string().optional(),
|
|
4662
|
+
params: z5.record(z5.unknown()).default({}),
|
|
4663
|
+
requester: z5.string().optional(),
|
|
4664
|
+
escrow_receipt: z5.record(z5.unknown()).optional(),
|
|
4497
4665
|
/** Optional UCAN token for capability delegation. */
|
|
4498
|
-
ucan_token:
|
|
4666
|
+
ucan_token: z5.string().optional()
|
|
4499
4667
|
});
|
|
4500
|
-
var RelayResponseMessageSchema =
|
|
4501
|
-
type:
|
|
4502
|
-
id:
|
|
4503
|
-
result:
|
|
4504
|
-
error:
|
|
4505
|
-
code:
|
|
4506
|
-
message:
|
|
4668
|
+
var RelayResponseMessageSchema = z5.object({
|
|
4669
|
+
type: z5.literal("relay_response"),
|
|
4670
|
+
id: z5.string().uuid(),
|
|
4671
|
+
result: z5.unknown().optional(),
|
|
4672
|
+
error: z5.object({
|
|
4673
|
+
code: z5.number(),
|
|
4674
|
+
message: z5.string()
|
|
4507
4675
|
}).optional()
|
|
4508
4676
|
});
|
|
4509
|
-
var ResponseMessageSchema =
|
|
4510
|
-
type:
|
|
4511
|
-
id:
|
|
4512
|
-
result:
|
|
4513
|
-
error:
|
|
4514
|
-
code:
|
|
4515
|
-
message:
|
|
4677
|
+
var ResponseMessageSchema = z5.object({
|
|
4678
|
+
type: z5.literal("response"),
|
|
4679
|
+
id: z5.string().uuid(),
|
|
4680
|
+
result: z5.unknown().optional(),
|
|
4681
|
+
error: z5.object({
|
|
4682
|
+
code: z5.number(),
|
|
4683
|
+
message: z5.string()
|
|
4516
4684
|
}).optional()
|
|
4517
4685
|
});
|
|
4518
|
-
var ErrorMessageSchema =
|
|
4519
|
-
type:
|
|
4520
|
-
code:
|
|
4521
|
-
message:
|
|
4522
|
-
request_id:
|
|
4686
|
+
var ErrorMessageSchema = z5.object({
|
|
4687
|
+
type: z5.literal("error"),
|
|
4688
|
+
code: z5.string(),
|
|
4689
|
+
message: z5.string(),
|
|
4690
|
+
request_id: z5.string().optional()
|
|
4523
4691
|
});
|
|
4524
|
-
var RelayProgressMessageSchema =
|
|
4525
|
-
type:
|
|
4526
|
-
id:
|
|
4692
|
+
var RelayProgressMessageSchema = z5.object({
|
|
4693
|
+
type: z5.literal("relay_progress"),
|
|
4694
|
+
id: z5.string().uuid(),
|
|
4527
4695
|
// request ID this progress relates to
|
|
4528
|
-
progress:
|
|
4696
|
+
progress: z5.number().min(0).max(100).optional(),
|
|
4529
4697
|
// optional percentage
|
|
4530
|
-
message:
|
|
4698
|
+
message: z5.string().optional()
|
|
4531
4699
|
// optional status message
|
|
4532
4700
|
});
|
|
4533
|
-
var RelayStartedMessageSchema =
|
|
4534
|
-
type:
|
|
4535
|
-
id:
|
|
4536
|
-
message:
|
|
4701
|
+
var RelayStartedMessageSchema = z5.object({
|
|
4702
|
+
type: z5.literal("relay_started"),
|
|
4703
|
+
id: z5.string().uuid(),
|
|
4704
|
+
message: z5.string().optional()
|
|
4537
4705
|
});
|
|
4538
|
-
var HeartbeatMessageSchema =
|
|
4539
|
-
type:
|
|
4540
|
-
owner:
|
|
4541
|
-
capacity:
|
|
4542
|
-
current_load:
|
|
4543
|
-
max_concurrent:
|
|
4544
|
-
queue_depth:
|
|
4706
|
+
var HeartbeatMessageSchema = z5.object({
|
|
4707
|
+
type: z5.literal("heartbeat"),
|
|
4708
|
+
owner: z5.string().min(1),
|
|
4709
|
+
capacity: z5.object({
|
|
4710
|
+
current_load: z5.number(),
|
|
4711
|
+
max_concurrent: z5.number(),
|
|
4712
|
+
queue_depth: z5.number()
|
|
4545
4713
|
}),
|
|
4546
|
-
self_summary:
|
|
4547
|
-
capabilities:
|
|
4548
|
-
success_rate:
|
|
4549
|
-
credit_balance:
|
|
4550
|
-
total_completed:
|
|
4551
|
-
provider_number:
|
|
4552
|
-
reliability:
|
|
4553
|
-
current_streak:
|
|
4554
|
-
repeat_hire_rate:
|
|
4555
|
-
avg_feedback:
|
|
4714
|
+
self_summary: z5.object({
|
|
4715
|
+
capabilities: z5.array(z5.string()),
|
|
4716
|
+
success_rate: z5.number(),
|
|
4717
|
+
credit_balance: z5.number(),
|
|
4718
|
+
total_completed: z5.number(),
|
|
4719
|
+
provider_number: z5.number(),
|
|
4720
|
+
reliability: z5.object({
|
|
4721
|
+
current_streak: z5.number(),
|
|
4722
|
+
repeat_hire_rate: z5.number(),
|
|
4723
|
+
avg_feedback: z5.number()
|
|
4556
4724
|
})
|
|
4557
4725
|
})
|
|
4558
4726
|
});
|
|
4559
|
-
var EscrowHoldMessageSchema =
|
|
4560
|
-
type:
|
|
4561
|
-
consumer_agent_id:
|
|
4562
|
-
provider_agent_id:
|
|
4563
|
-
skill_id:
|
|
4564
|
-
amount:
|
|
4565
|
-
request_id:
|
|
4566
|
-
signature:
|
|
4567
|
-
public_key:
|
|
4727
|
+
var EscrowHoldMessageSchema = z5.object({
|
|
4728
|
+
type: z5.literal("escrow_hold"),
|
|
4729
|
+
consumer_agent_id: z5.string().min(1),
|
|
4730
|
+
provider_agent_id: z5.string().min(1),
|
|
4731
|
+
skill_id: z5.string().min(1),
|
|
4732
|
+
amount: z5.number().positive(),
|
|
4733
|
+
request_id: z5.string().uuid(),
|
|
4734
|
+
signature: z5.string().optional(),
|
|
4735
|
+
public_key: z5.string().optional()
|
|
4568
4736
|
});
|
|
4569
|
-
var EscrowHoldConfirmedMessageSchema =
|
|
4570
|
-
type:
|
|
4571
|
-
request_id:
|
|
4572
|
-
escrow_id:
|
|
4573
|
-
hold_amount:
|
|
4574
|
-
consumer_remaining:
|
|
4737
|
+
var EscrowHoldConfirmedMessageSchema = z5.object({
|
|
4738
|
+
type: z5.literal("escrow_hold_confirmed"),
|
|
4739
|
+
request_id: z5.string(),
|
|
4740
|
+
escrow_id: z5.string(),
|
|
4741
|
+
hold_amount: z5.number(),
|
|
4742
|
+
consumer_remaining: z5.number()
|
|
4575
4743
|
});
|
|
4576
|
-
var EscrowSettleMessageSchema =
|
|
4577
|
-
type:
|
|
4578
|
-
escrow_id:
|
|
4579
|
-
request_id:
|
|
4580
|
-
success:
|
|
4581
|
-
failure_reason:
|
|
4582
|
-
result_hash:
|
|
4583
|
-
signature:
|
|
4584
|
-
public_key:
|
|
4585
|
-
consumer_agent_id:
|
|
4744
|
+
var EscrowSettleMessageSchema = z5.object({
|
|
4745
|
+
type: z5.literal("escrow_settle"),
|
|
4746
|
+
escrow_id: z5.string().min(1),
|
|
4747
|
+
request_id: z5.string().uuid(),
|
|
4748
|
+
success: z5.boolean(),
|
|
4749
|
+
failure_reason: z5.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
|
|
4750
|
+
result_hash: z5.string().optional(),
|
|
4751
|
+
signature: z5.string().optional(),
|
|
4752
|
+
public_key: z5.string().optional(),
|
|
4753
|
+
consumer_agent_id: z5.string().optional()
|
|
4586
4754
|
});
|
|
4587
|
-
var EscrowSettledMessageSchema =
|
|
4588
|
-
type:
|
|
4589
|
-
escrow_id:
|
|
4590
|
-
request_id:
|
|
4591
|
-
provider_earned:
|
|
4592
|
-
network_fee:
|
|
4593
|
-
consumer_remaining:
|
|
4594
|
-
provider_balance:
|
|
4755
|
+
var EscrowSettledMessageSchema = z5.object({
|
|
4756
|
+
type: z5.literal("escrow_settled"),
|
|
4757
|
+
escrow_id: z5.string(),
|
|
4758
|
+
request_id: z5.string(),
|
|
4759
|
+
provider_earned: z5.number(),
|
|
4760
|
+
network_fee: z5.number(),
|
|
4761
|
+
consumer_remaining: z5.number(),
|
|
4762
|
+
provider_balance: z5.number()
|
|
4595
4763
|
});
|
|
4596
|
-
var BalanceSyncMessageSchema =
|
|
4597
|
-
type:
|
|
4598
|
-
agent_id:
|
|
4764
|
+
var BalanceSyncMessageSchema = z5.object({
|
|
4765
|
+
type: z5.literal("balance_sync"),
|
|
4766
|
+
agent_id: z5.string().min(1)
|
|
4599
4767
|
});
|
|
4600
|
-
var BalanceSyncResponseMessageSchema =
|
|
4601
|
-
type:
|
|
4602
|
-
agent_id:
|
|
4603
|
-
balance:
|
|
4768
|
+
var BalanceSyncResponseMessageSchema = z5.object({
|
|
4769
|
+
type: z5.literal("balance_sync_response"),
|
|
4770
|
+
agent_id: z5.string(),
|
|
4771
|
+
balance: z5.number()
|
|
4604
4772
|
});
|
|
4605
|
-
var RelayMessageSchema =
|
|
4773
|
+
var RelayMessageSchema = z5.discriminatedUnion("type", [
|
|
4606
4774
|
RegisterMessageSchema,
|
|
4607
4775
|
RegisteredMessageSchema,
|
|
4608
4776
|
RelayRequestMessageSchema,
|
|
@@ -4618,7 +4786,13 @@ var RelayMessageSchema = z4.discriminatedUnion("type", [
|
|
|
4618
4786
|
EscrowSettleMessageSchema,
|
|
4619
4787
|
EscrowSettledMessageSchema,
|
|
4620
4788
|
BalanceSyncMessageSchema,
|
|
4621
|
-
BalanceSyncResponseMessageSchema
|
|
4789
|
+
BalanceSyncResponseMessageSchema,
|
|
4790
|
+
SessionOpenMessageSchema,
|
|
4791
|
+
SessionAckMessageSchema,
|
|
4792
|
+
SessionMessageMessageSchema,
|
|
4793
|
+
SessionEndMessageSchema,
|
|
4794
|
+
SessionSettledMessageSchema,
|
|
4795
|
+
SessionErrorMessageSchema
|
|
4622
4796
|
]);
|
|
4623
4797
|
|
|
4624
4798
|
// src/relay/websocket-client.ts
|
|
@@ -5005,8 +5179,8 @@ import { randomUUID as randomUUID12 } from "crypto";
|
|
|
5005
5179
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
5006
5180
|
|
|
5007
5181
|
// src/cli/peers.ts
|
|
5008
|
-
import { readFileSync as
|
|
5009
|
-
import { join as
|
|
5182
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
5183
|
+
import { join as join5 } from "path";
|
|
5010
5184
|
|
|
5011
5185
|
// src/autonomy/auto-request.ts
|
|
5012
5186
|
function minMaxNormalize(values) {
|
|
@@ -5123,7 +5297,8 @@ async function matchSubTasks(opts) {
|
|
|
5123
5297
|
}
|
|
5124
5298
|
|
|
5125
5299
|
// src/conductor/budget-controller.ts
|
|
5126
|
-
var
|
|
5300
|
+
var coreConductor = loadCoreConfig("economics");
|
|
5301
|
+
var ORCHESTRATION_FEE = coreConductor?.conductor?.orchestration_fee ?? 5;
|
|
5127
5302
|
var BudgetController = class {
|
|
5128
5303
|
/**
|
|
5129
5304
|
* Creates a new BudgetController.
|
|
@@ -5539,8 +5714,9 @@ async function orchestrate(opts) {
|
|
|
5539
5714
|
}
|
|
5540
5715
|
|
|
5541
5716
|
// src/credit/budget.ts
|
|
5717
|
+
var coreBudget = loadCoreConfig("economics");
|
|
5542
5718
|
var DEFAULT_BUDGET_CONFIG = {
|
|
5543
|
-
reserve_credits: 20
|
|
5719
|
+
reserve_credits: coreBudget?.budget_reserve_credits ?? 20
|
|
5544
5720
|
};
|
|
5545
5721
|
var BudgetManager = class {
|
|
5546
5722
|
/**
|
|
@@ -5978,18 +6154,18 @@ var ConductorMode = class {
|
|
|
5978
6154
|
};
|
|
5979
6155
|
|
|
5980
6156
|
// src/credit/escrow-receipt.ts
|
|
5981
|
-
import { z as
|
|
6157
|
+
import { z as z6 } from "zod";
|
|
5982
6158
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
5983
|
-
var EscrowReceiptSchema =
|
|
5984
|
-
requester_owner:
|
|
5985
|
-
requester_agent_id:
|
|
5986
|
-
requester_public_key:
|
|
5987
|
-
amount:
|
|
5988
|
-
card_id:
|
|
5989
|
-
skill_id:
|
|
5990
|
-
timestamp:
|
|
5991
|
-
nonce:
|
|
5992
|
-
signature:
|
|
6159
|
+
var EscrowReceiptSchema = z6.object({
|
|
6160
|
+
requester_owner: z6.string().min(1),
|
|
6161
|
+
requester_agent_id: z6.string().optional(),
|
|
6162
|
+
requester_public_key: z6.string().min(1),
|
|
6163
|
+
amount: z6.number().positive(),
|
|
6164
|
+
card_id: z6.string().min(1),
|
|
6165
|
+
skill_id: z6.string().optional(),
|
|
6166
|
+
timestamp: z6.string(),
|
|
6167
|
+
nonce: z6.string().uuid(),
|
|
6168
|
+
signature: z6.string().min(1)
|
|
5993
6169
|
});
|
|
5994
6170
|
function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
5995
6171
|
const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
|
|
@@ -6310,16 +6486,16 @@ var AgentBnBProvider = class {
|
|
|
6310
6486
|
};
|
|
6311
6487
|
|
|
6312
6488
|
// src/identity/guarantor.ts
|
|
6313
|
-
import { z as
|
|
6489
|
+
import { z as z7 } from "zod";
|
|
6314
6490
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
6315
6491
|
var MAX_AGENTS_PER_GUARANTOR = 10;
|
|
6316
6492
|
var GUARANTOR_CREDIT_POOL = 50;
|
|
6317
|
-
var GuarantorRecordSchema =
|
|
6318
|
-
id:
|
|
6319
|
-
github_login:
|
|
6320
|
-
agent_count:
|
|
6321
|
-
credit_pool:
|
|
6322
|
-
created_at:
|
|
6493
|
+
var GuarantorRecordSchema = z7.object({
|
|
6494
|
+
id: z7.string().uuid(),
|
|
6495
|
+
github_login: z7.string().min(1),
|
|
6496
|
+
agent_count: z7.number().int().nonnegative(),
|
|
6497
|
+
credit_pool: z7.number().int().nonnegative(),
|
|
6498
|
+
created_at: z7.string().datetime()
|
|
6323
6499
|
});
|
|
6324
6500
|
var GUARANTOR_SCHEMA = `
|
|
6325
6501
|
CREATE TABLE IF NOT EXISTS guarantors (
|
|
@@ -6429,9 +6605,10 @@ function initiateGithubAuth() {
|
|
|
6429
6605
|
}
|
|
6430
6606
|
|
|
6431
6607
|
// src/relay/websocket-relay.ts
|
|
6432
|
-
import { randomUUID as
|
|
6608
|
+
import { randomUUID as randomUUID20 } from "crypto";
|
|
6433
6609
|
|
|
6434
6610
|
// src/relay/relay-credit.ts
|
|
6611
|
+
var coreConductorFee = loadCoreConfig("economics");
|
|
6435
6612
|
function lookupCardPrice(registryDb, cardId, skillId) {
|
|
6436
6613
|
const row = registryDb.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId);
|
|
6437
6614
|
if (!row) return null;
|
|
@@ -6478,8 +6655,11 @@ function settleForRelay(creditDb, escrowId, recipientOwner) {
|
|
|
6478
6655
|
}
|
|
6479
6656
|
function calculateConductorFee(totalSubTaskCost) {
|
|
6480
6657
|
if (totalSubTaskCost <= 0) return 0;
|
|
6481
|
-
const
|
|
6482
|
-
|
|
6658
|
+
const rate = coreConductorFee?.conductor?.sub_task_fee_rate ?? 0.1;
|
|
6659
|
+
const min = coreConductorFee?.conductor?.sub_task_fee_min ?? 1;
|
|
6660
|
+
const max = coreConductorFee?.conductor?.sub_task_fee_max ?? 20;
|
|
6661
|
+
const fee = Math.ceil(totalSubTaskCost * rate);
|
|
6662
|
+
return Math.max(min, Math.min(max, fee));
|
|
6483
6663
|
}
|
|
6484
6664
|
function releaseForRelay(creditDb, escrowId) {
|
|
6485
6665
|
if (escrowId === void 0) return;
|
|
@@ -6533,10 +6713,9 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
|
|
|
6533
6713
|
if (!escrowRow) {
|
|
6534
6714
|
throw new Error(`Escrow not found or already settled: ${escrowId}`);
|
|
6535
6715
|
}
|
|
6536
|
-
const NETWORK_FEE_RATE2 = 0.05;
|
|
6537
6716
|
if (success) {
|
|
6538
6717
|
settleEscrow(creditDb, escrowId, providerAgentId);
|
|
6539
|
-
const networkFee = Math.floor(escrowRow.amount *
|
|
6718
|
+
const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE);
|
|
6540
6719
|
const providerAmount = escrowRow.amount - networkFee;
|
|
6541
6720
|
return {
|
|
6542
6721
|
escrow_id: escrowId,
|
|
@@ -6601,12 +6780,413 @@ function handleJobRelayResponse(opts) {
|
|
|
6601
6780
|
}
|
|
6602
6781
|
}
|
|
6603
6782
|
|
|
6783
|
+
// src/session/session-manager.ts
|
|
6784
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
6785
|
+
|
|
6786
|
+
// src/session/session-escrow.ts
|
|
6787
|
+
var SessionEscrow = class {
|
|
6788
|
+
constructor(creditDb) {
|
|
6789
|
+
this.creditDb = creditDb;
|
|
6790
|
+
}
|
|
6791
|
+
/** escrowId → { budget, spent } */
|
|
6792
|
+
tracking = /* @__PURE__ */ new Map();
|
|
6793
|
+
/**
|
|
6794
|
+
* Hold the full session budget in escrow.
|
|
6795
|
+
* @returns The escrow ID for tracking.
|
|
6796
|
+
*/
|
|
6797
|
+
holdBudget(owner, budget, cardId) {
|
|
6798
|
+
const escrowId = holdEscrow(this.creditDb, owner, budget, cardId);
|
|
6799
|
+
this.tracking.set(escrowId, { budget, spent: 0 });
|
|
6800
|
+
return escrowId;
|
|
6801
|
+
}
|
|
6802
|
+
/**
|
|
6803
|
+
* Record a per-message deduction against the session budget.
|
|
6804
|
+
* Does not touch the DB — tracking is in-memory until settle.
|
|
6805
|
+
*/
|
|
6806
|
+
deductMessage(escrowId, rate) {
|
|
6807
|
+
return this.deduct(escrowId, rate);
|
|
6808
|
+
}
|
|
6809
|
+
/**
|
|
6810
|
+
* Record a per-minute deduction against the session budget.
|
|
6811
|
+
*/
|
|
6812
|
+
deductMinute(escrowId, rate) {
|
|
6813
|
+
return this.deduct(escrowId, rate);
|
|
6814
|
+
}
|
|
6815
|
+
/**
|
|
6816
|
+
* Settle the session escrow. Pays the provider the actual cost and
|
|
6817
|
+
* refunds the remainder to the requester.
|
|
6818
|
+
*/
|
|
6819
|
+
settle(escrowId, providerOwner) {
|
|
6820
|
+
const t = this.tracking.get(escrowId);
|
|
6821
|
+
if (!t) {
|
|
6822
|
+
settleEscrow(this.creditDb, escrowId, providerOwner);
|
|
6823
|
+
return;
|
|
6824
|
+
}
|
|
6825
|
+
if (t.spent <= 0) {
|
|
6826
|
+
releaseEscrow(this.creditDb, escrowId);
|
|
6827
|
+
} else {
|
|
6828
|
+
settleEscrow(this.creditDb, escrowId, providerOwner);
|
|
6829
|
+
}
|
|
6830
|
+
this.tracking.delete(escrowId);
|
|
6831
|
+
}
|
|
6832
|
+
/**
|
|
6833
|
+
* Release the escrow entirely — full refund to requester.
|
|
6834
|
+
*/
|
|
6835
|
+
refund(escrowId) {
|
|
6836
|
+
releaseEscrow(this.creditDb, escrowId);
|
|
6837
|
+
this.tracking.delete(escrowId);
|
|
6838
|
+
}
|
|
6839
|
+
/**
|
|
6840
|
+
* Get remaining budget for a session escrow.
|
|
6841
|
+
*/
|
|
6842
|
+
getRemainingBudget(escrowId) {
|
|
6843
|
+
const t = this.tracking.get(escrowId);
|
|
6844
|
+
if (!t) return 0;
|
|
6845
|
+
return t.budget - t.spent;
|
|
6846
|
+
}
|
|
6847
|
+
/**
|
|
6848
|
+
* Get total spent for a session escrow.
|
|
6849
|
+
*/
|
|
6850
|
+
getSpent(escrowId) {
|
|
6851
|
+
return this.tracking.get(escrowId)?.spent ?? 0;
|
|
6852
|
+
}
|
|
6853
|
+
/**
|
|
6854
|
+
* Check if the budget is exhausted.
|
|
6855
|
+
*/
|
|
6856
|
+
isBudgetExhausted(escrowId) {
|
|
6857
|
+
return this.getRemainingBudget(escrowId) <= 0;
|
|
6858
|
+
}
|
|
6859
|
+
/**
|
|
6860
|
+
* Calculate the cost for a single interaction based on pricing model.
|
|
6861
|
+
*/
|
|
6862
|
+
calculateCost(pricingModel, rate, durationMinutes) {
|
|
6863
|
+
switch (pricingModel) {
|
|
6864
|
+
case "per_message":
|
|
6865
|
+
return rate;
|
|
6866
|
+
case "per_minute":
|
|
6867
|
+
return Math.ceil(durationMinutes ?? 1) * rate;
|
|
6868
|
+
case "per_session":
|
|
6869
|
+
return rate;
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
deduct(escrowId, amount) {
|
|
6873
|
+
const t = this.tracking.get(escrowId);
|
|
6874
|
+
if (!t) {
|
|
6875
|
+
throw new Error(`No session escrow tracking for ${escrowId}`);
|
|
6876
|
+
}
|
|
6877
|
+
t.spent += amount;
|
|
6878
|
+
return { spent: t.spent, remaining: t.budget - t.spent };
|
|
6879
|
+
}
|
|
6880
|
+
};
|
|
6881
|
+
|
|
6882
|
+
// src/session/session-manager.ts
|
|
6883
|
+
var SessionManager = class {
|
|
6884
|
+
sessions = /* @__PURE__ */ new Map();
|
|
6885
|
+
idleTimers = /* @__PURE__ */ new Map();
|
|
6886
|
+
durationTimers = /* @__PURE__ */ new Map();
|
|
6887
|
+
escrow;
|
|
6888
|
+
config;
|
|
6889
|
+
sendToAgent;
|
|
6890
|
+
/** Maps agent connection key → set of session IDs they participate in. */
|
|
6891
|
+
agentSessions = /* @__PURE__ */ new Map();
|
|
6892
|
+
constructor(opts) {
|
|
6893
|
+
this.escrow = new SessionEscrow(opts.creditDb);
|
|
6894
|
+
this.config = opts.config ?? loadSessionConfig();
|
|
6895
|
+
this.sendToAgent = opts.sendToAgent;
|
|
6896
|
+
}
|
|
6897
|
+
/**
|
|
6898
|
+
* Open a new session between requester and provider.
|
|
6899
|
+
*/
|
|
6900
|
+
openSession(msg, requesterKey) {
|
|
6901
|
+
const requesterSessions = this.agentSessions.get(requesterKey);
|
|
6902
|
+
if (requesterSessions && requesterSessions.size >= this.config.abuse.max_concurrent_sessions_per_agent) {
|
|
6903
|
+
this.sendToAgent(requesterKey, {
|
|
6904
|
+
type: "session_error",
|
|
6905
|
+
session_id: msg.session_id,
|
|
6906
|
+
code: "MAX_CONCURRENT_SESSIONS",
|
|
6907
|
+
message: `Maximum concurrent sessions (${this.config.abuse.max_concurrent_sessions_per_agent}) reached`
|
|
6908
|
+
});
|
|
6909
|
+
throw new Error("Max concurrent sessions reached");
|
|
6910
|
+
}
|
|
6911
|
+
const escrowId = this.escrow.holdBudget(msg.requester_id, msg.budget, msg.card_id);
|
|
6912
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6913
|
+
const session = {
|
|
6914
|
+
id: msg.session_id,
|
|
6915
|
+
requester_id: msg.requester_id,
|
|
6916
|
+
provider_id: msg.provider_id,
|
|
6917
|
+
skill_id: msg.skill_id,
|
|
6918
|
+
card_id: msg.card_id,
|
|
6919
|
+
status: "open",
|
|
6920
|
+
escrow_id: escrowId,
|
|
6921
|
+
budget: msg.budget,
|
|
6922
|
+
spent: 0,
|
|
6923
|
+
pricing_model: msg.pricing_model,
|
|
6924
|
+
messages: [],
|
|
6925
|
+
created_at: now,
|
|
6926
|
+
updated_at: now
|
|
6927
|
+
};
|
|
6928
|
+
this.sessions.set(session.id, session);
|
|
6929
|
+
this.trackAgentSession(requesterKey, session.id);
|
|
6930
|
+
this.trackAgentSession(msg.provider_id, session.id);
|
|
6931
|
+
this.sendToAgent(requesterKey, {
|
|
6932
|
+
type: "session_ack",
|
|
6933
|
+
session_id: session.id,
|
|
6934
|
+
escrow_id: escrowId,
|
|
6935
|
+
status: "open"
|
|
6936
|
+
});
|
|
6937
|
+
const initialMsg = this.createMessage(session.id, "requester", msg.initial_message);
|
|
6938
|
+
session.messages.push(initialMsg);
|
|
6939
|
+
session.status = "active";
|
|
6940
|
+
session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
6941
|
+
this.sendToAgent(msg.provider_id, {
|
|
6942
|
+
type: "session_message",
|
|
6943
|
+
session_id: session.id,
|
|
6944
|
+
sender: "requester",
|
|
6945
|
+
content: msg.initial_message
|
|
6946
|
+
});
|
|
6947
|
+
if (session.pricing_model === "per_session") {
|
|
6948
|
+
const cost = this.config.pricing.per_session_flat_rate;
|
|
6949
|
+
this.escrow.deductMessage(escrowId, cost);
|
|
6950
|
+
session.spent = cost;
|
|
6951
|
+
}
|
|
6952
|
+
this.resetIdleTimer(session.id);
|
|
6953
|
+
this.startDurationTimer(session.id);
|
|
6954
|
+
return session;
|
|
6955
|
+
}
|
|
6956
|
+
/**
|
|
6957
|
+
* Route a message within an active session.
|
|
6958
|
+
*/
|
|
6959
|
+
routeMessage(msg, senderKey) {
|
|
6960
|
+
const session = this.sessions.get(msg.session_id);
|
|
6961
|
+
if (!session) {
|
|
6962
|
+
this.sendToAgent(senderKey, {
|
|
6963
|
+
type: "session_error",
|
|
6964
|
+
session_id: msg.session_id,
|
|
6965
|
+
code: "SESSION_NOT_FOUND",
|
|
6966
|
+
message: "Session not found"
|
|
6967
|
+
});
|
|
6968
|
+
return;
|
|
6969
|
+
}
|
|
6970
|
+
if (session.status !== "active") {
|
|
6971
|
+
this.sendToAgent(senderKey, {
|
|
6972
|
+
type: "session_error",
|
|
6973
|
+
session_id: msg.session_id,
|
|
6974
|
+
code: "SESSION_NOT_ACTIVE",
|
|
6975
|
+
message: `Session is ${session.status}, not active`
|
|
6976
|
+
});
|
|
6977
|
+
return;
|
|
6978
|
+
}
|
|
6979
|
+
if (session.messages.length >= this.config.pricing.max_messages_per_session) {
|
|
6980
|
+
this.endSessionInternal(session, "budget_exhausted");
|
|
6981
|
+
return;
|
|
6982
|
+
}
|
|
6983
|
+
if (session.pricing_model === "per_message" && msg.sender === "provider") {
|
|
6984
|
+
const rate = this.config.pricing.per_message_base_rate;
|
|
6985
|
+
const { remaining } = this.escrow.deductMessage(session.escrow_id, rate);
|
|
6986
|
+
session.spent += rate;
|
|
6987
|
+
if (remaining <= 0) {
|
|
6988
|
+
const record2 = this.createMessage(session.id, msg.sender, msg.content, msg.metadata);
|
|
6989
|
+
session.messages.push(record2);
|
|
6990
|
+
session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
6991
|
+
const targetKey2 = this.getCounterpartyKey(session, msg.sender);
|
|
6992
|
+
this.sendToAgent(targetKey2, {
|
|
6993
|
+
type: "session_message",
|
|
6994
|
+
session_id: session.id,
|
|
6995
|
+
sender: msg.sender,
|
|
6996
|
+
content: msg.content,
|
|
6997
|
+
metadata: msg.metadata
|
|
6998
|
+
});
|
|
6999
|
+
this.endSessionInternal(session, "budget_exhausted");
|
|
7000
|
+
return;
|
|
7001
|
+
}
|
|
7002
|
+
}
|
|
7003
|
+
const record = this.createMessage(session.id, msg.sender, msg.content, msg.metadata);
|
|
7004
|
+
session.messages.push(record);
|
|
7005
|
+
session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7006
|
+
const targetKey = this.getCounterpartyKey(session, msg.sender);
|
|
7007
|
+
this.sendToAgent(targetKey, {
|
|
7008
|
+
type: "session_message",
|
|
7009
|
+
session_id: session.id,
|
|
7010
|
+
sender: msg.sender,
|
|
7011
|
+
content: msg.content,
|
|
7012
|
+
metadata: msg.metadata
|
|
7013
|
+
});
|
|
7014
|
+
this.resetIdleTimer(session.id);
|
|
7015
|
+
}
|
|
7016
|
+
/**
|
|
7017
|
+
* End a session at the request of either party.
|
|
7018
|
+
*/
|
|
7019
|
+
endSession(msg, _senderKey) {
|
|
7020
|
+
const session = this.sessions.get(msg.session_id);
|
|
7021
|
+
if (!session) return;
|
|
7022
|
+
if (session.status === "settled" || session.status === "closed") return;
|
|
7023
|
+
this.endSessionInternal(session, msg.reason);
|
|
7024
|
+
}
|
|
7025
|
+
/**
|
|
7026
|
+
* Handle agent disconnection — end all their active sessions.
|
|
7027
|
+
*/
|
|
7028
|
+
handleDisconnect(agentKey) {
|
|
7029
|
+
const sessionIds = this.agentSessions.get(agentKey);
|
|
7030
|
+
if (!sessionIds) return;
|
|
7031
|
+
for (const sessionId of sessionIds) {
|
|
7032
|
+
const session = this.sessions.get(sessionId);
|
|
7033
|
+
if (session && session.status !== "settled" && session.status !== "closed") {
|
|
7034
|
+
this.endSessionInternal(session, "error");
|
|
7035
|
+
}
|
|
7036
|
+
}
|
|
7037
|
+
}
|
|
7038
|
+
/** Get a session by ID. */
|
|
7039
|
+
getSession(sessionId) {
|
|
7040
|
+
return this.sessions.get(sessionId);
|
|
7041
|
+
}
|
|
7042
|
+
/** List sessions, optionally filtered by agent. */
|
|
7043
|
+
listSessions(agentId) {
|
|
7044
|
+
if (!agentId) return Array.from(this.sessions.values());
|
|
7045
|
+
return Array.from(this.sessions.values()).filter(
|
|
7046
|
+
(s) => s.requester_id === agentId || s.provider_id === agentId
|
|
7047
|
+
);
|
|
7048
|
+
}
|
|
7049
|
+
/** Clean up all timers (for graceful shutdown). */
|
|
7050
|
+
shutdown() {
|
|
7051
|
+
for (const timer of this.idleTimers.values()) clearTimeout(timer);
|
|
7052
|
+
for (const timer of this.durationTimers.values()) clearTimeout(timer);
|
|
7053
|
+
this.idleTimers.clear();
|
|
7054
|
+
this.durationTimers.clear();
|
|
7055
|
+
}
|
|
7056
|
+
// -------------------------------------------------------------------------
|
|
7057
|
+
// Internal helpers
|
|
7058
|
+
// -------------------------------------------------------------------------
|
|
7059
|
+
endSessionInternal(session, reason) {
|
|
7060
|
+
session.status = "closing";
|
|
7061
|
+
session.end_reason = reason;
|
|
7062
|
+
session.ended_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7063
|
+
this.clearTimers(session.id);
|
|
7064
|
+
if (session.spent > 0) {
|
|
7065
|
+
this.escrow.settle(session.escrow_id, session.provider_id);
|
|
7066
|
+
} else {
|
|
7067
|
+
this.escrow.refund(session.escrow_id);
|
|
7068
|
+
}
|
|
7069
|
+
const durationMs = Date.now() - new Date(session.created_at).getTime();
|
|
7070
|
+
const settledMsg = {
|
|
7071
|
+
type: "session_settled",
|
|
7072
|
+
session_id: session.id,
|
|
7073
|
+
total_cost: session.spent,
|
|
7074
|
+
messages_count: session.messages.length,
|
|
7075
|
+
duration_seconds: Math.round(durationMs / 1e3),
|
|
7076
|
+
refunded: session.budget - session.spent
|
|
7077
|
+
};
|
|
7078
|
+
session.status = "settled";
|
|
7079
|
+
session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7080
|
+
this.sendToAgent(session.requester_id, settledMsg);
|
|
7081
|
+
this.sendToAgent(session.provider_id, settledMsg);
|
|
7082
|
+
session.status = "closed";
|
|
7083
|
+
this.untrackAgentSession(session.requester_id, session.id);
|
|
7084
|
+
this.untrackAgentSession(session.provider_id, session.id);
|
|
7085
|
+
}
|
|
7086
|
+
resetIdleTimer(sessionId) {
|
|
7087
|
+
const existing = this.idleTimers.get(sessionId);
|
|
7088
|
+
if (existing) clearTimeout(existing);
|
|
7089
|
+
const timer = setTimeout(() => {
|
|
7090
|
+
const session = this.sessions.get(sessionId);
|
|
7091
|
+
if (session && session.status === "active") {
|
|
7092
|
+
this.endSessionInternal(session, "timeout");
|
|
7093
|
+
}
|
|
7094
|
+
}, this.config.timeouts.idle_timeout_ms);
|
|
7095
|
+
this.idleTimers.set(sessionId, timer);
|
|
7096
|
+
}
|
|
7097
|
+
startDurationTimer(sessionId) {
|
|
7098
|
+
const timer = setTimeout(() => {
|
|
7099
|
+
const session = this.sessions.get(sessionId);
|
|
7100
|
+
if (session && session.status !== "settled" && session.status !== "closed") {
|
|
7101
|
+
this.endSessionInternal(session, "timeout");
|
|
7102
|
+
}
|
|
7103
|
+
}, this.config.timeouts.max_session_duration_ms);
|
|
7104
|
+
this.durationTimers.set(sessionId, timer);
|
|
7105
|
+
}
|
|
7106
|
+
clearTimers(sessionId) {
|
|
7107
|
+
const idle = this.idleTimers.get(sessionId);
|
|
7108
|
+
if (idle) {
|
|
7109
|
+
clearTimeout(idle);
|
|
7110
|
+
this.idleTimers.delete(sessionId);
|
|
7111
|
+
}
|
|
7112
|
+
const dur = this.durationTimers.get(sessionId);
|
|
7113
|
+
if (dur) {
|
|
7114
|
+
clearTimeout(dur);
|
|
7115
|
+
this.durationTimers.delete(sessionId);
|
|
7116
|
+
}
|
|
7117
|
+
}
|
|
7118
|
+
createMessage(sessionId, sender, content, metadata) {
|
|
7119
|
+
return {
|
|
7120
|
+
id: randomUUID19(),
|
|
7121
|
+
session_id: sessionId,
|
|
7122
|
+
sender,
|
|
7123
|
+
content,
|
|
7124
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7125
|
+
metadata
|
|
7126
|
+
};
|
|
7127
|
+
}
|
|
7128
|
+
getCounterpartyKey(session, sender) {
|
|
7129
|
+
return sender === "requester" ? session.provider_id : session.requester_id;
|
|
7130
|
+
}
|
|
7131
|
+
trackAgentSession(agentKey, sessionId) {
|
|
7132
|
+
let set = this.agentSessions.get(agentKey);
|
|
7133
|
+
if (!set) {
|
|
7134
|
+
set = /* @__PURE__ */ new Set();
|
|
7135
|
+
this.agentSessions.set(agentKey, set);
|
|
7136
|
+
}
|
|
7137
|
+
set.add(sessionId);
|
|
7138
|
+
}
|
|
7139
|
+
untrackAgentSession(agentKey, sessionId) {
|
|
7140
|
+
const set = this.agentSessions.get(agentKey);
|
|
7141
|
+
if (set) {
|
|
7142
|
+
set.delete(sessionId);
|
|
7143
|
+
if (set.size === 0) this.agentSessions.delete(agentKey);
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
};
|
|
7147
|
+
|
|
7148
|
+
// src/session/session-relay.ts
|
|
7149
|
+
function attachSessionHandler(opts) {
|
|
7150
|
+
const { sessionManager } = opts;
|
|
7151
|
+
return {
|
|
7152
|
+
handleSessionMessage(msg, senderKey) {
|
|
7153
|
+
if (!SESSION_MESSAGE_TYPES.has(msg.type)) return false;
|
|
7154
|
+
switch (msg.type) {
|
|
7155
|
+
case "session_open": {
|
|
7156
|
+
const parsed = SessionOpenMessageSchema.parse(msg);
|
|
7157
|
+
sessionManager.openSession(parsed, senderKey);
|
|
7158
|
+
return true;
|
|
7159
|
+
}
|
|
7160
|
+
case "session_message": {
|
|
7161
|
+
const parsed = SessionMessageMessageSchema.parse(msg);
|
|
7162
|
+
sessionManager.routeMessage(parsed, senderKey);
|
|
7163
|
+
return true;
|
|
7164
|
+
}
|
|
7165
|
+
case "session_end": {
|
|
7166
|
+
const parsed = SessionEndMessageSchema.parse(msg);
|
|
7167
|
+
sessionManager.endSession(parsed, senderKey);
|
|
7168
|
+
return true;
|
|
7169
|
+
}
|
|
7170
|
+
// session_ack, session_settled, session_error are relay→agent only
|
|
7171
|
+
// They should not arrive from agents, but we silently absorb them
|
|
7172
|
+
case "session_ack":
|
|
7173
|
+
case "session_settled":
|
|
7174
|
+
case "session_error":
|
|
7175
|
+
return true;
|
|
7176
|
+
default:
|
|
7177
|
+
return false;
|
|
7178
|
+
}
|
|
7179
|
+
}
|
|
7180
|
+
};
|
|
7181
|
+
}
|
|
7182
|
+
|
|
6604
7183
|
// src/relay/websocket-relay.ts
|
|
6605
|
-
var
|
|
6606
|
-
var
|
|
6607
|
-
var
|
|
6608
|
-
var
|
|
6609
|
-
var
|
|
7184
|
+
var coreRelay = loadCoreConfig("relay");
|
|
7185
|
+
var RATE_LIMIT_MAX = coreRelay?.rate_limit_max ?? 60;
|
|
7186
|
+
var RATE_LIMIT_WINDOW_MS = coreRelay?.rate_limit_window_ms ?? 6e4;
|
|
7187
|
+
var RELAY_IDLE_TIMEOUT_MS = coreRelay?.relay_idle_timeout_ms ?? 3e4;
|
|
7188
|
+
var RELAY_HARD_TIMEOUT_MS = coreRelay?.relay_hard_timeout_ms ?? 3e5;
|
|
7189
|
+
var RELAY_DISCONNECT_GRACE_MS = coreRelay?.relay_disconnect_grace_ms ?? RELAY_HARD_TIMEOUT_MS + 3e4;
|
|
6610
7190
|
function readTimeoutOverride(envKey, fallbackMs) {
|
|
6611
7191
|
const raw = process.env[envKey];
|
|
6612
7192
|
if (!raw) return fallbackMs;
|
|
@@ -6837,7 +7417,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
6837
7417
|
function logAgentJoined(owner, cardName, cardId) {
|
|
6838
7418
|
try {
|
|
6839
7419
|
insertRequestLog(db, {
|
|
6840
|
-
id:
|
|
7420
|
+
id: randomUUID20(),
|
|
6841
7421
|
card_id: cardId,
|
|
6842
7422
|
card_name: cardName,
|
|
6843
7423
|
requester: owner,
|
|
@@ -6855,6 +7435,19 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
6855
7435
|
ws.send(JSON.stringify(msg));
|
|
6856
7436
|
}
|
|
6857
7437
|
}
|
|
7438
|
+
function sendToAgentByKey(agentKey, msg) {
|
|
7439
|
+
const connKey = resolveConnectionKey(agentKey);
|
|
7440
|
+
const ws = connKey ? connections.get(connKey) : void 0;
|
|
7441
|
+
if (ws && ws.readyState === 1) {
|
|
7442
|
+
ws.send(JSON.stringify(msg));
|
|
7443
|
+
}
|
|
7444
|
+
}
|
|
7445
|
+
const sessionManager = creditDb ? new SessionManager({
|
|
7446
|
+
creditDb,
|
|
7447
|
+
sendToAgent: sendToAgentByKey,
|
|
7448
|
+
isAgentOnline: (key) => !!resolveConnectionKey(key)
|
|
7449
|
+
}) : void 0;
|
|
7450
|
+
const sessionHandler = sessionManager ? attachSessionHandler({ sessionManager }) : void 0;
|
|
6858
7451
|
function handleRegister(ws, msg) {
|
|
6859
7452
|
const { owner, card } = msg;
|
|
6860
7453
|
const existing = connections.get(owner);
|
|
@@ -7074,6 +7667,9 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
7074
7667
|
}
|
|
7075
7668
|
}
|
|
7076
7669
|
markOwnerOffline(owner);
|
|
7670
|
+
if (sessionManager) {
|
|
7671
|
+
sessionManager.handleDisconnect(owner);
|
|
7672
|
+
}
|
|
7077
7673
|
for (const [reqId, pending] of pendingRequests) {
|
|
7078
7674
|
if (pending.targetOwner === owner) {
|
|
7079
7675
|
clearPendingTimers(pending);
|
|
@@ -7268,6 +7864,13 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
7268
7864
|
handleBalanceSync(socket, msg);
|
|
7269
7865
|
break;
|
|
7270
7866
|
default:
|
|
7867
|
+
if (sessionHandler && registeredOwner) {
|
|
7868
|
+
const handled = sessionHandler.handleSessionMessage(
|
|
7869
|
+
msg,
|
|
7870
|
+
registeredOwner
|
|
7871
|
+
);
|
|
7872
|
+
if (handled) break;
|
|
7873
|
+
}
|
|
7271
7874
|
break;
|
|
7272
7875
|
}
|
|
7273
7876
|
})();
|
|
@@ -7302,6 +7905,7 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
7302
7905
|
pendingRequests.clear();
|
|
7303
7906
|
rateLimits.clear();
|
|
7304
7907
|
agentCapacities.clear();
|
|
7908
|
+
if (sessionManager) sessionManager.shutdown();
|
|
7305
7909
|
},
|
|
7306
7910
|
setOnAgentOnline: (cb) => {
|
|
7307
7911
|
onAgentOnlineCallback = cb;
|
|
@@ -7317,12 +7921,12 @@ function registerWebSocketRelay(server, db, creditDb) {
|
|
|
7317
7921
|
}
|
|
7318
7922
|
|
|
7319
7923
|
// src/onboarding/index.ts
|
|
7320
|
-
import { randomUUID as
|
|
7321
|
-
import { existsSync as existsSync5, readFileSync as
|
|
7322
|
-
import { join as
|
|
7924
|
+
import { randomUUID as randomUUID22 } from "crypto";
|
|
7925
|
+
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
|
|
7926
|
+
import { join as join6 } from "path";
|
|
7323
7927
|
|
|
7324
7928
|
// src/cli/onboarding.ts
|
|
7325
|
-
import { randomUUID as
|
|
7929
|
+
import { randomUUID as randomUUID21 } from "crypto";
|
|
7326
7930
|
import { createConnection } from "net";
|
|
7327
7931
|
var KNOWN_API_KEYS = [
|
|
7328
7932
|
"OPENAI_API_KEY",
|
|
@@ -7418,9 +8022,9 @@ var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
|
|
|
7418
8022
|
function detectCapabilities(opts = {}) {
|
|
7419
8023
|
const cwd = opts.cwd ?? process.cwd();
|
|
7420
8024
|
if (opts.fromFile) {
|
|
7421
|
-
const filePath = opts.fromFile.startsWith("/") ? opts.fromFile :
|
|
8025
|
+
const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join6(cwd, opts.fromFile);
|
|
7422
8026
|
if (existsSync5(filePath)) {
|
|
7423
|
-
const content =
|
|
8027
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
7424
8028
|
const capabilities = detectFromDocs(content);
|
|
7425
8029
|
if (capabilities.length > 0) {
|
|
7426
8030
|
return { source: "docs", capabilities, sourceFile: filePath };
|
|
@@ -7429,9 +8033,9 @@ function detectCapabilities(opts = {}) {
|
|
|
7429
8033
|
return { source: "none", capabilities: [] };
|
|
7430
8034
|
}
|
|
7431
8035
|
for (const fileName of DOC_FILES) {
|
|
7432
|
-
const filePath =
|
|
8036
|
+
const filePath = join6(cwd, fileName);
|
|
7433
8037
|
if (!existsSync5(filePath)) continue;
|
|
7434
|
-
const content =
|
|
8038
|
+
const content = readFileSync6(filePath, "utf-8");
|
|
7435
8039
|
if (fileName === "SOUL.md") {
|
|
7436
8040
|
return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
|
|
7437
8041
|
}
|
|
@@ -7464,7 +8068,7 @@ function capabilitiesToV2Card(capabilities, owner, agentName) {
|
|
|
7464
8068
|
}));
|
|
7465
8069
|
const card = {
|
|
7466
8070
|
spec_version: "2.0",
|
|
7467
|
-
id:
|
|
8071
|
+
id: randomUUID22(),
|
|
7468
8072
|
owner,
|
|
7469
8073
|
agent_name: agentName ?? owner,
|
|
7470
8074
|
skills,
|