agentbnb 9.1.1 → 9.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/{card-UF465O7O.js → card-L3ZPPBVI.js} +3 -3
- package/dist/{chunk-LENX5NUW.js → chunk-2KSRFDKF.js} +56 -3
- package/dist/{chunk-TCA63C42.js → chunk-563ZZUOA.js} +61 -27
- package/dist/chunk-5FXLZ5FX.js +16 -0
- package/dist/{chunk-ELFGYC22.js → chunk-7YJOBVWN.js} +3 -0
- package/dist/{chunk-5CC6O6SO.js → chunk-AA25Z6FW.js} +1 -1
- package/dist/{chunk-WARYO57F.js → chunk-COOBXNXU.js} +6 -6
- package/dist/{chunk-I4E5ERDN.js → chunk-CPSV5WR2.js} +1 -1
- package/dist/{process-guard-6324CZDC.js → chunk-DG4FQ4MD.js} +1 -1
- package/dist/{chunk-MPS4RE7T.js → chunk-DT2IEL5U.js} +11 -0
- package/dist/chunk-EMVVFP2L.js +54 -0
- package/dist/{chunk-O44N3KR7.js → chunk-FVLHEI3Y.js} +5 -5
- package/dist/chunk-GIK2AZQH.js +23 -0
- package/dist/{chunk-W6LOCBWQ.js → chunk-IWAK4WHK.js} +1 -1
- package/dist/{chunk-Y7CO3VLF.js → chunk-NISX3N7K.js} +16 -7
- package/dist/{chunk-2HH2F3DM.js → chunk-NLGLGR2K.js} +55 -2
- package/dist/{chunk-AW4VSROG.js → chunk-OFIRWD6B.js} +1 -1
- package/dist/{chunk-AMABG5SI.js → chunk-OI46BKQF.js} +12 -12
- package/dist/{chunk-F2CIPAN2.js → chunk-OTAZIF65.js} +2 -2
- package/dist/{chunk-ZYOMPJGG.js → chunk-OXU4QJSZ.js} +3 -3
- package/dist/{chunk-RVOZHVM7.js → chunk-PFAEZI32.js} +10 -10
- package/dist/{chunk-D7NH6YLM.js → chunk-UJXDBOKV.js} +12 -1
- package/dist/{chunk-G4TF4LB4.js → chunk-VDYHCI5F.js} +22 -1
- package/dist/{chunk-QG2LLVXP.js → chunk-WA23XRTN.js} +1 -1
- package/dist/cli/index.js +797 -107
- package/dist/{client-XOSXFC7Q.js → client-KL67WZVJ.js} +2 -2
- package/dist/{conduct-UT6ZYSJD.js → conduct-65BGO2EU.js} +16 -14
- package/dist/{conduct-MALC6HEK.js → conduct-AALDEKTH.js} +16 -14
- package/dist/{conductor-mode-3WLLERB4.js → conductor-mode-6S6ADNLW.js} +18 -18
- package/dist/{conductor-mode-UJKMO2GW.js → conductor-mode-HJHU4XLT.js} +4 -4
- package/dist/{credits-action-KOUJNR36.js → credits-action-CLLPNRDT.js} +17 -8
- package/dist/{did-action-UHUYMA4Y.js → did-action-ERXWCVEJ.js} +3 -3
- package/dist/{execute-UFMGTXET.js → execute-R5STYWLD.js} +13 -13
- package/dist/{execute-3RADNI74.js → execute-YMPHTJPN.js} +3 -3
- package/dist/{openclaw-setup-HEWZZOY7.js → openclaw-setup-HUOBTGN4.js} +17 -15
- package/dist/{openclaw-skills-5XLQFRWT.js → openclaw-skills-74372B6I.js} +2 -2
- package/dist/process-guard-IUMZ2GSD.js +8 -0
- package/dist/{publish-capability-LM4RSQXX.js → publish-capability-OYXXXYAU.js} +4 -4
- package/dist/remote-registry-5TM7DMCO.js +16 -0
- package/dist/{request-LID2N42Y.js → request-NEA66RCW.js} +66 -24
- package/dist/{serve-skill-CDNSHTEE.js → serve-skill-VKNRBVWE.js} +19 -18
- package/dist/{server-QIAO3YSK.js → server-LNT4YQZ7.js} +24 -20
- package/dist/{service-coordinator-FB44QL7L.js → service-coordinator-RE2KPWO4.js} +312 -54
- package/dist/{session-action-GYITLYOE.js → session-action-UBWJTQVQ.js} +19 -4
- package/dist/signing-AQTKYJDB.js +16 -0
- package/dist/skills/agentbnb/bootstrap.js +430 -43
- package/dist/{store-C4DLIXYM.js → store-GJJFFEQZ.js} +3 -3
- package/dist/{vc-action-BWGNQ77Y.js → vc-action-72TQVMY2.js} +15 -5
- package/package.json +12 -18
- package/skills/agentbnb/install.sh +0 -0
- package/dist/{chunk-YNBZLXYS.js → chunk-65GNX2KC.js} +0 -0
- package/dist/{chunk-7VZ4M4CT.js → chunk-QE42IJC4.js} +6 -6
- package/dist/{daemon-ETXXE4IS.js → daemon-OM2K3U7J.js} +1 -1
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createLedger,
|
|
3
|
-
deriveAgentId,
|
|
4
|
-
ensureIdentity,
|
|
5
|
-
executeCapabilityBatch,
|
|
6
|
-
executeCapabilityRequest,
|
|
7
|
-
identityAuthPlugin,
|
|
8
|
-
loadOrRepairIdentity,
|
|
9
|
-
notifyProviderEvent,
|
|
10
|
-
syncCreditsFromRegistry
|
|
11
|
-
} from "../../chunk-2HH2F3DM.js";
|
|
12
1
|
import {
|
|
13
2
|
AutoRequestor,
|
|
14
3
|
BudgetController,
|
|
@@ -27,7 +16,19 @@ import {
|
|
|
27
16
|
requestViaTemporaryRelay,
|
|
28
17
|
resolvePendingRequest,
|
|
29
18
|
verifyUCAN
|
|
30
|
-
} from "../../chunk-
|
|
19
|
+
} from "../../chunk-OTAZIF65.js";
|
|
20
|
+
import {
|
|
21
|
+
createLedger,
|
|
22
|
+
deriveAgentId,
|
|
23
|
+
ensureIdentity,
|
|
24
|
+
executeCapabilityBatch,
|
|
25
|
+
executeCapabilityRequest,
|
|
26
|
+
identityAuthPlugin,
|
|
27
|
+
loadOrRepairIdentity,
|
|
28
|
+
notifyProviderEvent,
|
|
29
|
+
syncCreditsFromRegistry,
|
|
30
|
+
tryVerifyIdentity
|
|
31
|
+
} from "../../chunk-NLGLGR2K.js";
|
|
31
32
|
import {
|
|
32
33
|
NETWORK_FEE_RATE,
|
|
33
34
|
bootstrapAgent,
|
|
@@ -37,6 +38,7 @@ import {
|
|
|
37
38
|
fetchRemoteCards,
|
|
38
39
|
filterCards,
|
|
39
40
|
getBalance,
|
|
41
|
+
getEscrowStatus,
|
|
40
42
|
getTransactions,
|
|
41
43
|
holdEscrow,
|
|
42
44
|
markEscrowAbandoned,
|
|
@@ -48,7 +50,7 @@ import {
|
|
|
48
50
|
releaseEscrow,
|
|
49
51
|
searchCards,
|
|
50
52
|
settleEscrow
|
|
51
|
-
} from "../../chunk-
|
|
53
|
+
} from "../../chunk-DT2IEL5U.js";
|
|
52
54
|
import {
|
|
53
55
|
attachCanonicalAgentId,
|
|
54
56
|
getCard,
|
|
@@ -80,13 +82,13 @@ import "../../chunk-EE3V3DXK.js";
|
|
|
80
82
|
import {
|
|
81
83
|
requestCapability,
|
|
82
84
|
requestViaRelay
|
|
83
|
-
} from "../../chunk-
|
|
85
|
+
} from "../../chunk-IWAK4WHK.js";
|
|
84
86
|
import {
|
|
85
87
|
generateKeyPair,
|
|
86
88
|
loadKeyPair,
|
|
87
89
|
signEscrowReceipt,
|
|
88
90
|
verifyEscrowReceipt
|
|
89
|
-
} from "../../chunk-
|
|
91
|
+
} from "../../chunk-65GNX2KC.js";
|
|
90
92
|
import {
|
|
91
93
|
AgentBnBError,
|
|
92
94
|
AnyCardSchema
|
|
@@ -1504,7 +1506,7 @@ var AgentRuntime = class {
|
|
|
1504
1506
|
}
|
|
1505
1507
|
const modes = /* @__PURE__ */ new Map();
|
|
1506
1508
|
if (this.conductorEnabled) {
|
|
1507
|
-
const { ConductorMode } = await import("../../conductor-mode-
|
|
1509
|
+
const { ConductorMode } = await import("../../conductor-mode-HJHU4XLT.js");
|
|
1508
1510
|
const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-U2HQRPYN.js");
|
|
1509
1511
|
const { loadPeers: loadPeers2 } = await import("../../peers-IOVCBWAI.js");
|
|
1510
1512
|
registerConductorCard(this.registryDb);
|
|
@@ -3776,6 +3778,75 @@ function initiateGithubAuth() {
|
|
|
3776
3778
|
};
|
|
3777
3779
|
}
|
|
3778
3780
|
|
|
3781
|
+
// src/registry/hub-identities.ts
|
|
3782
|
+
import { randomBytes as randomBytes2, createHash } from "crypto";
|
|
3783
|
+
var HUB_IDENTITIES_SCHEMA = `
|
|
3784
|
+
CREATE TABLE IF NOT EXISTS hub_identities (
|
|
3785
|
+
email TEXT PRIMARY KEY,
|
|
3786
|
+
agent_id TEXT NOT NULL UNIQUE,
|
|
3787
|
+
public_key TEXT NOT NULL,
|
|
3788
|
+
encrypted_private_key TEXT NOT NULL,
|
|
3789
|
+
kdf_salt TEXT NOT NULL,
|
|
3790
|
+
display_name TEXT NOT NULL,
|
|
3791
|
+
created_at TEXT NOT NULL
|
|
3792
|
+
);
|
|
3793
|
+
|
|
3794
|
+
CREATE INDEX IF NOT EXISTS idx_hub_identities_agent_id
|
|
3795
|
+
ON hub_identities(agent_id);
|
|
3796
|
+
`;
|
|
3797
|
+
var CHALLENGES_SCHEMA = `
|
|
3798
|
+
CREATE TABLE IF NOT EXISTS hub_challenges (
|
|
3799
|
+
challenge TEXT PRIMARY KEY,
|
|
3800
|
+
expires_at TEXT NOT NULL,
|
|
3801
|
+
consumed_at TEXT
|
|
3802
|
+
);
|
|
3803
|
+
`;
|
|
3804
|
+
function ensureHubIdentitiesTables(db) {
|
|
3805
|
+
db.exec(HUB_IDENTITIES_SCHEMA);
|
|
3806
|
+
db.exec(CHALLENGES_SCHEMA);
|
|
3807
|
+
}
|
|
3808
|
+
function deriveAgentId2(publicKeyHex) {
|
|
3809
|
+
const hash = createHash("sha256").update(publicKeyHex, "hex").digest("hex");
|
|
3810
|
+
return `agent-${hash.slice(0, 16)}`;
|
|
3811
|
+
}
|
|
3812
|
+
var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
|
|
3813
|
+
function createChallenge(db) {
|
|
3814
|
+
const challenge = randomBytes2(32).toString("hex");
|
|
3815
|
+
const expires_at = new Date(Date.now() + CHALLENGE_TTL_MS).toISOString();
|
|
3816
|
+
db.prepare("INSERT INTO hub_challenges (challenge, expires_at) VALUES (?, ?)").run(challenge, expires_at);
|
|
3817
|
+
return { challenge, expires_at };
|
|
3818
|
+
}
|
|
3819
|
+
function consumeChallenge(db, challenge) {
|
|
3820
|
+
const row = db.prepare("SELECT expires_at, consumed_at FROM hub_challenges WHERE challenge = ?").get(challenge);
|
|
3821
|
+
if (!row) return false;
|
|
3822
|
+
if (row.consumed_at) return false;
|
|
3823
|
+
if (new Date(row.expires_at).getTime() < Date.now()) return false;
|
|
3824
|
+
const consumed_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
3825
|
+
db.prepare("UPDATE hub_challenges SET consumed_at = ? WHERE challenge = ?").run(consumed_at, challenge);
|
|
3826
|
+
return true;
|
|
3827
|
+
}
|
|
3828
|
+
function pruneChallenges(db) {
|
|
3829
|
+
const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
|
|
3830
|
+
db.prepare("DELETE FROM hub_challenges WHERE expires_at < ? OR consumed_at IS NOT NULL").run(cutoff);
|
|
3831
|
+
}
|
|
3832
|
+
function registerHubIdentity(db, input) {
|
|
3833
|
+
const agent_id = deriveAgentId2(input.public_key);
|
|
3834
|
+
const created_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
3835
|
+
db.prepare(`
|
|
3836
|
+
INSERT INTO hub_identities (email, agent_id, public_key, encrypted_private_key, kdf_salt, display_name, created_at)
|
|
3837
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
3838
|
+
`).run(input.email, agent_id, input.public_key, input.encrypted_private_key, input.kdf_salt, input.display_name, created_at);
|
|
3839
|
+
return { ...input, agent_id, created_at };
|
|
3840
|
+
}
|
|
3841
|
+
function getHubIdentityByEmail(db, email) {
|
|
3842
|
+
const row = db.prepare("SELECT * FROM hub_identities WHERE email = ?").get(email);
|
|
3843
|
+
return row ?? null;
|
|
3844
|
+
}
|
|
3845
|
+
function getHubIdentityByAgentId(db, agent_id) {
|
|
3846
|
+
const row = db.prepare("SELECT * FROM hub_identities WHERE agent_id = ?").get(agent_id);
|
|
3847
|
+
return row ?? null;
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3779
3850
|
// src/registry/free-tier.ts
|
|
3780
3851
|
function initFreeTierTable(db) {
|
|
3781
3852
|
db.exec(`
|
|
@@ -3873,6 +3944,39 @@ async function creditRoutesPlugin(fastify, options) {
|
|
|
3873
3944
|
const transactions = getTransactions(creditDb, owner, { limit, after: since });
|
|
3874
3945
|
return reply.send({ owner, transactions, limit });
|
|
3875
3946
|
});
|
|
3947
|
+
fastify.get("/api/credits/escrow/:id", {
|
|
3948
|
+
schema: {
|
|
3949
|
+
tags: ["credits"],
|
|
3950
|
+
summary: "Get escrow status by ID (public, no auth required)",
|
|
3951
|
+
params: {
|
|
3952
|
+
type: "object",
|
|
3953
|
+
properties: { id: { type: "string" } },
|
|
3954
|
+
required: ["id"]
|
|
3955
|
+
},
|
|
3956
|
+
response: {
|
|
3957
|
+
200: {
|
|
3958
|
+
type: "object",
|
|
3959
|
+
properties: {
|
|
3960
|
+
id: { type: "string" },
|
|
3961
|
+
owner: { type: "string" },
|
|
3962
|
+
amount: { type: "number" },
|
|
3963
|
+
card_id: { type: "string" },
|
|
3964
|
+
status: { type: "string" },
|
|
3965
|
+
created_at: { type: "string" },
|
|
3966
|
+
settled_at: { type: ["string", "null"] }
|
|
3967
|
+
}
|
|
3968
|
+
},
|
|
3969
|
+
404: { type: "object", properties: { error: { type: "string" } } }
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
}, async (request, reply) => {
|
|
3973
|
+
const { id } = request.params;
|
|
3974
|
+
const escrow = getEscrowStatus(creditDb, id);
|
|
3975
|
+
if (!escrow) {
|
|
3976
|
+
return reply.code(404).send({ error: "Escrow record not found" });
|
|
3977
|
+
}
|
|
3978
|
+
return reply.send(escrow);
|
|
3979
|
+
});
|
|
3876
3980
|
await fastify.register(async (scope) => {
|
|
3877
3981
|
identityAuthPlugin(scope, { agentDb: creditDb });
|
|
3878
3982
|
scope.post("/api/credits/hold", {
|
|
@@ -5805,6 +5909,121 @@ function createRegistryServer(opts) {
|
|
|
5805
5909
|
throw err;
|
|
5806
5910
|
}
|
|
5807
5911
|
});
|
|
5912
|
+
ensureHubIdentitiesTables(db);
|
|
5913
|
+
try {
|
|
5914
|
+
pruneChallenges(db);
|
|
5915
|
+
} catch {
|
|
5916
|
+
}
|
|
5917
|
+
api.get("/api/agents/challenge", {
|
|
5918
|
+
schema: {
|
|
5919
|
+
tags: ["hub-auth"],
|
|
5920
|
+
summary: "Get a registration challenge",
|
|
5921
|
+
response: {
|
|
5922
|
+
200: {
|
|
5923
|
+
type: "object",
|
|
5924
|
+
properties: {
|
|
5925
|
+
challenge: { type: "string" },
|
|
5926
|
+
expires_at: { type: "string" }
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
}
|
|
5931
|
+
}, async (_request, reply) => {
|
|
5932
|
+
const { challenge, expires_at } = createChallenge(db);
|
|
5933
|
+
return reply.send({ challenge, expires_at });
|
|
5934
|
+
});
|
|
5935
|
+
api.post("/api/agents/register", {
|
|
5936
|
+
schema: {
|
|
5937
|
+
tags: ["hub-auth"],
|
|
5938
|
+
summary: "Register a new Hub-managed agent identity",
|
|
5939
|
+
body: {
|
|
5940
|
+
type: "object",
|
|
5941
|
+
required: ["email", "public_key", "encrypted_private_key", "kdf_salt", "display_name", "challenge", "signature"],
|
|
5942
|
+
properties: {
|
|
5943
|
+
email: { type: "string", format: "email" },
|
|
5944
|
+
public_key: { type: "string" },
|
|
5945
|
+
encrypted_private_key: { type: "string" },
|
|
5946
|
+
kdf_salt: { type: "string" },
|
|
5947
|
+
display_name: { type: "string" },
|
|
5948
|
+
challenge: { type: "string" },
|
|
5949
|
+
signature: { type: "string" }
|
|
5950
|
+
}
|
|
5951
|
+
},
|
|
5952
|
+
response: {
|
|
5953
|
+
201: { type: "object", additionalProperties: true },
|
|
5954
|
+
400: { type: "object", properties: { error: { type: "string" } } },
|
|
5955
|
+
409: { type: "object", properties: { error: { type: "string" } } }
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
}, async (request, reply) => {
|
|
5959
|
+
const body = request.body;
|
|
5960
|
+
if (!consumeChallenge(db, body.challenge)) {
|
|
5961
|
+
return reply.code(400).send({ error: "Invalid or expired challenge" });
|
|
5962
|
+
}
|
|
5963
|
+
if (!/^[0-9a-fA-F]+$/.test(body.public_key) || body.public_key.length % 2 !== 0) {
|
|
5964
|
+
return reply.code(400).send({ error: "Invalid public_key format" });
|
|
5965
|
+
}
|
|
5966
|
+
try {
|
|
5967
|
+
const { verifyEscrowReceipt: verifyEscrowReceipt2 } = await import("../../signing-AQTKYJDB.js");
|
|
5968
|
+
const publicKeyBuffer = Buffer.from(body.public_key, "hex");
|
|
5969
|
+
const valid = verifyEscrowReceipt2({ challenge: body.challenge }, body.signature, publicKeyBuffer);
|
|
5970
|
+
if (!valid) {
|
|
5971
|
+
return reply.code(400).send({ error: "Invalid signature" });
|
|
5972
|
+
}
|
|
5973
|
+
} catch (err) {
|
|
5974
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5975
|
+
return reply.code(400).send({ error: `Signature verification failed: ${msg}` });
|
|
5976
|
+
}
|
|
5977
|
+
const existing = getHubIdentityByEmail(db, body.email.toLowerCase());
|
|
5978
|
+
if (existing) {
|
|
5979
|
+
return reply.code(409).send({ error: "Email already registered" });
|
|
5980
|
+
}
|
|
5981
|
+
const agent_id = deriveAgentId2(body.public_key);
|
|
5982
|
+
const existingByAgentId = getHubIdentityByAgentId(db, agent_id);
|
|
5983
|
+
if (existingByAgentId) {
|
|
5984
|
+
return reply.code(409).send({ error: "Agent already registered" });
|
|
5985
|
+
}
|
|
5986
|
+
const identity = registerHubIdentity(db, {
|
|
5987
|
+
email: body.email.toLowerCase(),
|
|
5988
|
+
public_key: body.public_key,
|
|
5989
|
+
encrypted_private_key: body.encrypted_private_key,
|
|
5990
|
+
kdf_salt: body.kdf_salt,
|
|
5991
|
+
display_name: body.display_name
|
|
5992
|
+
});
|
|
5993
|
+
return reply.code(201).send({
|
|
5994
|
+
agent_id: identity.agent_id,
|
|
5995
|
+
did: `did:agentbnb:${identity.agent_id}`,
|
|
5996
|
+
created_at: identity.created_at
|
|
5997
|
+
});
|
|
5998
|
+
});
|
|
5999
|
+
api.post("/api/agents/login", {
|
|
6000
|
+
schema: {
|
|
6001
|
+
tags: ["hub-auth"],
|
|
6002
|
+
summary: "Fetch encrypted identity blob for login",
|
|
6003
|
+
body: {
|
|
6004
|
+
type: "object",
|
|
6005
|
+
required: ["email"],
|
|
6006
|
+
properties: { email: { type: "string", format: "email" } }
|
|
6007
|
+
},
|
|
6008
|
+
response: {
|
|
6009
|
+
200: { type: "object", additionalProperties: true },
|
|
6010
|
+
404: { type: "object", properties: { error: { type: "string" } } }
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6013
|
+
}, async (request, reply) => {
|
|
6014
|
+
const body = request.body;
|
|
6015
|
+
const identity = getHubIdentityByEmail(db, body.email.toLowerCase());
|
|
6016
|
+
if (!identity) {
|
|
6017
|
+
return reply.code(404).send({ error: "Identity not found" });
|
|
6018
|
+
}
|
|
6019
|
+
return reply.send({
|
|
6020
|
+
agent_id: identity.agent_id,
|
|
6021
|
+
public_key: identity.public_key,
|
|
6022
|
+
encrypted_private_key: identity.encrypted_private_key,
|
|
6023
|
+
kdf_salt: identity.kdf_salt,
|
|
6024
|
+
display_name: identity.display_name
|
|
6025
|
+
});
|
|
6026
|
+
});
|
|
5808
6027
|
api.post("/api/identity/link", {
|
|
5809
6028
|
schema: {
|
|
5810
6029
|
tags: ["identity"],
|
|
@@ -6104,7 +6323,7 @@ function createRegistryServer(opts) {
|
|
|
6104
6323
|
});
|
|
6105
6324
|
await relayClient.connect();
|
|
6106
6325
|
}
|
|
6107
|
-
const { requestViaRelay: requestViaRelay2 } = await import("../../client-
|
|
6326
|
+
const { requestViaRelay: requestViaRelay2 } = await import("../../client-KL67WZVJ.js");
|
|
6108
6327
|
return requestViaRelay2(relayClient, {
|
|
6109
6328
|
targetOwner: target.owner,
|
|
6110
6329
|
cardId: target.cardId,
|
|
@@ -6123,12 +6342,24 @@ function createRegistryServer(opts) {
|
|
|
6123
6342
|
const ownerApiKey = opts.ownerApiKey;
|
|
6124
6343
|
const ownerName = opts.ownerName;
|
|
6125
6344
|
void api.register(async (ownerRoutes) => {
|
|
6126
|
-
ownerRoutes.addHook("
|
|
6345
|
+
ownerRoutes.addHook("preHandler", async (request, reply) => {
|
|
6127
6346
|
const auth = request.headers.authorization;
|
|
6128
6347
|
const token = auth?.startsWith("Bearer ") ? auth.slice(7).trim() : null;
|
|
6129
|
-
if (
|
|
6130
|
-
|
|
6348
|
+
if (token === ownerApiKey) {
|
|
6349
|
+
request.agentId = ownerName;
|
|
6350
|
+
return;
|
|
6351
|
+
}
|
|
6352
|
+
const didResult = await tryVerifyIdentity(request, {});
|
|
6353
|
+
if (didResult.valid) {
|
|
6354
|
+
const hubIdentity = getHubIdentityByAgentId(db, didResult.agentId);
|
|
6355
|
+
if (!hubIdentity) {
|
|
6356
|
+
return reply.status(401).send({ error: "Agent not registered on this Hub" });
|
|
6357
|
+
}
|
|
6358
|
+
request.agentId = didResult.agentId;
|
|
6359
|
+
request.agentPublicKey = didResult.publicKey;
|
|
6360
|
+
return;
|
|
6131
6361
|
}
|
|
6362
|
+
return reply.status(401).send({ error: "Unauthorized" });
|
|
6132
6363
|
});
|
|
6133
6364
|
ownerRoutes.get("/me", {
|
|
6134
6365
|
schema: {
|
|
@@ -6139,13 +6370,14 @@ function createRegistryServer(opts) {
|
|
|
6139
6370
|
200: { type: "object", properties: { owner: { type: "string" }, balance: { type: "number" } } }
|
|
6140
6371
|
}
|
|
6141
6372
|
}
|
|
6142
|
-
}, async (
|
|
6373
|
+
}, async (request, reply) => {
|
|
6374
|
+
const identity = request.agentId ?? ownerName;
|
|
6143
6375
|
let balance = 0;
|
|
6144
6376
|
if (opts.creditDb) {
|
|
6145
6377
|
const ledger = createLedger({ db: opts.creditDb });
|
|
6146
|
-
balance = await ledger.getBalance(
|
|
6378
|
+
balance = await ledger.getBalance(identity);
|
|
6147
6379
|
}
|
|
6148
|
-
return reply.send({ owner:
|
|
6380
|
+
return reply.send({ owner: identity, balance });
|
|
6149
6381
|
});
|
|
6150
6382
|
ownerRoutes.get("/requests", {
|
|
6151
6383
|
schema: {
|
|
@@ -6767,6 +6999,56 @@ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
|
6767
6999
|
import { join as join4 } from "path";
|
|
6768
7000
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
6769
7001
|
import { Cron as Cron2 } from "croner";
|
|
7002
|
+
|
|
7003
|
+
// src/utils/runtime-mode.ts
|
|
7004
|
+
function isTestMode() {
|
|
7005
|
+
return process.env["AGENTBNB_TEST_MODE"] === "1" || process.env["NODE_ENV"] === "test" || process.env["VITEST"] === "true";
|
|
7006
|
+
}
|
|
7007
|
+
function isOfflineMode() {
|
|
7008
|
+
return process.env["AGENTBNB_OFFLINE"] === "1";
|
|
7009
|
+
}
|
|
7010
|
+
function shouldSkipNetwork() {
|
|
7011
|
+
return isTestMode() || isOfflineMode();
|
|
7012
|
+
}
|
|
7013
|
+
|
|
7014
|
+
// src/utils/network-probe.ts
|
|
7015
|
+
var PROBE_TIMEOUT_MS = 2e3;
|
|
7016
|
+
async function probeRegistry(registryUrl, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
7017
|
+
if (shouldSkipNetwork()) return false;
|
|
7018
|
+
const controller = new AbortController();
|
|
7019
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
7020
|
+
try {
|
|
7021
|
+
const url = `${registryUrl.replace(/\/$/, "")}/health`;
|
|
7022
|
+
const res = await fetch(url, { method: "GET", signal: controller.signal });
|
|
7023
|
+
return res.ok;
|
|
7024
|
+
} catch {
|
|
7025
|
+
return false;
|
|
7026
|
+
} finally {
|
|
7027
|
+
clearTimeout(timer);
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
|
|
7031
|
+
// src/utils/with-timeout.ts
|
|
7032
|
+
var TimeoutError = class extends Error {
|
|
7033
|
+
constructor(timeoutMs) {
|
|
7034
|
+
super(`Operation timed out after ${timeoutMs}ms`);
|
|
7035
|
+
this.name = "TimeoutError";
|
|
7036
|
+
}
|
|
7037
|
+
};
|
|
7038
|
+
async function withTimeout(promise, timeoutMs) {
|
|
7039
|
+
let timer;
|
|
7040
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
7041
|
+
timer = setTimeout(() => reject(new TimeoutError(timeoutMs)), timeoutMs);
|
|
7042
|
+
});
|
|
7043
|
+
try {
|
|
7044
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
7045
|
+
} finally {
|
|
7046
|
+
if (timer) clearTimeout(timer);
|
|
7047
|
+
}
|
|
7048
|
+
}
|
|
7049
|
+
|
|
7050
|
+
// src/runtime/service-coordinator.ts
|
|
7051
|
+
var STARTUP_SYNC_BUDGET_MS = 3e3;
|
|
6770
7052
|
function buildFallbackRelayCard(owner) {
|
|
6771
7053
|
return {
|
|
6772
7054
|
id: randomUUID9(),
|
|
@@ -6970,11 +7252,28 @@ var ServiceCoordinator = class {
|
|
|
6970
7252
|
this.runtime.registerJob(idleJob);
|
|
6971
7253
|
console.log("IdleMonitor started (60s poll interval, 70% idle threshold)");
|
|
6972
7254
|
if (this.config.registry) {
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
console.log(`[agentbnb] credits synced: ${startupSync.remoteBalance} (was ${startupSync.localWas})`);
|
|
7255
|
+
if (shouldSkipNetwork()) {
|
|
7256
|
+
console.warn("[agentbnb] credit sync skipped: test/offline mode");
|
|
6976
7257
|
} else {
|
|
6977
|
-
|
|
7258
|
+
const reachable = await probeRegistry(this.config.registry);
|
|
7259
|
+
if (!reachable) {
|
|
7260
|
+
console.warn("[agentbnb] credit sync skipped: registry unreachable (will retry every 5m)");
|
|
7261
|
+
} else {
|
|
7262
|
+
try {
|
|
7263
|
+
const startupSync = await withTimeout(
|
|
7264
|
+
syncCreditsFromRegistry(this.config, this.runtime.creditDb),
|
|
7265
|
+
STARTUP_SYNC_BUDGET_MS
|
|
7266
|
+
);
|
|
7267
|
+
if (startupSync.synced) {
|
|
7268
|
+
console.log(`[agentbnb] credits synced: ${startupSync.remoteBalance} (was ${startupSync.localWas})`);
|
|
7269
|
+
} else {
|
|
7270
|
+
console.warn(`[agentbnb] credit sync skipped: ${startupSync.error}`);
|
|
7271
|
+
}
|
|
7272
|
+
} catch (err) {
|
|
7273
|
+
const reason = err instanceof TimeoutError ? `timeout after ${STARTUP_SYNC_BUDGET_MS}ms` : err.message;
|
|
7274
|
+
console.warn(`[agentbnb] credit sync skipped: ${reason} (will retry every 5m)`);
|
|
7275
|
+
}
|
|
7276
|
+
}
|
|
6978
7277
|
}
|
|
6979
7278
|
this.creditSyncJob = new Cron2("*/5 * * * *", async () => {
|
|
6980
7279
|
const result = await syncCreditsFromRegistry(this.config, this.runtime.creditDb);
|
|
@@ -7015,7 +7314,7 @@ var ServiceCoordinator = class {
|
|
|
7015
7314
|
}
|
|
7016
7315
|
if (opts.registryUrl && opts.relay) {
|
|
7017
7316
|
const { RelayClient: RelayClient2 } = await import("../../websocket-client-RT4KLJL4.js");
|
|
7018
|
-
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-
|
|
7317
|
+
const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-YMPHTJPN.js");
|
|
7019
7318
|
const localCards = listCards(this.runtime.registryDb, this.config.owner);
|
|
7020
7319
|
const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
|
|
7021
7320
|
if (this.config.conductor?.public) {
|
|
@@ -7761,6 +8060,56 @@ async function handleDiscover(args, ctx) {
|
|
|
7761
8060
|
|
|
7762
8061
|
// src/mcp/tools/request.ts
|
|
7763
8062
|
import { z as z9 } from "zod";
|
|
8063
|
+
|
|
8064
|
+
// src/autonomy/consumer-autonomy.ts
|
|
8065
|
+
var DEFAULT_CONSUMER_AUTONOMY = {
|
|
8066
|
+
session_budget: 50,
|
|
8067
|
+
single_request_max: 20,
|
|
8068
|
+
multi_skill_policy: "notify"
|
|
8069
|
+
};
|
|
8070
|
+
function createSessionState() {
|
|
8071
|
+
return { totalSpent: 0, paidCallCount: 0 };
|
|
8072
|
+
}
|
|
8073
|
+
function checkConsumerBudget(config, session, estimatedCost) {
|
|
8074
|
+
if (estimatedCost <= 0) {
|
|
8075
|
+
return { allowed: true };
|
|
8076
|
+
}
|
|
8077
|
+
if (estimatedCost > config.single_request_max) {
|
|
8078
|
+
return {
|
|
8079
|
+
allowed: false,
|
|
8080
|
+
error: `Request cost (${estimatedCost} credits) exceeds single_request_max (${config.single_request_max}). Adjust consumer_autonomy.single_request_max in config to allow higher-cost requests.`
|
|
8081
|
+
};
|
|
8082
|
+
}
|
|
8083
|
+
if (session.totalSpent + estimatedCost > config.session_budget) {
|
|
8084
|
+
return {
|
|
8085
|
+
allowed: false,
|
|
8086
|
+
error: `Session budget exceeded: spent ${session.totalSpent} + requested ${estimatedCost} = ${session.totalSpent + estimatedCost} credits, but session_budget is ${config.session_budget}. This session has already made ${session.paidCallCount} paid call(s).`
|
|
8087
|
+
};
|
|
8088
|
+
}
|
|
8089
|
+
if (session.paidCallCount > 0) {
|
|
8090
|
+
if (config.multi_skill_policy === "block") {
|
|
8091
|
+
return {
|
|
8092
|
+
allowed: false,
|
|
8093
|
+
error: `Multi-skill block: this would be paid call #${session.paidCallCount + 1} in this session (total spent: ${session.totalSpent}, this request: ${estimatedCost} credits). consumer_autonomy.multi_skill_policy is "block". Only one paid skill call is allowed per session unless policy is changed.`
|
|
8094
|
+
};
|
|
8095
|
+
}
|
|
8096
|
+
if (config.multi_skill_policy === "notify") {
|
|
8097
|
+
return {
|
|
8098
|
+
allowed: true,
|
|
8099
|
+
warning: `This is paid call #${session.paidCallCount + 1} in this session. Cumulative spend: ${session.totalSpent} + ${estimatedCost} = ${session.totalSpent + estimatedCost} credits (session budget: ${config.session_budget}).`
|
|
8100
|
+
};
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
8103
|
+
return { allowed: true };
|
|
8104
|
+
}
|
|
8105
|
+
function recordConsumerSpend(session, creditsSpent) {
|
|
8106
|
+
if (creditsSpent > 0) {
|
|
8107
|
+
session.totalSpent += creditsSpent;
|
|
8108
|
+
session.paidCallCount += 1;
|
|
8109
|
+
}
|
|
8110
|
+
}
|
|
8111
|
+
|
|
8112
|
+
// src/mcp/tools/request.ts
|
|
7764
8113
|
var requestInputSchema = {
|
|
7765
8114
|
query: z9.string().optional().describe("Search query to find a matching capability (auto-request mode)"),
|
|
7766
8115
|
card_id: z9.string().optional().describe("Direct card ID to request (skips search)"),
|
|
@@ -7798,7 +8147,17 @@ function deriveTimeoutHintFromCard(remoteCard, skillId) {
|
|
|
7798
8147
|
async function handleRequest(args, ctx) {
|
|
7799
8148
|
try {
|
|
7800
8149
|
const maxCost = args.max_cost ?? 50;
|
|
8150
|
+
const consumerConfig = ctx.config.consumer_autonomy ?? DEFAULT_CONSUMER_AUTONOMY;
|
|
8151
|
+
if (!ctx.consumerSession) {
|
|
8152
|
+
ctx.consumerSession = createSessionState();
|
|
8153
|
+
}
|
|
7801
8154
|
if (args.query) {
|
|
8155
|
+
const budgetCheck = checkConsumerBudget(consumerConfig, ctx.consumerSession, maxCost);
|
|
8156
|
+
if (!budgetCheck.allowed) {
|
|
8157
|
+
return {
|
|
8158
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: budgetCheck.error, budget_exceeded: true }) }]
|
|
8159
|
+
};
|
|
8160
|
+
}
|
|
7802
8161
|
const registryDb = openDatabase(ctx.config.db_path);
|
|
7803
8162
|
const creditDb = openCreditDb(ctx.config.credit_db_path);
|
|
7804
8163
|
registryDb.pragma("busy_timeout = 5000");
|
|
@@ -7822,8 +8181,12 @@ async function handleRequest(args, ctx) {
|
|
|
7822
8181
|
maxCostCredits: maxCost,
|
|
7823
8182
|
params: args.params
|
|
7824
8183
|
});
|
|
8184
|
+
const creditsUsed = typeof result?.creditsSpent === "number" ? result.creditsSpent : 0;
|
|
8185
|
+
recordConsumerSpend(ctx.consumerSession, creditsUsed);
|
|
8186
|
+
const response = { success: true, ...result };
|
|
8187
|
+
if (budgetCheck.warning) response.spend_warning = budgetCheck.warning;
|
|
7825
8188
|
return {
|
|
7826
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
8189
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
7827
8190
|
};
|
|
7828
8191
|
} finally {
|
|
7829
8192
|
registryDb.close();
|
|
@@ -7890,17 +8253,23 @@ async function handleRequest(args, ctx) {
|
|
|
7890
8253
|
const targetAgentId = typeof remoteCard["agent_id"] === "string" ? remoteCard["agent_id"] : void 0;
|
|
7891
8254
|
const gatewayUrl = remoteCard["gateway_url"];
|
|
7892
8255
|
const timeoutHint = deriveTimeoutHintFromCard(remoteCard, args.skill_id);
|
|
8256
|
+
let remoteCost = 0;
|
|
8257
|
+
const remoteSkills = remoteCard["skills"];
|
|
8258
|
+
if (Array.isArray(remoteSkills)) {
|
|
8259
|
+
const matchedSkill = args.skill_id ? remoteSkills.find((s) => s.id === args.skill_id) : remoteSkills[0];
|
|
8260
|
+
remoteCost = matchedSkill?.pricing?.credits_per_call ?? 0;
|
|
8261
|
+
} else {
|
|
8262
|
+
const remotePricing = remoteCard["pricing"];
|
|
8263
|
+
remoteCost = remotePricing?.credits_per_call ?? 0;
|
|
8264
|
+
}
|
|
7893
8265
|
if (gatewayUrl) {
|
|
7894
|
-
let remoteCost = 0;
|
|
7895
|
-
const remoteSkills = remoteCard["skills"];
|
|
7896
|
-
if (Array.isArray(remoteSkills)) {
|
|
7897
|
-
const matchedSkill = args.skill_id ? remoteSkills.find((s) => s.id === args.skill_id) : remoteSkills[0];
|
|
7898
|
-
remoteCost = matchedSkill?.pricing?.credits_per_call ?? 0;
|
|
7899
|
-
} else {
|
|
7900
|
-
const remotePricing = remoteCard["pricing"];
|
|
7901
|
-
remoteCost = remotePricing?.credits_per_call ?? 0;
|
|
7902
|
-
}
|
|
7903
8266
|
if (remoteCost > 0) {
|
|
8267
|
+
const budgetCheck = checkConsumerBudget(consumerConfig, ctx.consumerSession, remoteCost);
|
|
8268
|
+
if (!budgetCheck.allowed) {
|
|
8269
|
+
return {
|
|
8270
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: budgetCheck.error, budget_exceeded: true }) }]
|
|
8271
|
+
};
|
|
8272
|
+
}
|
|
7904
8273
|
if (!targetOwner) {
|
|
7905
8274
|
return {
|
|
7906
8275
|
content: [{ type: "text", text: JSON.stringify({ success: false, error: "Paid remote request requires a target owner for relay routing" }) }]
|
|
@@ -7917,8 +8286,11 @@ async function handleRequest(args, ctx) {
|
|
|
7917
8286
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {}, requester: ctx.config.owner },
|
|
7918
8287
|
timeoutMs: args.timeout_ms
|
|
7919
8288
|
});
|
|
8289
|
+
recordConsumerSpend(ctx.consumerSession, remoteCost);
|
|
8290
|
+
const response = { success: true, result, creditsSpent: remoteCost };
|
|
8291
|
+
if (budgetCheck.warning) response.spend_warning = budgetCheck.warning;
|
|
7920
8292
|
return {
|
|
7921
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
8293
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
7922
8294
|
};
|
|
7923
8295
|
} else {
|
|
7924
8296
|
const result = await requestCapability({
|
|
@@ -7936,6 +8308,14 @@ async function handleRequest(args, ctx) {
|
|
|
7936
8308
|
}
|
|
7937
8309
|
}
|
|
7938
8310
|
if (targetOwner) {
|
|
8311
|
+
if (remoteCost > 0) {
|
|
8312
|
+
const budgetCheck = checkConsumerBudget(consumerConfig, ctx.consumerSession, remoteCost);
|
|
8313
|
+
if (!budgetCheck.allowed) {
|
|
8314
|
+
return {
|
|
8315
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: budgetCheck.error, budget_exceeded: true }) }]
|
|
8316
|
+
};
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
7939
8319
|
const result = await requestViaTemporaryRelay({
|
|
7940
8320
|
registryUrl: ctx.config.registry,
|
|
7941
8321
|
owner: ctx.config.owner,
|
|
@@ -7947,8 +8327,13 @@ async function handleRequest(args, ctx) {
|
|
|
7947
8327
|
params: { ...args.params ?? {}, ...args.skill_id ? { skill_id: args.skill_id } : {} },
|
|
7948
8328
|
timeoutMs: args.timeout_ms
|
|
7949
8329
|
});
|
|
8330
|
+
if (remoteCost > 0) {
|
|
8331
|
+
recordConsumerSpend(ctx.consumerSession, remoteCost);
|
|
8332
|
+
}
|
|
8333
|
+
const response = { success: true, result };
|
|
8334
|
+
if (remoteCost > 0) response.creditsSpent = remoteCost;
|
|
7950
8335
|
return {
|
|
7951
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
8336
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
7952
8337
|
};
|
|
7953
8338
|
}
|
|
7954
8339
|
return {
|
|
@@ -8059,7 +8444,7 @@ async function conductAction(task, opts) {
|
|
|
8059
8444
|
);
|
|
8060
8445
|
};
|
|
8061
8446
|
let relay;
|
|
8062
|
-
if (config.registry) {
|
|
8447
|
+
if (config.registry && !shouldSkipNetwork()) {
|
|
8063
8448
|
relay = new RelayClient({
|
|
8064
8449
|
registryUrl: config.registry,
|
|
8065
8450
|
owner: config.owner,
|
|
@@ -8069,8 +8454,10 @@ async function conductAction(task, opts) {
|
|
|
8069
8454
|
silent: true
|
|
8070
8455
|
});
|
|
8071
8456
|
try {
|
|
8072
|
-
await relay.connect();
|
|
8073
|
-
} catch {
|
|
8457
|
+
await withTimeout(relay.connect(), 1e4);
|
|
8458
|
+
} catch (err) {
|
|
8459
|
+
if (err instanceof TimeoutError) {
|
|
8460
|
+
}
|
|
8074
8461
|
relay = void 0;
|
|
8075
8462
|
}
|
|
8076
8463
|
}
|
|
@@ -12,11 +12,11 @@ import {
|
|
|
12
12
|
updateReputation,
|
|
13
13
|
updateSkillAvailability,
|
|
14
14
|
updateSkillIdleRate
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-J4RFJVXI.js";
|
|
17
|
-
import "./chunk-UVCNMRPS.js";
|
|
15
|
+
} from "./chunk-QE42IJC4.js";
|
|
18
16
|
import "./chunk-4XTYT4JW.js";
|
|
19
17
|
import "./chunk-GZUTU6IZ.js";
|
|
18
|
+
import "./chunk-J4RFJVXI.js";
|
|
19
|
+
import "./chunk-UVCNMRPS.js";
|
|
20
20
|
import "./chunk-3RG5ZIWI.js";
|
|
21
21
|
export {
|
|
22
22
|
attachCanonicalAgentId,
|