@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 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 in Enforcement tier
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, with a policy pack attached, and the org tier set to Audit+ or Enforcement.
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 transaction, `tool_call_id`, and `agent_pubkey` to the Atbash judge API. The server broadcasts it to the Chromia blockchain and returns a verdict.
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 in Enforcement tier |
91
+ | `BLOCK` | Violates a red line | Abort — agent is auto-jailed |
90
92
 
91
- > **NB:** If your org is on the **Audit** tier, the judge returns `"No verdict"` — actions are logged on-chain for the audit trail but not evaluated by an AI provider. Upgrade to **Audit+** or **Enforcement** at [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) for active verdicts.
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
- chainOpts?: ChainOpts; // Override Chromia chain connection
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
- | `getOrgTierInfo(orgName)` | Check an org's tier and whether verdicts are enabled |
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
- > **Advanced:** The SDK connects to the default Atbash Chromia chain. To use a different chain, pass `chainOpts` with custom `nodeUrls` and `blockchainRid` in `JudgeOptions`.
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 (Enforcement tier) | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
338
- | `Org tier does not support verdicts` | Org is on Audit tier | [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) |
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
- getOrgTierInfo: () => getOrgTierInfo,
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 = "619E62A5FD01BDDBFF0EF7A3821B5C88145B0E64A870400EAB4065C6A2779981";
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?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
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 checkAgentExists(pubkey, opts) {
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 url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
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 checkAgentExists(auth.pubkey, clientOpts);
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: { "Content-Type": "application/json" },
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: { Accept: "application/json" },
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
- opts?.chainOpts,
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
- opts?.chainOpts
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
- async function getOrgTierInfo(orgName, opts) {
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("getOrgTierInfo");
649
+ recordCall("getOrgSubscription");
571
650
  try {
572
651
  const result = await getJson(
573
- riskEngineUrl("org-tier-info", { org: orgName }, opts),
652
+ riskEngineUrl("org-subscription", { org: orgName }, opts),
574
653
  opts
575
654
  );
576
- recordDuration("getOrgTierInfo", performance.now() - start, "success");
577
- return result;
655
+ recordDuration("getOrgSubscription", performance.now() - start, "success");
656
+ return coerceOrgSubscription(result, orgName);
578
657
  } catch (err) {
579
- recordDuration("getOrgTierInfo", performance.now() - start, "error");
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
- getOrgTierInfo,
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 = "619E62A5FD01BDDBFF0EF7A3821B5C88145B0E64A870400EAB4065C6A2779981";
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 getOrgTierInfo(orgName: string, opts?: ClientOpts): Promise<TierInfo | null>;
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 ChainOpts, 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 LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type Provider, type PubkeyValue, type TelemetryConfig, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, containsEvasionCharacters, createAtbashClient, createMemorySnapshot, derivePublicKey, diffMemorySnapshots, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, logToolCall, normalizeForMatching, resolve, resolveKeyPath, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
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 = "619E62A5FD01BDDBFF0EF7A3821B5C88145B0E64A870400EAB4065C6A2779981";
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 getOrgTierInfo(orgName: string, opts?: ClientOpts): Promise<TierInfo | null>;
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 ChainOpts, 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 LogToolCallResult, type MemoryAnomaly, type MemoryDiffResult, type MemoryEntry, type MemoryScanOptions, type MemoryScanResult, type MemoryScanVerdict, type MemorySnapshot, type Provider, type PubkeyValue, type TelemetryConfig, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, containsEvasionCharacters, createAtbashClient, createMemorySnapshot, derivePublicKey, diffMemorySnapshots, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, logToolCall, normalizeForMatching, resolve, resolveKeyPath, saveUserConfig, scanMemory, scanMemoryBatch, setupTelemetry, shutdownTelemetry, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
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 = "619E62A5FD01BDDBFF0EF7A3821B5C88145B0E64A870400EAB4065C6A2779981";
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?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
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 checkAgentExists(pubkey, opts) {
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 url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
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 checkAgentExists(auth.pubkey, clientOpts);
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: { "Content-Type": "application/json" },
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: { Accept: "application/json" },
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
- opts?.chainOpts,
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
- opts?.chainOpts
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
- async function getOrgTierInfo(orgName, opts) {
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("getOrgTierInfo");
574
+ recordCall("getOrgSubscription");
495
575
  try {
496
576
  const result = await getJson(
497
- riskEngineUrl("org-tier-info", { org: orgName }, opts),
577
+ riskEngineUrl("org-subscription", { org: orgName }, opts),
498
578
  opts
499
579
  );
500
- recordDuration("getOrgTierInfo", performance.now() - start, "success");
501
- return result;
580
+ recordDuration("getOrgSubscription", performance.now() - start, "success");
581
+ return coerceOrgSubscription(result, orgName);
502
582
  } catch (err) {
503
- recordDuration("getOrgTierInfo", performance.now() - start, "error");
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
- getOrgTierInfo,
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atbash/sdk",
3
- "version": "0.3.23",
3
+ "version": "0.3.25",
4
4
  "description": "Atbash SDK — control boundary before the last irreversible step in an agent workflow",
5
5
  "homepage": "https://atbash.ai",
6
6
  "author": "Atbash",