@atbash/sdk 0.3.23 → 0.3.25
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 +39 -31
- package/dist/index.cjs +127 -20
- package/dist/index.d.cts +21 -31
- package/dist/index.d.ts +21 -31
- package/dist/index.js +126 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,10 +23,12 @@ const agent = loadAgent(process.env.ATBASH_AGENT_PRIVKEY!);
|
|
|
23
23
|
// 2. Submit an action for judgment, before executing it.
|
|
24
24
|
// The SDK signs the transaction locally and sends it to the judge API.
|
|
25
25
|
// Private key stays on your machine — never sent over HTTP.
|
|
26
|
+
// Pass orgName so the SDK auto-resolves the correct chain (public or private).
|
|
26
27
|
const result = await judgeAction(
|
|
27
28
|
"Transfer $50,000 to external wallet 0xabc",
|
|
28
29
|
"Outbound AML check — new recipient, over threshold",
|
|
29
30
|
agent,
|
|
31
|
+
{ orgName: "my_org" },
|
|
30
32
|
);
|
|
31
33
|
|
|
32
34
|
// 3. Enforce the verdict
|
|
@@ -39,19 +41,19 @@ switch (result.verdict) {
|
|
|
39
41
|
console.log("Held for review:", result.tool_call_id);
|
|
40
42
|
break;
|
|
41
43
|
case "BLOCK":
|
|
42
|
-
// Refused — agent is jailed
|
|
44
|
+
// Refused — agent is auto-jailed
|
|
43
45
|
throw new Error(`Blocked: ${result.reason}`);
|
|
44
46
|
}
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
Before this works, the agent must be onboarded at [atbash.ai](https://atbash.ai/) — assigned to an org
|
|
49
|
+
Before this works, the agent must be onboarded at [atbash.ai](https://atbash.ai/) — assigned to an org with an active subscription and a policy pack attached.
|
|
48
50
|
|
|
49
51
|
### How it works
|
|
50
52
|
|
|
51
53
|
`judgeAction()` performs a two-step flow:
|
|
52
54
|
|
|
53
55
|
1. **Sign locally** — signs the transaction using the agent's private key. The key never leaves your machine.
|
|
54
|
-
2. **Request verdict** — sends the signed
|
|
56
|
+
2. **Request verdict** — sends the signed payload to the Atbash judge API, which records it on the Chromia blockchain and returns a verdict.
|
|
55
57
|
|
|
56
58
|
|
|
57
59
|
### Don't have an agent yet?
|
|
@@ -86,9 +88,9 @@ Every `judgeAction` call returns one of three verdicts:
|
|
|
86
88
|
|---------|---------|-------------------------|
|
|
87
89
|
| `ALLOW` | Action is within policy | Proceed with execution |
|
|
88
90
|
| `HOLD` | Requires operator review | Pause — poll `getJudgmentStatus` until resolved |
|
|
89
|
-
| `BLOCK` | Violates a red line | Abort — agent is jailed
|
|
91
|
+
| `BLOCK` | Violates a red line | Abort — agent is auto-jailed |
|
|
90
92
|
|
|
91
|
-
> **NB:** If your org
|
|
93
|
+
> **NB:** If your org has **no active subscription**, the judge returns `"No verdict"` — actions are logged on-chain for the audit trail but not evaluated. Assign a subscription plan at [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) for active verdicts. All subscription plans (including Free) get full enforcement.
|
|
92
94
|
|
|
93
95
|
## API
|
|
94
96
|
|
|
@@ -118,17 +120,11 @@ interface JudgeOptions {
|
|
|
118
120
|
model?: string; // Model override (e.g. "gpt-4o-mini")
|
|
119
121
|
toolName?: string; // Tool name for audit trail
|
|
120
122
|
toolArgsJson?: string; // Tool arguments JSON for audit trail
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
interface ChainOpts {
|
|
125
|
-
nodeUrls?: string[]; // Chromia node URLs (uses the default nodeurls)
|
|
126
|
-
blockchainRid?: string; // Blockchain RID (uses the default chromia rid)
|
|
123
|
+
orgName?: string; // Org name — SDK auto-resolves the correct chain
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
interface JudgeResult {
|
|
130
127
|
verdict: string; // "ALLOW", "HOLD", or "BLOCK"
|
|
131
|
-
action_type: string; // "allow", "hold_for_user_confirm", or "block"
|
|
132
128
|
reason: string; // Human-readable explanation
|
|
133
129
|
confidence: number; // 0–1
|
|
134
130
|
provider: string; // Which provider evaluated the action
|
|
@@ -138,20 +134,6 @@ interface JudgeResult {
|
|
|
138
134
|
}
|
|
139
135
|
```
|
|
140
136
|
|
|
141
|
-
### Log tool call (low-level)
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
logToolCall(
|
|
145
|
-
action: string,
|
|
146
|
-
context: string,
|
|
147
|
-
auth: AgentAuth,
|
|
148
|
-
chainOpts?: ChainOpts,
|
|
149
|
-
extra?: { toolName?: string; toolArgsJson?: string },
|
|
150
|
-
): Promise<LogToolCallResult>
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Sign the transaction locally. Returns `{ success, toolCallId, signedHex?, error? }`. Use this if you need to separate the signing step from the verdict request.
|
|
154
|
-
|
|
155
137
|
### Poll judgment status
|
|
156
138
|
|
|
157
139
|
```ts
|
|
@@ -191,7 +173,6 @@ Functions that sign transactions and write to the Chromia blockchain.
|
|
|
191
173
|
| Function | Use case |
|
|
192
174
|
|----------|----------|
|
|
193
175
|
| `judgeAction(action, context, auth, opts?)` | Sign locally + request a verdict from the judge API |
|
|
194
|
-
| `logToolCall(action, context, auth, ...)` | Sign the transaction locally without requesting a verdict |
|
|
195
176
|
|
|
196
177
|
### Queries
|
|
197
178
|
|
|
@@ -204,7 +185,7 @@ Functions that sign transactions and write to the Chromia blockchain.
|
|
|
204
185
|
| `getAgentToolCalls(pubkey, maxCount)` | List tool calls for a specific agent |
|
|
205
186
|
| `getToolCallCount()` | Get total number of tool calls on-chain |
|
|
206
187
|
| `getToolCallFull(toolCallId)` | Get full details of a single tool call (verdict, context, timing) |
|
|
207
|
-
| `
|
|
188
|
+
| `getOrgSubscription(orgName)` | Check an org's subscription plan, network, and active status |
|
|
208
189
|
| `getAgentDetail(pubkey)` | Get agent metadata (org, status, creation date) |
|
|
209
190
|
| `getAgentPolicy(pubkey)` | Check agent's policy pack and jail status |
|
|
210
191
|
| `getPendingHeldActions(orgName, maxCount)` | List actions waiting for operator approval |
|
|
@@ -242,6 +223,7 @@ saveUserConfig({
|
|
|
242
223
|
// Then use resolve() anywhere
|
|
243
224
|
const agent = loadAgent(resolve("agentKey"));
|
|
244
225
|
const result = await judgeAction("Transfer $500", "finance", agent, {
|
|
226
|
+
orgName: resolve("orgName"),
|
|
245
227
|
provider: resolve("provider"), // omit to use the on-chain ATBASH judge
|
|
246
228
|
});
|
|
247
229
|
```
|
|
@@ -264,7 +246,7 @@ Config file location: `~/.config/atbash/config.json`
|
|
|
264
246
|
| `provider` | `ATBASH_PROVIDER` |
|
|
265
247
|
| `providerModel` | `ATBASH_PROVIDER_MODEL` |
|
|
266
248
|
|
|
267
|
-
> **
|
|
249
|
+
> **Chain routing:** When you pass `orgName`, the SDK automatically connects to the correct chain for your org's subscription plan. You don't need to configure chain details manually.
|
|
268
250
|
|
|
269
251
|
## Secret redaction
|
|
270
252
|
|
|
@@ -285,6 +267,32 @@ Common `kinds`:
|
|
|
285
267
|
|
|
286
268
|
Redaction is silent at the consumer level — the SDK's caller still has the original arguments. Only what's sent to the judge (and persisted on chain via the verdict log) is scrubbed.
|
|
287
269
|
|
|
270
|
+
## High-level client
|
|
271
|
+
|
|
272
|
+
For framework integrations, `createAtbashClient` wraps key loading, secret redaction, and verdict handling into a single `auditToolCall` method:
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
import { createAtbashClient } from "@atbash/sdk";
|
|
276
|
+
|
|
277
|
+
const atbash = createAtbashClient({
|
|
278
|
+
orgName: "my_org",
|
|
279
|
+
keyPair: { privKey: process.env.ATBASH_AGENT_KEY!, pubKey: "" },
|
|
280
|
+
failClosed: true, // block on errors (default: true)
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const decision = await atbash.auditToolCall({
|
|
284
|
+
toolName: "send_email",
|
|
285
|
+
args: { to: "user@example.com", subject: "Reset" },
|
|
286
|
+
context: "Password reset flow",
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
if (!decision.allow) {
|
|
290
|
+
console.log(`${decision.verdict}: ${decision.reason}`);
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The client auto-resolves the correct chain from the org's subscription on the first call and caches the result. Secret redaction runs automatically before signing.
|
|
295
|
+
|
|
288
296
|
## Integration patterns
|
|
289
297
|
|
|
290
298
|
### Pre-execution gate
|
|
@@ -334,8 +342,8 @@ API error 404: {"error":"Agent not registered..."}
|
|
|
334
342
|
|---|---|---|
|
|
335
343
|
| `API error 404: Agent not registered` | Agent not onboarded | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
|
|
336
344
|
| `API error 400: Agent has no policy` | No policy attached to agent | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
|
|
337
|
-
| `Agent is jailed` | BLOCK verdict triggered auto-jail
|
|
338
|
-
| `
|
|
345
|
+
| `Agent is jailed` | BLOCK verdict triggered auto-jail | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
|
|
346
|
+
| `Verdicts are disabled` | Org has no active subscription | [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) |
|
|
339
347
|
| `API error 400: action is required` | Empty action string | Fix caller |
|
|
340
348
|
| `API error 502: Incorrect API key` | Invalid provider API key | Check saved key at [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) |
|
|
341
349
|
|
package/dist/index.cjs
CHANGED
|
@@ -47,7 +47,7 @@ __export(index_exports, {
|
|
|
47
47
|
getConfigPath: () => getConfigPath,
|
|
48
48
|
getHeldActionReviews: () => getHeldActionReviews,
|
|
49
49
|
getJudgmentStatus: () => getJudgmentStatus,
|
|
50
|
-
|
|
50
|
+
getOrgSubscription: () => getOrgSubscription,
|
|
51
51
|
getOrgToolCalls: () => getOrgToolCalls,
|
|
52
52
|
getPendingHeldActions: () => getPendingHeldActions,
|
|
53
53
|
getSafetyStats: () => getSafetyStats,
|
|
@@ -59,7 +59,6 @@ __export(index_exports, {
|
|
|
59
59
|
loadAgent: () => loadAgent,
|
|
60
60
|
loadAgentFromFile: () => loadAgentFromFile,
|
|
61
61
|
loadUserConfig: () => loadUserConfig,
|
|
62
|
-
logToolCall: () => logToolCall,
|
|
63
62
|
normalizeForMatching: () => normalizeForMatching,
|
|
64
63
|
resolve: () => resolve,
|
|
65
64
|
resolveKeyPath: () => resolveKeyPath,
|
|
@@ -197,7 +196,37 @@ var DEFAULT_CHROMIA_NODE_URLS = [
|
|
|
197
196
|
"https://node1.testnet.chromia.com:7740",
|
|
198
197
|
"https://node3.testnet.chromia.com:7740"
|
|
199
198
|
];
|
|
200
|
-
var DEFAULT_BLOCKCHAIN_RID = "
|
|
199
|
+
var DEFAULT_BLOCKCHAIN_RID = "B91106947F1EAED7B5D789C7D35755330A8A7DD7CB990D59366114EFFB79ED10";
|
|
200
|
+
var DEFAULT_PRIVATE_NODE_URLS = [
|
|
201
|
+
"https://node0-pvn-testnet.dynamic.chromia.dev"
|
|
202
|
+
];
|
|
203
|
+
var DEFAULT_PRIVATE_BLOCKCHAIN_RID = "431AE6A5695D157D74194A61AB4D0B6A98C99AFEEF186FC885CDA4A3BAAB800E";
|
|
204
|
+
var PUBLIC_CHAIN = {
|
|
205
|
+
network: "public",
|
|
206
|
+
blockchainRid: DEFAULT_BLOCKCHAIN_RID,
|
|
207
|
+
nodeUrls: DEFAULT_CHROMIA_NODE_URLS
|
|
208
|
+
};
|
|
209
|
+
var PRIVATE_CHAIN = {
|
|
210
|
+
network: "private",
|
|
211
|
+
blockchainRid: DEFAULT_PRIVATE_BLOCKCHAIN_RID,
|
|
212
|
+
nodeUrls: DEFAULT_PRIVATE_NODE_URLS
|
|
213
|
+
};
|
|
214
|
+
function chainForNetwork(network) {
|
|
215
|
+
return network === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
216
|
+
}
|
|
217
|
+
function resolveChainOpts(chainOpts) {
|
|
218
|
+
if (chainOpts?.network) {
|
|
219
|
+
const chain = chainForNetwork(chainOpts.network);
|
|
220
|
+
return {
|
|
221
|
+
nodeUrls: chainOpts.nodeUrls ?? chain.nodeUrls,
|
|
222
|
+
blockchainRid: chainOpts.blockchainRid ?? chain.blockchainRid
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
nodeUrls: chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS,
|
|
227
|
+
blockchainRid: chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID
|
|
228
|
+
};
|
|
229
|
+
}
|
|
201
230
|
function isValidPrivateKey(hex) {
|
|
202
231
|
return /^[0-9a-fA-F]{64}$/.test(hex);
|
|
203
232
|
}
|
|
@@ -236,14 +265,30 @@ function toPubkeyHex(val) {
|
|
|
236
265
|
function baseUrl(opts) {
|
|
237
266
|
return opts?.endpoint || DEFAULT_ENDPOINT;
|
|
238
267
|
}
|
|
268
|
+
var AUTH_BEARER_REFRESH_MS = 4 * 60 * 1e3;
|
|
269
|
+
var bearerCache = /* @__PURE__ */ new Map();
|
|
270
|
+
async function getOrCreateAuthBearer(auth) {
|
|
271
|
+
const now = Date.now();
|
|
272
|
+
const cached = bearerCache.get(auth.pubkey);
|
|
273
|
+
if (cached && now - cached.issuedAt < AUTH_BEARER_REFRESH_MS) {
|
|
274
|
+
return cached.hex;
|
|
275
|
+
}
|
|
276
|
+
const nonce = `auth-${now.toString(36)}-${(0, import_crypto.randomBytes)(4).toString("hex")}`;
|
|
277
|
+
const hex = await buildSignedTx(
|
|
278
|
+
"log_tool_call",
|
|
279
|
+
[nonce, `auth:${now}`, "", "auth-bearer", ""],
|
|
280
|
+
auth
|
|
281
|
+
);
|
|
282
|
+
bearerCache.set(auth.pubkey, { hex, issuedAt: now });
|
|
283
|
+
return hex;
|
|
284
|
+
}
|
|
239
285
|
function generateToolCallId() {
|
|
240
286
|
const ts = Date.now();
|
|
241
287
|
const rand = (0, import_crypto.randomBytes)(4).toString("hex");
|
|
242
288
|
return `tc-${ts}-${rand}`;
|
|
243
289
|
}
|
|
244
290
|
async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
245
|
-
const nodeUrls = chainOpts
|
|
246
|
-
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
291
|
+
const { nodeUrls, blockchainRid } = resolveChainOpts(chainOpts);
|
|
247
292
|
const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
|
|
248
293
|
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
249
294
|
const keyPair = encryption2.makeKeyPair(privKeyBuf);
|
|
@@ -260,11 +305,13 @@ async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
|
260
305
|
);
|
|
261
306
|
return Buffer.from(signed).toString("hex");
|
|
262
307
|
}
|
|
263
|
-
async function
|
|
308
|
+
async function _checkAgentExists(pubkey, opts, chainOpts) {
|
|
264
309
|
const start = performance.now();
|
|
265
310
|
recordCall("checkAgentExists", void 0, pubkey);
|
|
266
311
|
try {
|
|
267
|
-
const
|
|
312
|
+
const network = chainOpts?.network;
|
|
313
|
+
let url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
314
|
+
if (network) url += `&network=${encodeURIComponent(network)}`;
|
|
268
315
|
const data = await getJson(url, opts);
|
|
269
316
|
recordDuration("checkAgentExists", performance.now() - start, "success");
|
|
270
317
|
return Boolean(data.registered);
|
|
@@ -273,10 +320,13 @@ async function checkAgentExists(pubkey, opts) {
|
|
|
273
320
|
throw err;
|
|
274
321
|
}
|
|
275
322
|
}
|
|
323
|
+
async function checkAgentExists(pubkey, opts) {
|
|
324
|
+
return _checkAgentExists(pubkey, opts);
|
|
325
|
+
}
|
|
276
326
|
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
277
327
|
const start = performance.now();
|
|
278
328
|
recordCall("logToolCall", void 0, auth.pubkey);
|
|
279
|
-
const exists = await
|
|
329
|
+
const exists = await _checkAgentExists(auth.pubkey, clientOpts, chainOpts);
|
|
280
330
|
if (!exists) {
|
|
281
331
|
recordDuration("logToolCall", performance.now() - start, "error");
|
|
282
332
|
return {
|
|
@@ -345,9 +395,13 @@ function enrichError(status, body, statusText, opts) {
|
|
|
345
395
|
return new Error(message);
|
|
346
396
|
}
|
|
347
397
|
async function postJson(url, body, opts) {
|
|
398
|
+
const headers = { "Content-Type": "application/json" };
|
|
399
|
+
if (opts?.auth) {
|
|
400
|
+
headers["Authorization"] = `Bearer ${await getOrCreateAuthBearer(opts.auth)}`;
|
|
401
|
+
}
|
|
348
402
|
const resp = await fetch(url, {
|
|
349
403
|
method: "POST",
|
|
350
|
-
headers
|
|
404
|
+
headers,
|
|
351
405
|
body: JSON.stringify(body),
|
|
352
406
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
353
407
|
});
|
|
@@ -359,9 +413,13 @@ async function postJson(url, body, opts) {
|
|
|
359
413
|
return ct.includes("application/json") ? resp.json() : {};
|
|
360
414
|
}
|
|
361
415
|
async function getJson(url, opts) {
|
|
416
|
+
const headers = { Accept: "application/json" };
|
|
417
|
+
if (opts?.auth) {
|
|
418
|
+
headers["Authorization"] = `Bearer ${await getOrCreateAuthBearer(opts.auth)}`;
|
|
419
|
+
}
|
|
362
420
|
const resp = await fetch(url, {
|
|
363
421
|
method: "GET",
|
|
364
|
-
headers
|
|
422
|
+
headers,
|
|
365
423
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
366
424
|
});
|
|
367
425
|
if (!resp.ok) {
|
|
@@ -402,11 +460,16 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
402
460
|
throw new Error("action is required and cannot be empty.");
|
|
403
461
|
}
|
|
404
462
|
try {
|
|
463
|
+
let chainOpts = opts?.chainOpts;
|
|
464
|
+
if (opts?.orgName && !chainOpts?.blockchainRid) {
|
|
465
|
+
const resolved = await resolveChainForOrg(opts.orgName, opts);
|
|
466
|
+
chainOpts = { ...chainOpts, network: resolved.network };
|
|
467
|
+
}
|
|
405
468
|
const logResult = await logToolCall(
|
|
406
469
|
action,
|
|
407
470
|
context,
|
|
408
471
|
auth,
|
|
409
|
-
|
|
472
|
+
chainOpts,
|
|
410
473
|
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
|
|
411
474
|
opts
|
|
412
475
|
);
|
|
@@ -420,7 +483,7 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
420
483
|
"judge_action",
|
|
421
484
|
[judgmentId, action, context || "", ""],
|
|
422
485
|
auth,
|
|
423
|
-
|
|
486
|
+
chainOpts
|
|
424
487
|
);
|
|
425
488
|
}
|
|
426
489
|
const url = `${baseUrl(opts)}/api/v1/judge`;
|
|
@@ -565,21 +628,52 @@ async function getToolCallFull(toolCallId, opts) {
|
|
|
565
628
|
throw err;
|
|
566
629
|
}
|
|
567
630
|
}
|
|
568
|
-
|
|
631
|
+
function coerceOrgSubscription(row, orgName) {
|
|
632
|
+
if (!row || typeof row !== "object") return null;
|
|
633
|
+
const r = row;
|
|
634
|
+
return {
|
|
635
|
+
org_name: String(r.org_name ?? orgName),
|
|
636
|
+
subscription_name: String(r.subscription_name ?? ""),
|
|
637
|
+
agent_number: Number(r.agent_number ?? 0),
|
|
638
|
+
is_private_blockchain: Boolean(r.is_private_blockchain),
|
|
639
|
+
monthly_price: Number(r.monthly_price ?? 0),
|
|
640
|
+
yearly_price: Number(r.yearly_price ?? 0),
|
|
641
|
+
duration_months: Number(r.duration_months ?? 0),
|
|
642
|
+
assigned_at: Number(r.assigned_at ?? 0),
|
|
643
|
+
expires_at: Number(r.expires_at ?? 0),
|
|
644
|
+
is_active: Boolean(r.is_active)
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
async function getOrgSubscription(orgName, opts) {
|
|
569
648
|
const start = performance.now();
|
|
570
|
-
recordCall("
|
|
649
|
+
recordCall("getOrgSubscription");
|
|
571
650
|
try {
|
|
572
651
|
const result = await getJson(
|
|
573
|
-
riskEngineUrl("org-
|
|
652
|
+
riskEngineUrl("org-subscription", { org: orgName }, opts),
|
|
574
653
|
opts
|
|
575
654
|
);
|
|
576
|
-
recordDuration("
|
|
577
|
-
return result;
|
|
655
|
+
recordDuration("getOrgSubscription", performance.now() - start, "success");
|
|
656
|
+
return coerceOrgSubscription(result, orgName);
|
|
578
657
|
} catch (err) {
|
|
579
|
-
recordDuration("
|
|
658
|
+
recordDuration("getOrgSubscription", performance.now() - start, "error");
|
|
580
659
|
throw err;
|
|
581
660
|
}
|
|
582
661
|
}
|
|
662
|
+
var _chainCache = /* @__PURE__ */ new Map();
|
|
663
|
+
async function resolveChainForOrg(orgName, opts) {
|
|
664
|
+
const cached = _chainCache.get(orgName);
|
|
665
|
+
if (cached) return cached;
|
|
666
|
+
try {
|
|
667
|
+
const sub = await getOrgSubscription(orgName, opts);
|
|
668
|
+
if (sub?.is_private_blockchain) {
|
|
669
|
+
_chainCache.set(orgName, PRIVATE_CHAIN);
|
|
670
|
+
return PRIVATE_CHAIN;
|
|
671
|
+
}
|
|
672
|
+
} catch {
|
|
673
|
+
}
|
|
674
|
+
_chainCache.set(orgName, PUBLIC_CHAIN);
|
|
675
|
+
return PUBLIC_CHAIN;
|
|
676
|
+
}
|
|
583
677
|
async function getPendingHeldActions(orgName, maxCount, opts) {
|
|
584
678
|
const start = performance.now();
|
|
585
679
|
recordCall("getPendingHeldActions");
|
|
@@ -835,6 +929,8 @@ function createAtbashClient(config = {}) {
|
|
|
835
929
|
const validated = validateJudgeEndpoint(config.judge);
|
|
836
930
|
const failClosed = config.failClosed !== false;
|
|
837
931
|
const logger = config.logger ?? {};
|
|
932
|
+
const orgName = config.orgName;
|
|
933
|
+
let resolvedChain = null;
|
|
838
934
|
const inlineKeyPair = config.keyPair;
|
|
839
935
|
const keyPath = inlineKeyPair ? null : config.keyPath;
|
|
840
936
|
if (validated.url !== DEFAULT_ENDPOINT) {
|
|
@@ -884,12 +980,23 @@ function createAtbashClient(config = {}) {
|
|
|
884
980
|
});
|
|
885
981
|
}
|
|
886
982
|
try {
|
|
983
|
+
if (!resolvedChain && orgName) {
|
|
984
|
+
resolvedChain = await resolveChainForOrg(orgName, { endpoint: validated.url });
|
|
985
|
+
config.nodeUrls = resolvedChain.nodeUrls;
|
|
986
|
+
config.blockchainRid = resolvedChain.blockchainRid;
|
|
987
|
+
logger.info?.("[atbash] resolved network from subscription", {
|
|
988
|
+
org: orgName,
|
|
989
|
+
network: resolvedChain.network,
|
|
990
|
+
brid: resolvedChain.blockchainRid
|
|
991
|
+
});
|
|
992
|
+
}
|
|
887
993
|
logger.info?.("[atbash] judge API called", { tool: toolName });
|
|
888
994
|
const result = await judgeAction(actionText, contextText, agent, {
|
|
889
995
|
endpoint: validated.url,
|
|
890
996
|
verifyPubKey: validated.verifyPubKey ?? void 0,
|
|
891
997
|
toolName,
|
|
892
998
|
toolArgsJson: argsJson,
|
|
999
|
+
orgName,
|
|
893
1000
|
chainOpts: {
|
|
894
1001
|
nodeUrls: config.nodeUrls,
|
|
895
1002
|
blockchainRid: config.blockchainRid
|
|
@@ -977,6 +1084,7 @@ var ENV_MAP = {
|
|
|
977
1084
|
orgName: "ATBASH_ORG_NAME",
|
|
978
1085
|
judgeEndpoint: "ATBASH_ENDPOINT",
|
|
979
1086
|
blockchainRid: "ATBASH_BLOCKCHAIN_RID",
|
|
1087
|
+
network: "ATBASH_NETWORK",
|
|
980
1088
|
provider: "ATBASH_PROVIDER",
|
|
981
1089
|
providerModel: "ATBASH_PROVIDER_MODEL"
|
|
982
1090
|
};
|
|
@@ -1482,7 +1590,7 @@ function deduplicateAnomalies(anomalies) {
|
|
|
1482
1590
|
getConfigPath,
|
|
1483
1591
|
getHeldActionReviews,
|
|
1484
1592
|
getJudgmentStatus,
|
|
1485
|
-
|
|
1593
|
+
getOrgSubscription,
|
|
1486
1594
|
getOrgToolCalls,
|
|
1487
1595
|
getPendingHeldActions,
|
|
1488
1596
|
getSafetyStats,
|
|
@@ -1494,7 +1602,6 @@ function deduplicateAnomalies(anomalies) {
|
|
|
1494
1602
|
loadAgent,
|
|
1495
1603
|
loadAgentFromFile,
|
|
1496
1604
|
loadUserConfig,
|
|
1497
|
-
logToolCall,
|
|
1498
1605
|
normalizeForMatching,
|
|
1499
1606
|
resolve,
|
|
1500
1607
|
resolveKeyPath,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
|
|
2
2
|
type Provider = "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
3
|
-
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
4
3
|
type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
|
|
5
4
|
type PubkeyValue = string | Buffer | {
|
|
6
5
|
data: number[];
|
|
7
6
|
};
|
|
8
7
|
type JudgmentStatusState = "pending" | "answered" | "error";
|
|
8
|
+
interface Subscription {
|
|
9
|
+
subscription_name: string;
|
|
10
|
+
agent_number: number;
|
|
11
|
+
is_private_blockchain: boolean;
|
|
12
|
+
monthly_price: number;
|
|
13
|
+
yearly_price: number;
|
|
14
|
+
}
|
|
15
|
+
interface OrgSubscription extends Subscription {
|
|
16
|
+
org_name: string;
|
|
17
|
+
duration_months: number;
|
|
18
|
+
assigned_at: number;
|
|
19
|
+
expires_at: number;
|
|
20
|
+
is_active: boolean;
|
|
21
|
+
}
|
|
9
22
|
interface AgentAuth {
|
|
10
23
|
pubkey: string;
|
|
11
24
|
privkey: string;
|
|
@@ -13,17 +26,12 @@ interface AgentAuth {
|
|
|
13
26
|
interface ClientOpts {
|
|
14
27
|
endpoint?: string;
|
|
15
28
|
timeout?: number;
|
|
29
|
+
auth?: AgentAuth;
|
|
16
30
|
}
|
|
17
31
|
interface ChainOpts {
|
|
18
32
|
nodeUrls?: string[];
|
|
19
33
|
blockchainRid?: string;
|
|
20
34
|
}
|
|
21
|
-
interface LogToolCallResult {
|
|
22
|
-
success: boolean;
|
|
23
|
-
toolCallId: string | null;
|
|
24
|
-
signedHex?: string;
|
|
25
|
-
error?: string;
|
|
26
|
-
}
|
|
27
35
|
interface JudgeResult {
|
|
28
36
|
verdict: Verdict;
|
|
29
37
|
action_type: ActionType;
|
|
@@ -39,6 +47,7 @@ interface JudgeOptions extends ClientOpts {
|
|
|
39
47
|
model?: string;
|
|
40
48
|
toolName?: string;
|
|
41
49
|
toolArgsJson?: string;
|
|
50
|
+
orgName?: string;
|
|
42
51
|
chainOpts?: ChainOpts;
|
|
43
52
|
verifyPubKey?: string;
|
|
44
53
|
}
|
|
@@ -51,12 +60,6 @@ interface JudgmentStatus {
|
|
|
51
60
|
cached?: boolean;
|
|
52
61
|
responseTimeMs?: number;
|
|
53
62
|
}
|
|
54
|
-
interface TierInfo {
|
|
55
|
-
org_name: string;
|
|
56
|
-
tier: Tier;
|
|
57
|
-
verdict_enabled: boolean;
|
|
58
|
-
enforcement_enabled: boolean;
|
|
59
|
-
}
|
|
60
63
|
interface ToolCallRecord {
|
|
61
64
|
tool_call_id: string;
|
|
62
65
|
agent_pubkey: PubkeyValue;
|
|
@@ -179,6 +182,7 @@ interface AtbashClientConfig {
|
|
|
179
182
|
judge?: JudgeEndpointConfig;
|
|
180
183
|
nodeUrls?: string[];
|
|
181
184
|
blockchainRid?: string;
|
|
185
|
+
orgName?: string;
|
|
182
186
|
keyPath?: string;
|
|
183
187
|
keyPair?: {
|
|
184
188
|
privKey: string;
|
|
@@ -193,7 +197,7 @@ interface AtbashClientConfig {
|
|
|
193
197
|
|
|
194
198
|
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
195
199
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
196
|
-
declare const DEFAULT_BLOCKCHAIN_RID = "
|
|
200
|
+
declare const DEFAULT_BLOCKCHAIN_RID = "B91106947F1EAED7B5D789C7D35755330A8A7DD7CB990D59366114EFFB79ED10";
|
|
197
201
|
declare function isValidPrivateKey(hex: string): boolean;
|
|
198
202
|
declare function derivePublicKey(privKeyHex: string): string;
|
|
199
203
|
declare function generateKeyPair(): {
|
|
@@ -202,22 +206,7 @@ declare function generateKeyPair(): {
|
|
|
202
206
|
};
|
|
203
207
|
declare function loadAgent(privkey: string): AgentAuth;
|
|
204
208
|
declare function toPubkeyHex(val: unknown): string;
|
|
205
|
-
/**
|
|
206
|
-
* Check if an agent is onboarded before signing anything.
|
|
207
|
-
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
208
|
-
*/
|
|
209
209
|
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
210
|
-
/**
|
|
211
|
-
* Sign `log_tool_call` locally and return the signed transaction hex.
|
|
212
|
-
*
|
|
213
|
-
* Checks that the agent is onboarded before signing. The private key
|
|
214
|
-
* is used locally — never sent over the network. The server will
|
|
215
|
-
* broadcast the signed transaction to the chain.
|
|
216
|
-
*/
|
|
217
|
-
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
218
|
-
toolName?: string;
|
|
219
|
-
toolArgsJson?: string;
|
|
220
|
-
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
221
210
|
declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
|
|
222
211
|
declare function getJudgmentStatus(judgmentId: string, agentPubkey: string, opts?: ClientOpts): Promise<JudgmentStatus>;
|
|
223
212
|
declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
@@ -225,7 +214,7 @@ declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: Clien
|
|
|
225
214
|
declare function getAgentToolCalls(agentPubkey: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
226
215
|
declare function getToolCallCount(opts?: ClientOpts): Promise<number>;
|
|
227
216
|
declare function getToolCallFull(toolCallId: string, opts?: ClientOpts): Promise<ToolCallFull | null>;
|
|
228
|
-
declare function
|
|
217
|
+
declare function getOrgSubscription(orgName: string, opts?: ClientOpts): Promise<OrgSubscription | null>;
|
|
229
218
|
declare function getPendingHeldActions(orgName: string, maxCount: number, opts?: ClientOpts): Promise<HeldAction[]>;
|
|
230
219
|
declare function getHeldActionReviews(orgName: string, maxCount: number, opts?: ClientOpts): Promise<HeldActionReview[]>;
|
|
231
220
|
declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
@@ -277,6 +266,7 @@ interface AtbashUserConfig {
|
|
|
277
266
|
orgName?: string;
|
|
278
267
|
judgeEndpoint?: string;
|
|
279
268
|
blockchainRid?: string;
|
|
269
|
+
network?: string;
|
|
280
270
|
provider?: string;
|
|
281
271
|
providerModel?: string;
|
|
282
272
|
}
|
|
@@ -346,4 +336,4 @@ declare function normalizeForMatching(input: string): string;
|
|
|
346
336
|
*/
|
|
347
337
|
declare function containsEvasionCharacters(input: string): boolean;
|
|
348
338
|
|
|
349
|
-
export { type ActionType, type AgentAuth, type AgentPolicy, type AnomalySeverity, type AnomalyType, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type
|
|
339
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type AnomalySeverity, type AnomalyType, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type ClientOpts, type ClientSource, 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 MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type OrgSubscription, type Provider, type PubkeyValue, type TelemetryConfig, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, containsEvasionCharacters, createAtbashClient, createMemorySnapshot, derivePublicKey, diffMemorySnapshots, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgSubscription, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, normalizeForMatching, resolve, resolveKeyPath, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
|
|
2
2
|
type Provider = "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
3
|
-
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
4
3
|
type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
|
|
5
4
|
type PubkeyValue = string | Buffer | {
|
|
6
5
|
data: number[];
|
|
7
6
|
};
|
|
8
7
|
type JudgmentStatusState = "pending" | "answered" | "error";
|
|
8
|
+
interface Subscription {
|
|
9
|
+
subscription_name: string;
|
|
10
|
+
agent_number: number;
|
|
11
|
+
is_private_blockchain: boolean;
|
|
12
|
+
monthly_price: number;
|
|
13
|
+
yearly_price: number;
|
|
14
|
+
}
|
|
15
|
+
interface OrgSubscription extends Subscription {
|
|
16
|
+
org_name: string;
|
|
17
|
+
duration_months: number;
|
|
18
|
+
assigned_at: number;
|
|
19
|
+
expires_at: number;
|
|
20
|
+
is_active: boolean;
|
|
21
|
+
}
|
|
9
22
|
interface AgentAuth {
|
|
10
23
|
pubkey: string;
|
|
11
24
|
privkey: string;
|
|
@@ -13,17 +26,12 @@ interface AgentAuth {
|
|
|
13
26
|
interface ClientOpts {
|
|
14
27
|
endpoint?: string;
|
|
15
28
|
timeout?: number;
|
|
29
|
+
auth?: AgentAuth;
|
|
16
30
|
}
|
|
17
31
|
interface ChainOpts {
|
|
18
32
|
nodeUrls?: string[];
|
|
19
33
|
blockchainRid?: string;
|
|
20
34
|
}
|
|
21
|
-
interface LogToolCallResult {
|
|
22
|
-
success: boolean;
|
|
23
|
-
toolCallId: string | null;
|
|
24
|
-
signedHex?: string;
|
|
25
|
-
error?: string;
|
|
26
|
-
}
|
|
27
35
|
interface JudgeResult {
|
|
28
36
|
verdict: Verdict;
|
|
29
37
|
action_type: ActionType;
|
|
@@ -39,6 +47,7 @@ interface JudgeOptions extends ClientOpts {
|
|
|
39
47
|
model?: string;
|
|
40
48
|
toolName?: string;
|
|
41
49
|
toolArgsJson?: string;
|
|
50
|
+
orgName?: string;
|
|
42
51
|
chainOpts?: ChainOpts;
|
|
43
52
|
verifyPubKey?: string;
|
|
44
53
|
}
|
|
@@ -51,12 +60,6 @@ interface JudgmentStatus {
|
|
|
51
60
|
cached?: boolean;
|
|
52
61
|
responseTimeMs?: number;
|
|
53
62
|
}
|
|
54
|
-
interface TierInfo {
|
|
55
|
-
org_name: string;
|
|
56
|
-
tier: Tier;
|
|
57
|
-
verdict_enabled: boolean;
|
|
58
|
-
enforcement_enabled: boolean;
|
|
59
|
-
}
|
|
60
63
|
interface ToolCallRecord {
|
|
61
64
|
tool_call_id: string;
|
|
62
65
|
agent_pubkey: PubkeyValue;
|
|
@@ -179,6 +182,7 @@ interface AtbashClientConfig {
|
|
|
179
182
|
judge?: JudgeEndpointConfig;
|
|
180
183
|
nodeUrls?: string[];
|
|
181
184
|
blockchainRid?: string;
|
|
185
|
+
orgName?: string;
|
|
182
186
|
keyPath?: string;
|
|
183
187
|
keyPair?: {
|
|
184
188
|
privKey: string;
|
|
@@ -193,7 +197,7 @@ interface AtbashClientConfig {
|
|
|
193
197
|
|
|
194
198
|
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
195
199
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
196
|
-
declare const DEFAULT_BLOCKCHAIN_RID = "
|
|
200
|
+
declare const DEFAULT_BLOCKCHAIN_RID = "B91106947F1EAED7B5D789C7D35755330A8A7DD7CB990D59366114EFFB79ED10";
|
|
197
201
|
declare function isValidPrivateKey(hex: string): boolean;
|
|
198
202
|
declare function derivePublicKey(privKeyHex: string): string;
|
|
199
203
|
declare function generateKeyPair(): {
|
|
@@ -202,22 +206,7 @@ declare function generateKeyPair(): {
|
|
|
202
206
|
};
|
|
203
207
|
declare function loadAgent(privkey: string): AgentAuth;
|
|
204
208
|
declare function toPubkeyHex(val: unknown): string;
|
|
205
|
-
/**
|
|
206
|
-
* Check if an agent is onboarded before signing anything.
|
|
207
|
-
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
208
|
-
*/
|
|
209
209
|
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
210
|
-
/**
|
|
211
|
-
* Sign `log_tool_call` locally and return the signed transaction hex.
|
|
212
|
-
*
|
|
213
|
-
* Checks that the agent is onboarded before signing. The private key
|
|
214
|
-
* is used locally — never sent over the network. The server will
|
|
215
|
-
* broadcast the signed transaction to the chain.
|
|
216
|
-
*/
|
|
217
|
-
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
218
|
-
toolName?: string;
|
|
219
|
-
toolArgsJson?: string;
|
|
220
|
-
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
221
210
|
declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
|
|
222
211
|
declare function getJudgmentStatus(judgmentId: string, agentPubkey: string, opts?: ClientOpts): Promise<JudgmentStatus>;
|
|
223
212
|
declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
@@ -225,7 +214,7 @@ declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: Clien
|
|
|
225
214
|
declare function getAgentToolCalls(agentPubkey: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
226
215
|
declare function getToolCallCount(opts?: ClientOpts): Promise<number>;
|
|
227
216
|
declare function getToolCallFull(toolCallId: string, opts?: ClientOpts): Promise<ToolCallFull | null>;
|
|
228
|
-
declare function
|
|
217
|
+
declare function getOrgSubscription(orgName: string, opts?: ClientOpts): Promise<OrgSubscription | null>;
|
|
229
218
|
declare function getPendingHeldActions(orgName: string, maxCount: number, opts?: ClientOpts): Promise<HeldAction[]>;
|
|
230
219
|
declare function getHeldActionReviews(orgName: string, maxCount: number, opts?: ClientOpts): Promise<HeldActionReview[]>;
|
|
231
220
|
declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
@@ -277,6 +266,7 @@ interface AtbashUserConfig {
|
|
|
277
266
|
orgName?: string;
|
|
278
267
|
judgeEndpoint?: string;
|
|
279
268
|
blockchainRid?: string;
|
|
269
|
+
network?: string;
|
|
280
270
|
provider?: string;
|
|
281
271
|
providerModel?: string;
|
|
282
272
|
}
|
|
@@ -346,4 +336,4 @@ declare function normalizeForMatching(input: string): string;
|
|
|
346
336
|
*/
|
|
347
337
|
declare function containsEvasionCharacters(input: string): boolean;
|
|
348
338
|
|
|
349
|
-
export { type ActionType, type AgentAuth, type AgentPolicy, type AnomalySeverity, type AnomalyType, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type
|
|
339
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type AnomalySeverity, type AnomalyType, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type ClientOpts, type ClientSource, 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 MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type OrgSubscription, type Provider, type PubkeyValue, type TelemetryConfig, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, containsEvasionCharacters, createAtbashClient, createMemorySnapshot, derivePublicKey, diffMemorySnapshots, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgSubscription, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, normalizeForMatching, resolve, resolveKeyPath, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
|
package/dist/index.js
CHANGED
|
@@ -121,7 +121,37 @@ var DEFAULT_CHROMIA_NODE_URLS = [
|
|
|
121
121
|
"https://node1.testnet.chromia.com:7740",
|
|
122
122
|
"https://node3.testnet.chromia.com:7740"
|
|
123
123
|
];
|
|
124
|
-
var DEFAULT_BLOCKCHAIN_RID = "
|
|
124
|
+
var DEFAULT_BLOCKCHAIN_RID = "B91106947F1EAED7B5D789C7D35755330A8A7DD7CB990D59366114EFFB79ED10";
|
|
125
|
+
var DEFAULT_PRIVATE_NODE_URLS = [
|
|
126
|
+
"https://node0-pvn-testnet.dynamic.chromia.dev"
|
|
127
|
+
];
|
|
128
|
+
var DEFAULT_PRIVATE_BLOCKCHAIN_RID = "431AE6A5695D157D74194A61AB4D0B6A98C99AFEEF186FC885CDA4A3BAAB800E";
|
|
129
|
+
var PUBLIC_CHAIN = {
|
|
130
|
+
network: "public",
|
|
131
|
+
blockchainRid: DEFAULT_BLOCKCHAIN_RID,
|
|
132
|
+
nodeUrls: DEFAULT_CHROMIA_NODE_URLS
|
|
133
|
+
};
|
|
134
|
+
var PRIVATE_CHAIN = {
|
|
135
|
+
network: "private",
|
|
136
|
+
blockchainRid: DEFAULT_PRIVATE_BLOCKCHAIN_RID,
|
|
137
|
+
nodeUrls: DEFAULT_PRIVATE_NODE_URLS
|
|
138
|
+
};
|
|
139
|
+
function chainForNetwork(network) {
|
|
140
|
+
return network === "private" ? PRIVATE_CHAIN : PUBLIC_CHAIN;
|
|
141
|
+
}
|
|
142
|
+
function resolveChainOpts(chainOpts) {
|
|
143
|
+
if (chainOpts?.network) {
|
|
144
|
+
const chain = chainForNetwork(chainOpts.network);
|
|
145
|
+
return {
|
|
146
|
+
nodeUrls: chainOpts.nodeUrls ?? chain.nodeUrls,
|
|
147
|
+
blockchainRid: chainOpts.blockchainRid ?? chain.blockchainRid
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
nodeUrls: chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS,
|
|
152
|
+
blockchainRid: chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID
|
|
153
|
+
};
|
|
154
|
+
}
|
|
125
155
|
function isValidPrivateKey(hex) {
|
|
126
156
|
return /^[0-9a-fA-F]{64}$/.test(hex);
|
|
127
157
|
}
|
|
@@ -160,14 +190,30 @@ function toPubkeyHex(val) {
|
|
|
160
190
|
function baseUrl(opts) {
|
|
161
191
|
return opts?.endpoint || DEFAULT_ENDPOINT;
|
|
162
192
|
}
|
|
193
|
+
var AUTH_BEARER_REFRESH_MS = 4 * 60 * 1e3;
|
|
194
|
+
var bearerCache = /* @__PURE__ */ new Map();
|
|
195
|
+
async function getOrCreateAuthBearer(auth) {
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
const cached = bearerCache.get(auth.pubkey);
|
|
198
|
+
if (cached && now - cached.issuedAt < AUTH_BEARER_REFRESH_MS) {
|
|
199
|
+
return cached.hex;
|
|
200
|
+
}
|
|
201
|
+
const nonce = `auth-${now.toString(36)}-${randomBytes(4).toString("hex")}`;
|
|
202
|
+
const hex = await buildSignedTx(
|
|
203
|
+
"log_tool_call",
|
|
204
|
+
[nonce, `auth:${now}`, "", "auth-bearer", ""],
|
|
205
|
+
auth
|
|
206
|
+
);
|
|
207
|
+
bearerCache.set(auth.pubkey, { hex, issuedAt: now });
|
|
208
|
+
return hex;
|
|
209
|
+
}
|
|
163
210
|
function generateToolCallId() {
|
|
164
211
|
const ts = Date.now();
|
|
165
212
|
const rand = randomBytes(4).toString("hex");
|
|
166
213
|
return `tc-${ts}-${rand}`;
|
|
167
214
|
}
|
|
168
215
|
async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
169
|
-
const nodeUrls = chainOpts
|
|
170
|
-
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
216
|
+
const { nodeUrls, blockchainRid } = resolveChainOpts(chainOpts);
|
|
171
217
|
const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
|
|
172
218
|
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
173
219
|
const keyPair = encryption2.makeKeyPair(privKeyBuf);
|
|
@@ -184,11 +230,13 @@ async function buildSignedTx(opName, args, auth, chainOpts) {
|
|
|
184
230
|
);
|
|
185
231
|
return Buffer.from(signed).toString("hex");
|
|
186
232
|
}
|
|
187
|
-
async function
|
|
233
|
+
async function _checkAgentExists(pubkey, opts, chainOpts) {
|
|
188
234
|
const start = performance.now();
|
|
189
235
|
recordCall("checkAgentExists", void 0, pubkey);
|
|
190
236
|
try {
|
|
191
|
-
const
|
|
237
|
+
const network = chainOpts?.network;
|
|
238
|
+
let url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
239
|
+
if (network) url += `&network=${encodeURIComponent(network)}`;
|
|
192
240
|
const data = await getJson(url, opts);
|
|
193
241
|
recordDuration("checkAgentExists", performance.now() - start, "success");
|
|
194
242
|
return Boolean(data.registered);
|
|
@@ -197,10 +245,13 @@ async function checkAgentExists(pubkey, opts) {
|
|
|
197
245
|
throw err;
|
|
198
246
|
}
|
|
199
247
|
}
|
|
248
|
+
async function checkAgentExists(pubkey, opts) {
|
|
249
|
+
return _checkAgentExists(pubkey, opts);
|
|
250
|
+
}
|
|
200
251
|
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
201
252
|
const start = performance.now();
|
|
202
253
|
recordCall("logToolCall", void 0, auth.pubkey);
|
|
203
|
-
const exists = await
|
|
254
|
+
const exists = await _checkAgentExists(auth.pubkey, clientOpts, chainOpts);
|
|
204
255
|
if (!exists) {
|
|
205
256
|
recordDuration("logToolCall", performance.now() - start, "error");
|
|
206
257
|
return {
|
|
@@ -269,9 +320,13 @@ function enrichError(status, body, statusText, opts) {
|
|
|
269
320
|
return new Error(message);
|
|
270
321
|
}
|
|
271
322
|
async function postJson(url, body, opts) {
|
|
323
|
+
const headers = { "Content-Type": "application/json" };
|
|
324
|
+
if (opts?.auth) {
|
|
325
|
+
headers["Authorization"] = `Bearer ${await getOrCreateAuthBearer(opts.auth)}`;
|
|
326
|
+
}
|
|
272
327
|
const resp = await fetch(url, {
|
|
273
328
|
method: "POST",
|
|
274
|
-
headers
|
|
329
|
+
headers,
|
|
275
330
|
body: JSON.stringify(body),
|
|
276
331
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
277
332
|
});
|
|
@@ -283,9 +338,13 @@ async function postJson(url, body, opts) {
|
|
|
283
338
|
return ct.includes("application/json") ? resp.json() : {};
|
|
284
339
|
}
|
|
285
340
|
async function getJson(url, opts) {
|
|
341
|
+
const headers = { Accept: "application/json" };
|
|
342
|
+
if (opts?.auth) {
|
|
343
|
+
headers["Authorization"] = `Bearer ${await getOrCreateAuthBearer(opts.auth)}`;
|
|
344
|
+
}
|
|
286
345
|
const resp = await fetch(url, {
|
|
287
346
|
method: "GET",
|
|
288
|
-
headers
|
|
347
|
+
headers,
|
|
289
348
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
290
349
|
});
|
|
291
350
|
if (!resp.ok) {
|
|
@@ -326,11 +385,16 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
326
385
|
throw new Error("action is required and cannot be empty.");
|
|
327
386
|
}
|
|
328
387
|
try {
|
|
388
|
+
let chainOpts = opts?.chainOpts;
|
|
389
|
+
if (opts?.orgName && !chainOpts?.blockchainRid) {
|
|
390
|
+
const resolved = await resolveChainForOrg(opts.orgName, opts);
|
|
391
|
+
chainOpts = { ...chainOpts, network: resolved.network };
|
|
392
|
+
}
|
|
329
393
|
const logResult = await logToolCall(
|
|
330
394
|
action,
|
|
331
395
|
context,
|
|
332
396
|
auth,
|
|
333
|
-
|
|
397
|
+
chainOpts,
|
|
334
398
|
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
|
|
335
399
|
opts
|
|
336
400
|
);
|
|
@@ -344,7 +408,7 @@ async function judgeAction(action, context = "", auth, opts) {
|
|
|
344
408
|
"judge_action",
|
|
345
409
|
[judgmentId, action, context || "", ""],
|
|
346
410
|
auth,
|
|
347
|
-
|
|
411
|
+
chainOpts
|
|
348
412
|
);
|
|
349
413
|
}
|
|
350
414
|
const url = `${baseUrl(opts)}/api/v1/judge`;
|
|
@@ -489,21 +553,52 @@ async function getToolCallFull(toolCallId, opts) {
|
|
|
489
553
|
throw err;
|
|
490
554
|
}
|
|
491
555
|
}
|
|
492
|
-
|
|
556
|
+
function coerceOrgSubscription(row, orgName) {
|
|
557
|
+
if (!row || typeof row !== "object") return null;
|
|
558
|
+
const r = row;
|
|
559
|
+
return {
|
|
560
|
+
org_name: String(r.org_name ?? orgName),
|
|
561
|
+
subscription_name: String(r.subscription_name ?? ""),
|
|
562
|
+
agent_number: Number(r.agent_number ?? 0),
|
|
563
|
+
is_private_blockchain: Boolean(r.is_private_blockchain),
|
|
564
|
+
monthly_price: Number(r.monthly_price ?? 0),
|
|
565
|
+
yearly_price: Number(r.yearly_price ?? 0),
|
|
566
|
+
duration_months: Number(r.duration_months ?? 0),
|
|
567
|
+
assigned_at: Number(r.assigned_at ?? 0),
|
|
568
|
+
expires_at: Number(r.expires_at ?? 0),
|
|
569
|
+
is_active: Boolean(r.is_active)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
async function getOrgSubscription(orgName, opts) {
|
|
493
573
|
const start = performance.now();
|
|
494
|
-
recordCall("
|
|
574
|
+
recordCall("getOrgSubscription");
|
|
495
575
|
try {
|
|
496
576
|
const result = await getJson(
|
|
497
|
-
riskEngineUrl("org-
|
|
577
|
+
riskEngineUrl("org-subscription", { org: orgName }, opts),
|
|
498
578
|
opts
|
|
499
579
|
);
|
|
500
|
-
recordDuration("
|
|
501
|
-
return result;
|
|
580
|
+
recordDuration("getOrgSubscription", performance.now() - start, "success");
|
|
581
|
+
return coerceOrgSubscription(result, orgName);
|
|
502
582
|
} catch (err) {
|
|
503
|
-
recordDuration("
|
|
583
|
+
recordDuration("getOrgSubscription", performance.now() - start, "error");
|
|
504
584
|
throw err;
|
|
505
585
|
}
|
|
506
586
|
}
|
|
587
|
+
var _chainCache = /* @__PURE__ */ new Map();
|
|
588
|
+
async function resolveChainForOrg(orgName, opts) {
|
|
589
|
+
const cached = _chainCache.get(orgName);
|
|
590
|
+
if (cached) return cached;
|
|
591
|
+
try {
|
|
592
|
+
const sub = await getOrgSubscription(orgName, opts);
|
|
593
|
+
if (sub?.is_private_blockchain) {
|
|
594
|
+
_chainCache.set(orgName, PRIVATE_CHAIN);
|
|
595
|
+
return PRIVATE_CHAIN;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
_chainCache.set(orgName, PUBLIC_CHAIN);
|
|
600
|
+
return PUBLIC_CHAIN;
|
|
601
|
+
}
|
|
507
602
|
async function getPendingHeldActions(orgName, maxCount, opts) {
|
|
508
603
|
const start = performance.now();
|
|
509
604
|
recordCall("getPendingHeldActions");
|
|
@@ -759,6 +854,8 @@ function createAtbashClient(config = {}) {
|
|
|
759
854
|
const validated = validateJudgeEndpoint(config.judge);
|
|
760
855
|
const failClosed = config.failClosed !== false;
|
|
761
856
|
const logger = config.logger ?? {};
|
|
857
|
+
const orgName = config.orgName;
|
|
858
|
+
let resolvedChain = null;
|
|
762
859
|
const inlineKeyPair = config.keyPair;
|
|
763
860
|
const keyPath = inlineKeyPair ? null : config.keyPath;
|
|
764
861
|
if (validated.url !== DEFAULT_ENDPOINT) {
|
|
@@ -808,12 +905,23 @@ function createAtbashClient(config = {}) {
|
|
|
808
905
|
});
|
|
809
906
|
}
|
|
810
907
|
try {
|
|
908
|
+
if (!resolvedChain && orgName) {
|
|
909
|
+
resolvedChain = await resolveChainForOrg(orgName, { endpoint: validated.url });
|
|
910
|
+
config.nodeUrls = resolvedChain.nodeUrls;
|
|
911
|
+
config.blockchainRid = resolvedChain.blockchainRid;
|
|
912
|
+
logger.info?.("[atbash] resolved network from subscription", {
|
|
913
|
+
org: orgName,
|
|
914
|
+
network: resolvedChain.network,
|
|
915
|
+
brid: resolvedChain.blockchainRid
|
|
916
|
+
});
|
|
917
|
+
}
|
|
811
918
|
logger.info?.("[atbash] judge API called", { tool: toolName });
|
|
812
919
|
const result = await judgeAction(actionText, contextText, agent, {
|
|
813
920
|
endpoint: validated.url,
|
|
814
921
|
verifyPubKey: validated.verifyPubKey ?? void 0,
|
|
815
922
|
toolName,
|
|
816
923
|
toolArgsJson: argsJson,
|
|
924
|
+
orgName,
|
|
817
925
|
chainOpts: {
|
|
818
926
|
nodeUrls: config.nodeUrls,
|
|
819
927
|
blockchainRid: config.blockchainRid
|
|
@@ -901,6 +1009,7 @@ var ENV_MAP = {
|
|
|
901
1009
|
orgName: "ATBASH_ORG_NAME",
|
|
902
1010
|
judgeEndpoint: "ATBASH_ENDPOINT",
|
|
903
1011
|
blockchainRid: "ATBASH_BLOCKCHAIN_RID",
|
|
1012
|
+
network: "ATBASH_NETWORK",
|
|
904
1013
|
provider: "ATBASH_PROVIDER",
|
|
905
1014
|
providerModel: "ATBASH_PROVIDER_MODEL"
|
|
906
1015
|
};
|
|
@@ -1405,7 +1514,7 @@ export {
|
|
|
1405
1514
|
getConfigPath,
|
|
1406
1515
|
getHeldActionReviews,
|
|
1407
1516
|
getJudgmentStatus,
|
|
1408
|
-
|
|
1517
|
+
getOrgSubscription,
|
|
1409
1518
|
getOrgToolCalls,
|
|
1410
1519
|
getPendingHeldActions,
|
|
1411
1520
|
getSafetyStats,
|
|
@@ -1417,7 +1526,6 @@ export {
|
|
|
1417
1526
|
loadAgent,
|
|
1418
1527
|
loadAgentFromFile,
|
|
1419
1528
|
loadUserConfig,
|
|
1420
|
-
logToolCall,
|
|
1421
1529
|
normalizeForMatching,
|
|
1422
1530
|
resolve,
|
|
1423
1531
|
resolveKeyPath,
|