@atbash/sdk 0.3.6 → 0.3.7
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/index.cjs +268 -5
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +262 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
DEFAULT_CHROMIA_NODE_URLS: () => DEFAULT_CHROMIA_NODE_URLS,
|
|
35
35
|
DEFAULT_ENDPOINT: () => DEFAULT_ENDPOINT,
|
|
36
36
|
checkAgentExists: () => checkAgentExists,
|
|
37
|
+
createAtbashClient: () => createAtbashClient,
|
|
37
38
|
derivePublicKey: () => derivePublicKey,
|
|
38
39
|
generateKeyPair: () => generateKeyPair,
|
|
39
40
|
getAgentDetail: () => getAgentDetail,
|
|
@@ -51,15 +52,47 @@ __export(index_exports, {
|
|
|
51
52
|
isValidPrivateKey: () => isValidPrivateKey,
|
|
52
53
|
judgeAction: () => judgeAction,
|
|
53
54
|
loadAgent: () => loadAgent,
|
|
55
|
+
loadAgentFromFile: () => loadAgentFromFile,
|
|
54
56
|
logToolCall: () => logToolCall,
|
|
55
|
-
|
|
57
|
+
resolveKeyPath: () => resolveKeyPath,
|
|
58
|
+
toPubkeyHex: () => toPubkeyHex,
|
|
59
|
+
validateJudgeEndpoint: () => validateJudgeEndpoint,
|
|
60
|
+
verifyJudgeResponseSignature: () => verifyJudgeResponseSignature
|
|
56
61
|
});
|
|
57
62
|
module.exports = __toCommonJS(index_exports);
|
|
58
63
|
|
|
59
64
|
// src/client.ts
|
|
60
65
|
var import_crypto = require("crypto");
|
|
66
|
+
var import_postchain_client2 = __toESM(require("postchain-client"), 1);
|
|
67
|
+
|
|
68
|
+
// src/signature.ts
|
|
61
69
|
var import_postchain_client = __toESM(require("postchain-client"), 1);
|
|
62
|
-
var {
|
|
70
|
+
var { encryption } = import_postchain_client.default;
|
|
71
|
+
function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
|
|
72
|
+
if (!signatureHex) {
|
|
73
|
+
return { ok: false, reason: "missing X-Atbash-Signature header" };
|
|
74
|
+
}
|
|
75
|
+
const sigClean = signatureHex.trim().toLowerCase().replace(/^0x/, "");
|
|
76
|
+
if (!/^[0-9a-f]+$/.test(sigClean) || sigClean.length < 64 || sigClean.length > 256) {
|
|
77
|
+
return { ok: false, reason: "malformed signature header" };
|
|
78
|
+
}
|
|
79
|
+
let isValid = false;
|
|
80
|
+
try {
|
|
81
|
+
const digest = encryption.sha256(Buffer.from(bodyBytes));
|
|
82
|
+
const pubKeyBytes = Buffer.from(pubKeyHex.replace(/^0x/, ""), "hex");
|
|
83
|
+
const sigBytes = Buffer.from(sigClean, "hex");
|
|
84
|
+
isValid = encryption.checkDigestSignature(digest, pubKeyBytes, sigBytes);
|
|
85
|
+
} catch (err) {
|
|
86
|
+
const message = String(
|
|
87
|
+
err?.message ?? err ?? ""
|
|
88
|
+
);
|
|
89
|
+
return { ok: false, reason: `signature verification threw: ${message}` };
|
|
90
|
+
}
|
|
91
|
+
return isValid ? { ok: true } : { ok: false, reason: "signature does not verify against configured verifyPubKey" };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/client.ts
|
|
95
|
+
var { createClient, encryption: encryption2, newSignatureProvider } = import_postchain_client2.default;
|
|
63
96
|
var DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
64
97
|
var DEFAULT_CHROMIA_NODE_URLS = [
|
|
65
98
|
"https://node6.testnet.chromia.com:7740",
|
|
@@ -115,7 +148,7 @@ async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
|
115
148
|
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
116
149
|
const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
|
|
117
150
|
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
118
|
-
const keyPair =
|
|
151
|
+
const keyPair = encryption2.makeKeyPair(privKeyBuf);
|
|
119
152
|
const sigProvider = newSignatureProvider({
|
|
120
153
|
privKey: keyPair.privKey,
|
|
121
154
|
pubKey: keyPair.pubKey
|
|
@@ -226,6 +259,31 @@ async function getJson(url, opts) {
|
|
|
226
259
|
}
|
|
227
260
|
return resp.json();
|
|
228
261
|
}
|
|
262
|
+
async function postJudgeRequest(url, body, opts) {
|
|
263
|
+
if (!opts?.verifyPubKey) {
|
|
264
|
+
return postJson(url, body, opts);
|
|
265
|
+
}
|
|
266
|
+
const resp = await fetch(url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: { "Content-Type": "application/json" },
|
|
269
|
+
body: JSON.stringify(body),
|
|
270
|
+
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
271
|
+
});
|
|
272
|
+
if (!resp.ok) {
|
|
273
|
+
const text = await resp.text().catch(() => "");
|
|
274
|
+
throw enrichError(resp.status, text, resp.statusText, opts);
|
|
275
|
+
}
|
|
276
|
+
const buf = new Uint8Array(await resp.arrayBuffer());
|
|
277
|
+
const verdict = verifyJudgeResponseSignature(
|
|
278
|
+
buf,
|
|
279
|
+
resp.headers.get("X-Atbash-Signature"),
|
|
280
|
+
opts.verifyPubKey
|
|
281
|
+
);
|
|
282
|
+
if (!verdict.ok) {
|
|
283
|
+
throw new Error(`signature verification failed: ${verdict.reason}`);
|
|
284
|
+
}
|
|
285
|
+
return JSON.parse(new TextDecoder().decode(buf));
|
|
286
|
+
}
|
|
229
287
|
async function judgeAction(action, context = "", auth, opts) {
|
|
230
288
|
if (!action || !action.trim()) {
|
|
231
289
|
throw new Error("action is required and cannot be empty.");
|
|
@@ -263,7 +321,7 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
263
321
|
...opts?.toolName && { tool_name: opts.toolName },
|
|
264
322
|
...opts?.model && { model: opts.model }
|
|
265
323
|
};
|
|
266
|
-
const data = await
|
|
324
|
+
const data = await postJudgeRequest(url, body, opts);
|
|
267
325
|
return {
|
|
268
326
|
verdict: normalizeVerdict(data.verdict),
|
|
269
327
|
action_type: String(data.action_type || ""),
|
|
@@ -390,12 +448,213 @@ async function getSafetyStats(opts) {
|
|
|
390
448
|
const result = await getJson(url, opts);
|
|
391
449
|
return result?.data || result;
|
|
392
450
|
}
|
|
451
|
+
|
|
452
|
+
// src/config.ts
|
|
453
|
+
var ALLOWED_JUDGE_HOSTS = /* @__PURE__ */ new Set([
|
|
454
|
+
"atbash.ai",
|
|
455
|
+
"www.atbash.ai"
|
|
456
|
+
]);
|
|
457
|
+
function validateJudgeEndpoint(judge) {
|
|
458
|
+
const policy = judge?.policy === "self-hosted" ? "self-hosted" : "default";
|
|
459
|
+
const candidate = judge?.endpoint?.trim() || DEFAULT_ENDPOINT;
|
|
460
|
+
let parsed;
|
|
461
|
+
try {
|
|
462
|
+
parsed = new URL(candidate);
|
|
463
|
+
} catch {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`[atbash] invalid judge endpoint URL: ${candidate}. Refusing to load \u2014 fix the URL or omit it to use the default (${DEFAULT_ENDPOINT}).`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
if (parsed.protocol !== "https:") {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`[atbash] judge endpoint must use https:// (got "${parsed.protocol}"). Refusing to load \u2014 plaintext endpoints leak verdicts and enable trivial MITM bypass.`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
if (parsed.username || parsed.password) {
|
|
474
|
+
throw new Error(
|
|
475
|
+
`[atbash] judge endpoint must not contain credentials (user:pass@host). Refusing to load \u2014 credentials embedded in URLs leak to logs and process listings.`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
const normalisedUrl = parsed.origin;
|
|
479
|
+
if (policy === "self-hosted") {
|
|
480
|
+
const verifyPubKey = judge?.verifyPubKey;
|
|
481
|
+
const key = verifyPubKey?.trim().toLowerCase();
|
|
482
|
+
if (!key || !/^[0-9a-f]{66}$/.test(key)) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`[atbash] judge endpoint policy "self-hosted" requires verifyPubKey to be a 66-hex-char compressed secp256k1 pubkey. Refusing to load \u2014 self-hosted judges must produce signed responses so the SDK can detect a malicious or compromised judge.`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
return { url: normalisedUrl, policy, verifyPubKey: key };
|
|
488
|
+
}
|
|
489
|
+
if (!ALLOWED_JUDGE_HOSTS.has(parsed.hostname.toLowerCase())) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`[atbash] judge endpoint hostname "${parsed.hostname}" is not in the trusted allowlist. Allowed: ${[...ALLOWED_JUDGE_HOSTS].join(", ")}. To use a self-hosted judge, set BOTH policy="self-hosted" AND verifyPubKey to the 66-hex pubkey of your judge's response-signing key. Refusing to load \u2014 silent endpoint redirection is a known attack vector (F-003).`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
return { url: normalisedUrl, policy, verifyPubKey: null };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/key-loader.ts
|
|
498
|
+
var import_node_fs = require("fs");
|
|
499
|
+
var import_node_os = require("os");
|
|
500
|
+
var import_node_path = require("path");
|
|
501
|
+
var DEFAULT_KEY_PATH_REL = ".config/atbash/guard-client-key";
|
|
502
|
+
function resolveKeyPath(input) {
|
|
503
|
+
if (input) return expandHome(input);
|
|
504
|
+
const home = process.env.HOME || (0, import_node_os.homedir)() || "";
|
|
505
|
+
return (0, import_node_path.join)(home, DEFAULT_KEY_PATH_REL);
|
|
506
|
+
}
|
|
507
|
+
function expandHome(p) {
|
|
508
|
+
if (!p.startsWith("~/")) return p;
|
|
509
|
+
const home = process.env.HOME || (0, import_node_os.homedir)() || "";
|
|
510
|
+
return (0, import_node_path.join)(home, p.slice(2));
|
|
511
|
+
}
|
|
512
|
+
function readKeyFile(keyPath) {
|
|
513
|
+
const content = String((0, import_node_fs.readFileSync)(keyPath, "utf8") || "").trim();
|
|
514
|
+
let privKey = "";
|
|
515
|
+
let pubKey = "";
|
|
516
|
+
if (content.startsWith("{")) {
|
|
517
|
+
const creds = JSON.parse(content);
|
|
518
|
+
privKey = String(
|
|
519
|
+
creds.privKey || creds.privkey || creds.privateKey || ""
|
|
520
|
+
).trim();
|
|
521
|
+
pubKey = String(
|
|
522
|
+
creds.pubKey || creds.pubkey || creds.publicKey || ""
|
|
523
|
+
).trim();
|
|
524
|
+
} else {
|
|
525
|
+
const lines = content.split(/\r?\n/);
|
|
526
|
+
for (const line of lines) {
|
|
527
|
+
if (line.startsWith("privkey=")) privKey = line.slice("privkey=".length).trim();
|
|
528
|
+
if (line.startsWith("pubkey=")) pubKey = line.slice("pubkey=".length).trim();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (!privKey || !pubKey) {
|
|
532
|
+
throw new Error(`atbash key file missing priv/pub key fields: ${keyPath}`);
|
|
533
|
+
}
|
|
534
|
+
privKey = privKey.replace(/^0x/, "");
|
|
535
|
+
return { privKey, pubKey };
|
|
536
|
+
}
|
|
537
|
+
function loadAgentFromFile(keyPath) {
|
|
538
|
+
const resolved = resolveKeyPath(keyPath);
|
|
539
|
+
const { privKey } = readKeyFile(resolved);
|
|
540
|
+
return loadAgent(privKey);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/factory.ts
|
|
544
|
+
function createAtbashClient(config = {}) {
|
|
545
|
+
const validated = validateJudgeEndpoint(config.judge);
|
|
546
|
+
const failClosed = config.failClosed !== false;
|
|
547
|
+
const logger = config.logger ?? {};
|
|
548
|
+
const inlineKeyPair = config.keyPair;
|
|
549
|
+
const keyPath = inlineKeyPair ? null : config.keyPath;
|
|
550
|
+
if (validated.url !== DEFAULT_ENDPOINT) {
|
|
551
|
+
logger.warn?.("[atbash] running on non-default judge endpoint", {
|
|
552
|
+
endpoint: validated.url,
|
|
553
|
+
policy: validated.policy,
|
|
554
|
+
verifying: validated.verifyPubKey ? "with response-signature pubkey configured" : "without signature verification"
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
let cachedAgent = inlineKeyPair ? loadAgent(inlineKeyPair.privKey) : null;
|
|
558
|
+
function loadAgentOnce() {
|
|
559
|
+
if (cachedAgent) return cachedAgent;
|
|
560
|
+
cachedAgent = loadAgentFromFile(keyPath ?? void 0);
|
|
561
|
+
return cachedAgent;
|
|
562
|
+
}
|
|
563
|
+
function fail(reason, toolCallId) {
|
|
564
|
+
return { allow: !failClosed, verdict: "ERROR", reason, toolCallId };
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
async auditToolCall(input) {
|
|
568
|
+
let agent;
|
|
569
|
+
try {
|
|
570
|
+
agent = loadAgentOnce();
|
|
571
|
+
} catch (err) {
|
|
572
|
+
const message = String(err?.message ?? err ?? "");
|
|
573
|
+
logger.warn?.("[atbash] failed to load key pair, blocking for safety", {
|
|
574
|
+
error: message
|
|
575
|
+
});
|
|
576
|
+
return fail("key load failed, blocking for safety");
|
|
577
|
+
}
|
|
578
|
+
const toolName = input.toolName || "unknown";
|
|
579
|
+
const argsJson = stringifyArgs(input.args);
|
|
580
|
+
const actionText = truncate(argsJson);
|
|
581
|
+
const contextText = input.context ?? toolName;
|
|
582
|
+
try {
|
|
583
|
+
logger.info?.("[atbash] judge API called", { tool: toolName });
|
|
584
|
+
const result = await judgeAction(actionText, contextText, agent, {
|
|
585
|
+
endpoint: validated.url,
|
|
586
|
+
verifyPubKey: validated.verifyPubKey ?? void 0,
|
|
587
|
+
toolName,
|
|
588
|
+
toolArgsJson: argsJson,
|
|
589
|
+
chainOpts: {
|
|
590
|
+
nodeUrls: config.nodeUrls,
|
|
591
|
+
blockchainRid: config.blockchainRid
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
if (result.verdict === "No verdict") {
|
|
595
|
+
return {
|
|
596
|
+
allow: true,
|
|
597
|
+
verdict: "ALLOW",
|
|
598
|
+
reason: result.reason || "audit tier \u2014 request logged on-chain, no AI enforcement",
|
|
599
|
+
toolCallId: result.tool_call_id
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
const action = result.action_type;
|
|
603
|
+
if (action === "block") {
|
|
604
|
+
return {
|
|
605
|
+
allow: false,
|
|
606
|
+
verdict: "BLOCK",
|
|
607
|
+
reason: result.reason,
|
|
608
|
+
toolCallId: result.tool_call_id
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
if (action === "hold_for_user_confirm") {
|
|
612
|
+
return {
|
|
613
|
+
allow: false,
|
|
614
|
+
verdict: "HOLD",
|
|
615
|
+
reason: result.reason || "held for human confirmation",
|
|
616
|
+
toolCallId: result.tool_call_id
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
if (action === "allow") {
|
|
620
|
+
const surfacedVerdict = result.verdict === "ALLOW" || result.verdict === "HOLD" || result.verdict === "BLOCK" ? result.verdict : "ALLOW";
|
|
621
|
+
return {
|
|
622
|
+
allow: true,
|
|
623
|
+
verdict: surfacedVerdict,
|
|
624
|
+
reason: result.reason,
|
|
625
|
+
toolCallId: result.tool_call_id
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
return fail("unrecognized action_type from judge", result.tool_call_id);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
const message = String(err?.message ?? err ?? "");
|
|
631
|
+
logger.warn?.("[atbash] judge API failed", { reason: message });
|
|
632
|
+
return fail(message);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function stringifyArgs(args) {
|
|
638
|
+
if (args == null) return "";
|
|
639
|
+
if (typeof args === "string") return args;
|
|
640
|
+
try {
|
|
641
|
+
return JSON.stringify(args);
|
|
642
|
+
} catch {
|
|
643
|
+
return String(args);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
var MAX_ACTION_LEN = 4e3;
|
|
647
|
+
function truncate(text) {
|
|
648
|
+
if (text.length <= MAX_ACTION_LEN) return text;
|
|
649
|
+
return text.slice(0, MAX_ACTION_LEN) + "\u2026";
|
|
650
|
+
}
|
|
393
651
|
// Annotate the CommonJS export names for ESM import in node:
|
|
394
652
|
0 && (module.exports = {
|
|
395
653
|
DEFAULT_BLOCKCHAIN_RID,
|
|
396
654
|
DEFAULT_CHROMIA_NODE_URLS,
|
|
397
655
|
DEFAULT_ENDPOINT,
|
|
398
656
|
checkAgentExists,
|
|
657
|
+
createAtbashClient,
|
|
399
658
|
derivePublicKey,
|
|
400
659
|
generateKeyPair,
|
|
401
660
|
getAgentDetail,
|
|
@@ -413,6 +672,10 @@ async function getSafetyStats(opts) {
|
|
|
413
672
|
isValidPrivateKey,
|
|
414
673
|
judgeAction,
|
|
415
674
|
loadAgent,
|
|
675
|
+
loadAgentFromFile,
|
|
416
676
|
logToolCall,
|
|
417
|
-
|
|
677
|
+
resolveKeyPath,
|
|
678
|
+
toPubkeyHex,
|
|
679
|
+
validateJudgeEndpoint,
|
|
680
|
+
verifyJudgeResponseSignature
|
|
418
681
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -40,6 +40,7 @@ interface JudgeOptions extends ClientOpts {
|
|
|
40
40
|
toolName?: string;
|
|
41
41
|
toolArgsJson?: string;
|
|
42
42
|
chainOpts?: ChainOpts;
|
|
43
|
+
verifyPubKey?: string;
|
|
43
44
|
}
|
|
44
45
|
interface JudgmentStatus {
|
|
45
46
|
status: JudgmentStatusState;
|
|
@@ -106,6 +107,46 @@ interface AgentPolicy {
|
|
|
106
107
|
is_custom: boolean;
|
|
107
108
|
default_policy: string;
|
|
108
109
|
}
|
|
110
|
+
type DecisionVerdict = "ALLOW" | "HOLD" | "BLOCK" | "ERROR";
|
|
111
|
+
interface Decision {
|
|
112
|
+
allow: boolean;
|
|
113
|
+
verdict: DecisionVerdict;
|
|
114
|
+
reason?: string;
|
|
115
|
+
toolCallId?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ToolCallInput {
|
|
118
|
+
toolName: string;
|
|
119
|
+
args?: unknown;
|
|
120
|
+
context?: string;
|
|
121
|
+
}
|
|
122
|
+
type JudgeEndpointConfig = {
|
|
123
|
+
policy?: "default";
|
|
124
|
+
endpoint?: string;
|
|
125
|
+
} | {
|
|
126
|
+
policy: "self-hosted";
|
|
127
|
+
endpoint: string;
|
|
128
|
+
verifyPubKey: string;
|
|
129
|
+
};
|
|
130
|
+
interface ValidatedEndpoint {
|
|
131
|
+
url: string;
|
|
132
|
+
policy: "default" | "self-hosted";
|
|
133
|
+
verifyPubKey: string | null;
|
|
134
|
+
}
|
|
135
|
+
interface AtbashClientConfig {
|
|
136
|
+
judge?: JudgeEndpointConfig;
|
|
137
|
+
nodeUrls?: string[];
|
|
138
|
+
blockchainRid?: string;
|
|
139
|
+
keyPath?: string;
|
|
140
|
+
keyPair?: {
|
|
141
|
+
privKey: string;
|
|
142
|
+
pubKey: string;
|
|
143
|
+
};
|
|
144
|
+
failClosed?: boolean;
|
|
145
|
+
logger?: {
|
|
146
|
+
info?(...a: unknown[]): void;
|
|
147
|
+
warn?(...a: unknown[]): void;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
109
150
|
|
|
110
151
|
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
111
152
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
@@ -148,4 +189,19 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
148
189
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
149
190
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
150
191
|
|
|
151
|
-
|
|
192
|
+
interface AtbashClient {
|
|
193
|
+
auditToolCall(input: ToolCallInput): Promise<Decision>;
|
|
194
|
+
}
|
|
195
|
+
declare function createAtbashClient(config?: AtbashClientConfig): AtbashClient;
|
|
196
|
+
|
|
197
|
+
declare function validateJudgeEndpoint(judge?: JudgeEndpointConfig): ValidatedEndpoint;
|
|
198
|
+
|
|
199
|
+
declare function resolveKeyPath(input?: string): string;
|
|
200
|
+
declare function loadAgentFromFile(keyPath?: string): AgentAuth;
|
|
201
|
+
|
|
202
|
+
declare function verifyJudgeResponseSignature(bodyBytes: Uint8Array, signatureHex: string | null, pubKeyHex: string): {
|
|
203
|
+
ok: boolean;
|
|
204
|
+
reason?: string;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, logToolCall, resolveKeyPath, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ interface JudgeOptions extends ClientOpts {
|
|
|
40
40
|
toolName?: string;
|
|
41
41
|
toolArgsJson?: string;
|
|
42
42
|
chainOpts?: ChainOpts;
|
|
43
|
+
verifyPubKey?: string;
|
|
43
44
|
}
|
|
44
45
|
interface JudgmentStatus {
|
|
45
46
|
status: JudgmentStatusState;
|
|
@@ -106,6 +107,46 @@ interface AgentPolicy {
|
|
|
106
107
|
is_custom: boolean;
|
|
107
108
|
default_policy: string;
|
|
108
109
|
}
|
|
110
|
+
type DecisionVerdict = "ALLOW" | "HOLD" | "BLOCK" | "ERROR";
|
|
111
|
+
interface Decision {
|
|
112
|
+
allow: boolean;
|
|
113
|
+
verdict: DecisionVerdict;
|
|
114
|
+
reason?: string;
|
|
115
|
+
toolCallId?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ToolCallInput {
|
|
118
|
+
toolName: string;
|
|
119
|
+
args?: unknown;
|
|
120
|
+
context?: string;
|
|
121
|
+
}
|
|
122
|
+
type JudgeEndpointConfig = {
|
|
123
|
+
policy?: "default";
|
|
124
|
+
endpoint?: string;
|
|
125
|
+
} | {
|
|
126
|
+
policy: "self-hosted";
|
|
127
|
+
endpoint: string;
|
|
128
|
+
verifyPubKey: string;
|
|
129
|
+
};
|
|
130
|
+
interface ValidatedEndpoint {
|
|
131
|
+
url: string;
|
|
132
|
+
policy: "default" | "self-hosted";
|
|
133
|
+
verifyPubKey: string | null;
|
|
134
|
+
}
|
|
135
|
+
interface AtbashClientConfig {
|
|
136
|
+
judge?: JudgeEndpointConfig;
|
|
137
|
+
nodeUrls?: string[];
|
|
138
|
+
blockchainRid?: string;
|
|
139
|
+
keyPath?: string;
|
|
140
|
+
keyPair?: {
|
|
141
|
+
privKey: string;
|
|
142
|
+
pubKey: string;
|
|
143
|
+
};
|
|
144
|
+
failClosed?: boolean;
|
|
145
|
+
logger?: {
|
|
146
|
+
info?(...a: unknown[]): void;
|
|
147
|
+
warn?(...a: unknown[]): void;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
109
150
|
|
|
110
151
|
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
111
152
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
@@ -148,4 +189,19 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
148
189
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
149
190
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
150
191
|
|
|
151
|
-
|
|
192
|
+
interface AtbashClient {
|
|
193
|
+
auditToolCall(input: ToolCallInput): Promise<Decision>;
|
|
194
|
+
}
|
|
195
|
+
declare function createAtbashClient(config?: AtbashClientConfig): AtbashClient;
|
|
196
|
+
|
|
197
|
+
declare function validateJudgeEndpoint(judge?: JudgeEndpointConfig): ValidatedEndpoint;
|
|
198
|
+
|
|
199
|
+
declare function resolveKeyPath(input?: string): string;
|
|
200
|
+
declare function loadAgentFromFile(keyPath?: string): AgentAuth;
|
|
201
|
+
|
|
202
|
+
declare function verifyJudgeResponseSignature(bodyBytes: Uint8Array, signatureHex: string | null, pubKeyHex: string): {
|
|
203
|
+
ok: boolean;
|
|
204
|
+
reason?: string;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, logToolCall, resolveKeyPath, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
import { createECDH, randomBytes } from "crypto";
|
|
3
|
+
import postchain2 from "postchain-client";
|
|
4
|
+
|
|
5
|
+
// src/signature.ts
|
|
3
6
|
import postchain from "postchain-client";
|
|
4
|
-
var {
|
|
7
|
+
var { encryption } = postchain;
|
|
8
|
+
function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
|
|
9
|
+
if (!signatureHex) {
|
|
10
|
+
return { ok: false, reason: "missing X-Atbash-Signature header" };
|
|
11
|
+
}
|
|
12
|
+
const sigClean = signatureHex.trim().toLowerCase().replace(/^0x/, "");
|
|
13
|
+
if (!/^[0-9a-f]+$/.test(sigClean) || sigClean.length < 64 || sigClean.length > 256) {
|
|
14
|
+
return { ok: false, reason: "malformed signature header" };
|
|
15
|
+
}
|
|
16
|
+
let isValid = false;
|
|
17
|
+
try {
|
|
18
|
+
const digest = encryption.sha256(Buffer.from(bodyBytes));
|
|
19
|
+
const pubKeyBytes = Buffer.from(pubKeyHex.replace(/^0x/, ""), "hex");
|
|
20
|
+
const sigBytes = Buffer.from(sigClean, "hex");
|
|
21
|
+
isValid = encryption.checkDigestSignature(digest, pubKeyBytes, sigBytes);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
const message = String(
|
|
24
|
+
err?.message ?? err ?? ""
|
|
25
|
+
);
|
|
26
|
+
return { ok: false, reason: `signature verification threw: ${message}` };
|
|
27
|
+
}
|
|
28
|
+
return isValid ? { ok: true } : { ok: false, reason: "signature does not verify against configured verifyPubKey" };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/client.ts
|
|
32
|
+
var { createClient, encryption: encryption2, newSignatureProvider } = postchain2;
|
|
5
33
|
var DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
6
34
|
var DEFAULT_CHROMIA_NODE_URLS = [
|
|
7
35
|
"https://node6.testnet.chromia.com:7740",
|
|
@@ -57,7 +85,7 @@ async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
|
57
85
|
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
58
86
|
const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
|
|
59
87
|
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
60
|
-
const keyPair =
|
|
88
|
+
const keyPair = encryption2.makeKeyPair(privKeyBuf);
|
|
61
89
|
const sigProvider = newSignatureProvider({
|
|
62
90
|
privKey: keyPair.privKey,
|
|
63
91
|
pubKey: keyPair.pubKey
|
|
@@ -168,6 +196,31 @@ async function getJson(url, opts) {
|
|
|
168
196
|
}
|
|
169
197
|
return resp.json();
|
|
170
198
|
}
|
|
199
|
+
async function postJudgeRequest(url, body, opts) {
|
|
200
|
+
if (!opts?.verifyPubKey) {
|
|
201
|
+
return postJson(url, body, opts);
|
|
202
|
+
}
|
|
203
|
+
const resp = await fetch(url, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers: { "Content-Type": "application/json" },
|
|
206
|
+
body: JSON.stringify(body),
|
|
207
|
+
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
208
|
+
});
|
|
209
|
+
if (!resp.ok) {
|
|
210
|
+
const text = await resp.text().catch(() => "");
|
|
211
|
+
throw enrichError(resp.status, text, resp.statusText, opts);
|
|
212
|
+
}
|
|
213
|
+
const buf = new Uint8Array(await resp.arrayBuffer());
|
|
214
|
+
const verdict = verifyJudgeResponseSignature(
|
|
215
|
+
buf,
|
|
216
|
+
resp.headers.get("X-Atbash-Signature"),
|
|
217
|
+
opts.verifyPubKey
|
|
218
|
+
);
|
|
219
|
+
if (!verdict.ok) {
|
|
220
|
+
throw new Error(`signature verification failed: ${verdict.reason}`);
|
|
221
|
+
}
|
|
222
|
+
return JSON.parse(new TextDecoder().decode(buf));
|
|
223
|
+
}
|
|
171
224
|
async function judgeAction(action, context = "", auth, opts) {
|
|
172
225
|
if (!action || !action.trim()) {
|
|
173
226
|
throw new Error("action is required and cannot be empty.");
|
|
@@ -205,7 +258,7 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
205
258
|
...opts?.toolName && { tool_name: opts.toolName },
|
|
206
259
|
...opts?.model && { model: opts.model }
|
|
207
260
|
};
|
|
208
|
-
const data = await
|
|
261
|
+
const data = await postJudgeRequest(url, body, opts);
|
|
209
262
|
return {
|
|
210
263
|
verdict: normalizeVerdict(data.verdict),
|
|
211
264
|
action_type: String(data.action_type || ""),
|
|
@@ -332,11 +385,212 @@ async function getSafetyStats(opts) {
|
|
|
332
385
|
const result = await getJson(url, opts);
|
|
333
386
|
return result?.data || result;
|
|
334
387
|
}
|
|
388
|
+
|
|
389
|
+
// src/config.ts
|
|
390
|
+
var ALLOWED_JUDGE_HOSTS = /* @__PURE__ */ new Set([
|
|
391
|
+
"atbash.ai",
|
|
392
|
+
"www.atbash.ai"
|
|
393
|
+
]);
|
|
394
|
+
function validateJudgeEndpoint(judge) {
|
|
395
|
+
const policy = judge?.policy === "self-hosted" ? "self-hosted" : "default";
|
|
396
|
+
const candidate = judge?.endpoint?.trim() || DEFAULT_ENDPOINT;
|
|
397
|
+
let parsed;
|
|
398
|
+
try {
|
|
399
|
+
parsed = new URL(candidate);
|
|
400
|
+
} catch {
|
|
401
|
+
throw new Error(
|
|
402
|
+
`[atbash] invalid judge endpoint URL: ${candidate}. Refusing to load \u2014 fix the URL or omit it to use the default (${DEFAULT_ENDPOINT}).`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
if (parsed.protocol !== "https:") {
|
|
406
|
+
throw new Error(
|
|
407
|
+
`[atbash] judge endpoint must use https:// (got "${parsed.protocol}"). Refusing to load \u2014 plaintext endpoints leak verdicts and enable trivial MITM bypass.`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
if (parsed.username || parsed.password) {
|
|
411
|
+
throw new Error(
|
|
412
|
+
`[atbash] judge endpoint must not contain credentials (user:pass@host). Refusing to load \u2014 credentials embedded in URLs leak to logs and process listings.`
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
const normalisedUrl = parsed.origin;
|
|
416
|
+
if (policy === "self-hosted") {
|
|
417
|
+
const verifyPubKey = judge?.verifyPubKey;
|
|
418
|
+
const key = verifyPubKey?.trim().toLowerCase();
|
|
419
|
+
if (!key || !/^[0-9a-f]{66}$/.test(key)) {
|
|
420
|
+
throw new Error(
|
|
421
|
+
`[atbash] judge endpoint policy "self-hosted" requires verifyPubKey to be a 66-hex-char compressed secp256k1 pubkey. Refusing to load \u2014 self-hosted judges must produce signed responses so the SDK can detect a malicious or compromised judge.`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
return { url: normalisedUrl, policy, verifyPubKey: key };
|
|
425
|
+
}
|
|
426
|
+
if (!ALLOWED_JUDGE_HOSTS.has(parsed.hostname.toLowerCase())) {
|
|
427
|
+
throw new Error(
|
|
428
|
+
`[atbash] judge endpoint hostname "${parsed.hostname}" is not in the trusted allowlist. Allowed: ${[...ALLOWED_JUDGE_HOSTS].join(", ")}. To use a self-hosted judge, set BOTH policy="self-hosted" AND verifyPubKey to the 66-hex pubkey of your judge's response-signing key. Refusing to load \u2014 silent endpoint redirection is a known attack vector (F-003).`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
return { url: normalisedUrl, policy, verifyPubKey: null };
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/key-loader.ts
|
|
435
|
+
import { readFileSync } from "fs";
|
|
436
|
+
import { homedir } from "os";
|
|
437
|
+
import { join } from "path";
|
|
438
|
+
var DEFAULT_KEY_PATH_REL = ".config/atbash/guard-client-key";
|
|
439
|
+
function resolveKeyPath(input) {
|
|
440
|
+
if (input) return expandHome(input);
|
|
441
|
+
const home = process.env.HOME || homedir() || "";
|
|
442
|
+
return join(home, DEFAULT_KEY_PATH_REL);
|
|
443
|
+
}
|
|
444
|
+
function expandHome(p) {
|
|
445
|
+
if (!p.startsWith("~/")) return p;
|
|
446
|
+
const home = process.env.HOME || homedir() || "";
|
|
447
|
+
return join(home, p.slice(2));
|
|
448
|
+
}
|
|
449
|
+
function readKeyFile(keyPath) {
|
|
450
|
+
const content = String(readFileSync(keyPath, "utf8") || "").trim();
|
|
451
|
+
let privKey = "";
|
|
452
|
+
let pubKey = "";
|
|
453
|
+
if (content.startsWith("{")) {
|
|
454
|
+
const creds = JSON.parse(content);
|
|
455
|
+
privKey = String(
|
|
456
|
+
creds.privKey || creds.privkey || creds.privateKey || ""
|
|
457
|
+
).trim();
|
|
458
|
+
pubKey = String(
|
|
459
|
+
creds.pubKey || creds.pubkey || creds.publicKey || ""
|
|
460
|
+
).trim();
|
|
461
|
+
} else {
|
|
462
|
+
const lines = content.split(/\r?\n/);
|
|
463
|
+
for (const line of lines) {
|
|
464
|
+
if (line.startsWith("privkey=")) privKey = line.slice("privkey=".length).trim();
|
|
465
|
+
if (line.startsWith("pubkey=")) pubKey = line.slice("pubkey=".length).trim();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (!privKey || !pubKey) {
|
|
469
|
+
throw new Error(`atbash key file missing priv/pub key fields: ${keyPath}`);
|
|
470
|
+
}
|
|
471
|
+
privKey = privKey.replace(/^0x/, "");
|
|
472
|
+
return { privKey, pubKey };
|
|
473
|
+
}
|
|
474
|
+
function loadAgentFromFile(keyPath) {
|
|
475
|
+
const resolved = resolveKeyPath(keyPath);
|
|
476
|
+
const { privKey } = readKeyFile(resolved);
|
|
477
|
+
return loadAgent(privKey);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/factory.ts
|
|
481
|
+
function createAtbashClient(config = {}) {
|
|
482
|
+
const validated = validateJudgeEndpoint(config.judge);
|
|
483
|
+
const failClosed = config.failClosed !== false;
|
|
484
|
+
const logger = config.logger ?? {};
|
|
485
|
+
const inlineKeyPair = config.keyPair;
|
|
486
|
+
const keyPath = inlineKeyPair ? null : config.keyPath;
|
|
487
|
+
if (validated.url !== DEFAULT_ENDPOINT) {
|
|
488
|
+
logger.warn?.("[atbash] running on non-default judge endpoint", {
|
|
489
|
+
endpoint: validated.url,
|
|
490
|
+
policy: validated.policy,
|
|
491
|
+
verifying: validated.verifyPubKey ? "with response-signature pubkey configured" : "without signature verification"
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
let cachedAgent = inlineKeyPair ? loadAgent(inlineKeyPair.privKey) : null;
|
|
495
|
+
function loadAgentOnce() {
|
|
496
|
+
if (cachedAgent) return cachedAgent;
|
|
497
|
+
cachedAgent = loadAgentFromFile(keyPath ?? void 0);
|
|
498
|
+
return cachedAgent;
|
|
499
|
+
}
|
|
500
|
+
function fail(reason, toolCallId) {
|
|
501
|
+
return { allow: !failClosed, verdict: "ERROR", reason, toolCallId };
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
async auditToolCall(input) {
|
|
505
|
+
let agent;
|
|
506
|
+
try {
|
|
507
|
+
agent = loadAgentOnce();
|
|
508
|
+
} catch (err) {
|
|
509
|
+
const message = String(err?.message ?? err ?? "");
|
|
510
|
+
logger.warn?.("[atbash] failed to load key pair, blocking for safety", {
|
|
511
|
+
error: message
|
|
512
|
+
});
|
|
513
|
+
return fail("key load failed, blocking for safety");
|
|
514
|
+
}
|
|
515
|
+
const toolName = input.toolName || "unknown";
|
|
516
|
+
const argsJson = stringifyArgs(input.args);
|
|
517
|
+
const actionText = truncate(argsJson);
|
|
518
|
+
const contextText = input.context ?? toolName;
|
|
519
|
+
try {
|
|
520
|
+
logger.info?.("[atbash] judge API called", { tool: toolName });
|
|
521
|
+
const result = await judgeAction(actionText, contextText, agent, {
|
|
522
|
+
endpoint: validated.url,
|
|
523
|
+
verifyPubKey: validated.verifyPubKey ?? void 0,
|
|
524
|
+
toolName,
|
|
525
|
+
toolArgsJson: argsJson,
|
|
526
|
+
chainOpts: {
|
|
527
|
+
nodeUrls: config.nodeUrls,
|
|
528
|
+
blockchainRid: config.blockchainRid
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
if (result.verdict === "No verdict") {
|
|
532
|
+
return {
|
|
533
|
+
allow: true,
|
|
534
|
+
verdict: "ALLOW",
|
|
535
|
+
reason: result.reason || "audit tier \u2014 request logged on-chain, no AI enforcement",
|
|
536
|
+
toolCallId: result.tool_call_id
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const action = result.action_type;
|
|
540
|
+
if (action === "block") {
|
|
541
|
+
return {
|
|
542
|
+
allow: false,
|
|
543
|
+
verdict: "BLOCK",
|
|
544
|
+
reason: result.reason,
|
|
545
|
+
toolCallId: result.tool_call_id
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
if (action === "hold_for_user_confirm") {
|
|
549
|
+
return {
|
|
550
|
+
allow: false,
|
|
551
|
+
verdict: "HOLD",
|
|
552
|
+
reason: result.reason || "held for human confirmation",
|
|
553
|
+
toolCallId: result.tool_call_id
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (action === "allow") {
|
|
557
|
+
const surfacedVerdict = result.verdict === "ALLOW" || result.verdict === "HOLD" || result.verdict === "BLOCK" ? result.verdict : "ALLOW";
|
|
558
|
+
return {
|
|
559
|
+
allow: true,
|
|
560
|
+
verdict: surfacedVerdict,
|
|
561
|
+
reason: result.reason,
|
|
562
|
+
toolCallId: result.tool_call_id
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
return fail("unrecognized action_type from judge", result.tool_call_id);
|
|
566
|
+
} catch (err) {
|
|
567
|
+
const message = String(err?.message ?? err ?? "");
|
|
568
|
+
logger.warn?.("[atbash] judge API failed", { reason: message });
|
|
569
|
+
return fail(message);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function stringifyArgs(args) {
|
|
575
|
+
if (args == null) return "";
|
|
576
|
+
if (typeof args === "string") return args;
|
|
577
|
+
try {
|
|
578
|
+
return JSON.stringify(args);
|
|
579
|
+
} catch {
|
|
580
|
+
return String(args);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
var MAX_ACTION_LEN = 4e3;
|
|
584
|
+
function truncate(text) {
|
|
585
|
+
if (text.length <= MAX_ACTION_LEN) return text;
|
|
586
|
+
return text.slice(0, MAX_ACTION_LEN) + "\u2026";
|
|
587
|
+
}
|
|
335
588
|
export {
|
|
336
589
|
DEFAULT_BLOCKCHAIN_RID,
|
|
337
590
|
DEFAULT_CHROMIA_NODE_URLS,
|
|
338
591
|
DEFAULT_ENDPOINT,
|
|
339
592
|
checkAgentExists,
|
|
593
|
+
createAtbashClient,
|
|
340
594
|
derivePublicKey,
|
|
341
595
|
generateKeyPair,
|
|
342
596
|
getAgentDetail,
|
|
@@ -354,6 +608,10 @@ export {
|
|
|
354
608
|
isValidPrivateKey,
|
|
355
609
|
judgeAction,
|
|
356
610
|
loadAgent,
|
|
611
|
+
loadAgentFromFile,
|
|
357
612
|
logToolCall,
|
|
358
|
-
|
|
613
|
+
resolveKeyPath,
|
|
614
|
+
toPubkeyHex,
|
|
615
|
+
validateJudgeEndpoint,
|
|
616
|
+
verifyJudgeResponseSignature
|
|
359
617
|
};
|