@atbash/sdk 0.3.4 → 0.3.6

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
@@ -119,8 +119,6 @@ interface JudgeOptions {
119
119
  endpoint?: string; // API base URL (default: https://atbash.ai)
120
120
  timeout?: number; // Request timeout in ms
121
121
  provider?: string; // "openai" | "google" | "microsoft" | "custom"
122
- apiKey?: string; // API key for the AI provider
123
- providerEndpoint?: string; // Endpoint for microsoft/custom providers
124
122
  model?: string; // Model override (e.g. "gpt-4o-mini")
125
123
  toolName?: string; // Tool name for audit trail
126
124
  toolArgsJson?: string; // Tool arguments JSON for audit trail
@@ -128,8 +126,8 @@ interface JudgeOptions {
128
126
  }
129
127
 
130
128
  interface ChainOpts {
131
- nodeUrls?: string[]; // Chromia node URLs (defaults to testnet)
132
- blockchainRid?: string; // Blockchain RID (defaults to testnet)
129
+ nodeUrls?: string[]; // Chromia node URLs (uses the default nodeurls)
130
+ blockchainRid?: string; // Blockchain RID (uses the default chromia rid)
133
131
  }
134
132
 
135
133
  interface JudgeResult {
@@ -227,10 +225,9 @@ const result = await judgeAction(action, context, auth, {
227
225
  endpoint: "https://your-instance.example.com",
228
226
  });
229
227
 
230
- // Custom provider
228
+ // Custom provider (API keys are saved in the dashboard, not passed here)
231
229
  const result = await judgeAction(action, context, auth, {
232
230
  provider: "openai",
233
- apiKey: process.env.OPENAI_API_KEY,
234
231
  model: "gpt-4o",
235
232
  });
236
233
 
@@ -290,7 +287,7 @@ API error 404: {"error":"Agent not registered..."}
290
287
  | `Agent is jailed` | BLOCK verdict triggered auto-jail (Enforcement tier) | [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) |
291
288
  | `Org tier does not support verdicts` | Org is on Audit tier | [atbash.ai/risk-engine/settings](https://atbash.ai/risk-engine/settings) |
292
289
  | `API error 400: action is required` | Empty action string | Fix caller |
293
- | `API error 502: Incorrect API key` | Invalid provider API key | Check `apiKey` in `JudgeOptions` |
290
+ | `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) |
294
291
 
295
292
  ```ts
296
293
  try {
package/dist/index.cjs CHANGED
@@ -110,6 +110,25 @@ function generateToolCallId() {
110
110
  const rand = (0, import_crypto.randomBytes)(4).toString("hex");
111
111
  return `tc-${ts}-${rand}`;
112
112
  }
113
+ async function buildSignedTx(opName, args, auth, chainOpts) {
114
+ const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
115
+ const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
116
+ const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
117
+ const privKeyBuf = Buffer.from(auth.privkey, "hex");
118
+ const keyPair = encryption.makeKeyPair(privKeyBuf);
119
+ const sigProvider = newSignatureProvider({
120
+ privKey: keyPair.privKey,
121
+ pubKey: keyPair.pubKey
122
+ });
123
+ const signed = await client.signTransaction(
124
+ {
125
+ operations: [{ name: opName, args }],
126
+ signers: [keyPair.pubKey]
127
+ },
128
+ sigProvider
129
+ );
130
+ return Buffer.from(signed).toString("hex");
131
+ }
113
132
  async function checkAgentExists(pubkey, opts) {
114
133
  const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
115
134
  const data = await getJson(url, opts);
@@ -125,38 +144,25 @@ async function logToolCall(action, context, auth, chainOpts, extra, clientOpts)
125
144
  };
126
145
  }
127
146
  try {
128
- const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
129
- const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
130
- const client = await createClient({
131
- nodeUrlPool: nodeUrls,
132
- blockchainRid
133
- });
134
- const privKeyBuf = Buffer.from(auth.privkey, "hex");
135
- const keyPair = encryption.makeKeyPair(privKeyBuf);
136
- const sigProvider = newSignatureProvider({
137
- privKey: keyPair.privKey,
138
- pubKey: keyPair.pubKey
139
- });
140
147
  const toolCallId = generateToolCallId();
141
- await client.signAndSendUniqueTransaction(
142
- {
143
- name: "log_tool_call",
144
- args: [
145
- toolCallId,
146
- action,
147
- context || "",
148
- extra?.toolName || "",
149
- extra?.toolArgsJson || ""
150
- ]
151
- },
152
- sigProvider
148
+ const signedHex = await buildSignedTx(
149
+ "log_tool_call",
150
+ [
151
+ toolCallId,
152
+ action,
153
+ context || "",
154
+ extra?.toolName || "",
155
+ extra?.toolArgsJson || ""
156
+ ],
157
+ auth,
158
+ chainOpts
153
159
  );
154
- return { success: true, toolCallId };
160
+ return { success: true, toolCallId, signedHex };
155
161
  } catch (err) {
156
162
  return {
157
163
  success: false,
158
164
  toolCallId: null,
159
- error: err instanceof Error ? err.message : "Failed to log tool call on-chain"
165
+ error: err instanceof Error ? err.message : "Failed to sign log_tool_call"
160
166
  };
161
167
  }
162
168
  }
@@ -220,7 +226,7 @@ async function getJson(url, opts) {
220
226
  }
221
227
  return resp.json();
222
228
  }
223
- async function judgeAction(action, context, auth, opts) {
229
+ async function judgeAction(action, context = "", auth, opts) {
224
230
  if (!action || !action.trim()) {
225
231
  throw new Error("action is required and cannot be empty.");
226
232
  }
@@ -232,25 +238,32 @@ async function judgeAction(action, context, auth, opts) {
232
238
  { toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
233
239
  opts
234
240
  );
235
- if (!logResult.success || !logResult.toolCallId) {
236
- throw new Error(logResult.error || "Failed to log tool call on-chain");
241
+ if (!logResult.success || !logResult.toolCallId || !logResult.signedHex) {
242
+ throw new Error(logResult.error || "Failed to sign log_tool_call");
243
+ }
244
+ let signedJudgeActionHex;
245
+ if (!opts?.provider) {
246
+ const judgmentId = generateToolCallId();
247
+ signedJudgeActionHex = await buildSignedTx(
248
+ "judge_action",
249
+ [judgmentId, action, context || "", ""],
250
+ auth,
251
+ opts?.chainOpts
252
+ );
237
253
  }
238
254
  const url = `${baseUrl(opts)}/api/v1/judge`;
239
- const data = await postJson(
240
- url,
241
- {
242
- tool_call_id: logResult.toolCallId,
243
- agent_pubkey: auth.pubkey,
244
- action,
245
- ...context && { context },
246
- ...opts?.provider && { provider: opts.provider },
247
- ...opts?.toolName && { tool_name: opts.toolName },
248
- ...opts?.apiKey && { api_key: opts.apiKey },
249
- ...opts?.providerEndpoint && { endpoint_url: opts.providerEndpoint },
250
- ...opts?.model && { model: opts.model }
251
- },
252
- opts
253
- );
255
+ const body = {
256
+ tool_call_id: logResult.toolCallId,
257
+ agent_pubkey: auth.pubkey,
258
+ action,
259
+ signed_log_tool_call: logResult.signedHex,
260
+ ...signedJudgeActionHex && { signed_judge_action: signedJudgeActionHex },
261
+ ...context && { context },
262
+ ...opts?.provider && { provider: opts.provider },
263
+ ...opts?.toolName && { tool_name: opts.toolName },
264
+ ...opts?.model && { model: opts.model }
265
+ };
266
+ const data = await postJson(url, body, opts);
254
267
  return {
255
268
  verdict: normalizeVerdict(data.verdict),
256
269
  action_type: String(data.action_type || ""),
package/dist/index.d.cts CHANGED
@@ -21,6 +21,7 @@ interface ChainOpts {
21
21
  interface LogToolCallResult {
22
22
  success: boolean;
23
23
  toolCallId: string | null;
24
+ signedHex?: string;
24
25
  error?: string;
25
26
  }
26
27
  interface JudgeResult {
@@ -35,8 +36,6 @@ interface JudgeResult {
35
36
  }
36
37
  interface JudgeOptions extends ClientOpts {
37
38
  provider?: Provider;
38
- apiKey?: string;
39
- providerEndpoint?: string;
40
39
  model?: string;
41
40
  toolName?: string;
42
41
  toolArgsJson?: string;
@@ -125,16 +124,17 @@ declare function toPubkeyHex(val: unknown): string;
125
124
  */
126
125
  declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
127
126
  /**
128
- * Sign and broadcast `log_tool_call` to the Chromia chain.
127
+ * Sign `log_tool_call` locally and return the signed transaction hex.
129
128
  *
130
- * Checks that the agent is onboarded before signing. The agent's private
131
- * key is used to sign the transaction locally — never sent over the network.
129
+ * Checks that the agent is onboarded before signing. The private key
130
+ * is used locally — never sent over the network. The server will
131
+ * broadcast the signed transaction to the chain.
132
132
  */
133
133
  declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
134
134
  toolName?: string;
135
135
  toolArgsJson?: string;
136
136
  }, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
137
- declare function judgeAction(action: string, context: string, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
137
+ declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
138
138
  declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
139
139
  declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
140
140
  declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
package/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ interface ChainOpts {
21
21
  interface LogToolCallResult {
22
22
  success: boolean;
23
23
  toolCallId: string | null;
24
+ signedHex?: string;
24
25
  error?: string;
25
26
  }
26
27
  interface JudgeResult {
@@ -35,8 +36,6 @@ interface JudgeResult {
35
36
  }
36
37
  interface JudgeOptions extends ClientOpts {
37
38
  provider?: Provider;
38
- apiKey?: string;
39
- providerEndpoint?: string;
40
39
  model?: string;
41
40
  toolName?: string;
42
41
  toolArgsJson?: string;
@@ -125,16 +124,17 @@ declare function toPubkeyHex(val: unknown): string;
125
124
  */
126
125
  declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
127
126
  /**
128
- * Sign and broadcast `log_tool_call` to the Chromia chain.
127
+ * Sign `log_tool_call` locally and return the signed transaction hex.
129
128
  *
130
- * Checks that the agent is onboarded before signing. The agent's private
131
- * key is used to sign the transaction locally — never sent over the network.
129
+ * Checks that the agent is onboarded before signing. The private key
130
+ * is used locally — never sent over the network. The server will
131
+ * broadcast the signed transaction to the chain.
132
132
  */
133
133
  declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
134
134
  toolName?: string;
135
135
  toolArgsJson?: string;
136
136
  }, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
137
- declare function judgeAction(action: string, context: string, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
137
+ declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
138
138
  declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
139
139
  declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
140
140
  declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
package/dist/index.js CHANGED
@@ -52,6 +52,25 @@ function generateToolCallId() {
52
52
  const rand = randomBytes(4).toString("hex");
53
53
  return `tc-${ts}-${rand}`;
54
54
  }
55
+ async function buildSignedTx(opName, args, auth, chainOpts) {
56
+ const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
57
+ const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
58
+ const client = await createClient({ nodeUrlPool: nodeUrls, blockchainRid });
59
+ const privKeyBuf = Buffer.from(auth.privkey, "hex");
60
+ const keyPair = encryption.makeKeyPair(privKeyBuf);
61
+ const sigProvider = newSignatureProvider({
62
+ privKey: keyPair.privKey,
63
+ pubKey: keyPair.pubKey
64
+ });
65
+ const signed = await client.signTransaction(
66
+ {
67
+ operations: [{ name: opName, args }],
68
+ signers: [keyPair.pubKey]
69
+ },
70
+ sigProvider
71
+ );
72
+ return Buffer.from(signed).toString("hex");
73
+ }
55
74
  async function checkAgentExists(pubkey, opts) {
56
75
  const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
57
76
  const data = await getJson(url, opts);
@@ -67,38 +86,25 @@ async function logToolCall(action, context, auth, chainOpts, extra, clientOpts)
67
86
  };
68
87
  }
69
88
  try {
70
- const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
71
- const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
72
- const client = await createClient({
73
- nodeUrlPool: nodeUrls,
74
- blockchainRid
75
- });
76
- const privKeyBuf = Buffer.from(auth.privkey, "hex");
77
- const keyPair = encryption.makeKeyPair(privKeyBuf);
78
- const sigProvider = newSignatureProvider({
79
- privKey: keyPair.privKey,
80
- pubKey: keyPair.pubKey
81
- });
82
89
  const toolCallId = generateToolCallId();
83
- await client.signAndSendUniqueTransaction(
84
- {
85
- name: "log_tool_call",
86
- args: [
87
- toolCallId,
88
- action,
89
- context || "",
90
- extra?.toolName || "",
91
- extra?.toolArgsJson || ""
92
- ]
93
- },
94
- sigProvider
90
+ const signedHex = await buildSignedTx(
91
+ "log_tool_call",
92
+ [
93
+ toolCallId,
94
+ action,
95
+ context || "",
96
+ extra?.toolName || "",
97
+ extra?.toolArgsJson || ""
98
+ ],
99
+ auth,
100
+ chainOpts
95
101
  );
96
- return { success: true, toolCallId };
102
+ return { success: true, toolCallId, signedHex };
97
103
  } catch (err) {
98
104
  return {
99
105
  success: false,
100
106
  toolCallId: null,
101
- error: err instanceof Error ? err.message : "Failed to log tool call on-chain"
107
+ error: err instanceof Error ? err.message : "Failed to sign log_tool_call"
102
108
  };
103
109
  }
104
110
  }
@@ -162,7 +168,7 @@ async function getJson(url, opts) {
162
168
  }
163
169
  return resp.json();
164
170
  }
165
- async function judgeAction(action, context, auth, opts) {
171
+ async function judgeAction(action, context = "", auth, opts) {
166
172
  if (!action || !action.trim()) {
167
173
  throw new Error("action is required and cannot be empty.");
168
174
  }
@@ -174,25 +180,32 @@ async function judgeAction(action, context, auth, opts) {
174
180
  { toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
175
181
  opts
176
182
  );
177
- if (!logResult.success || !logResult.toolCallId) {
178
- throw new Error(logResult.error || "Failed to log tool call on-chain");
183
+ if (!logResult.success || !logResult.toolCallId || !logResult.signedHex) {
184
+ throw new Error(logResult.error || "Failed to sign log_tool_call");
185
+ }
186
+ let signedJudgeActionHex;
187
+ if (!opts?.provider) {
188
+ const judgmentId = generateToolCallId();
189
+ signedJudgeActionHex = await buildSignedTx(
190
+ "judge_action",
191
+ [judgmentId, action, context || "", ""],
192
+ auth,
193
+ opts?.chainOpts
194
+ );
179
195
  }
180
196
  const url = `${baseUrl(opts)}/api/v1/judge`;
181
- const data = await postJson(
182
- url,
183
- {
184
- tool_call_id: logResult.toolCallId,
185
- agent_pubkey: auth.pubkey,
186
- action,
187
- ...context && { context },
188
- ...opts?.provider && { provider: opts.provider },
189
- ...opts?.toolName && { tool_name: opts.toolName },
190
- ...opts?.apiKey && { api_key: opts.apiKey },
191
- ...opts?.providerEndpoint && { endpoint_url: opts.providerEndpoint },
192
- ...opts?.model && { model: opts.model }
193
- },
194
- opts
195
- );
197
+ const body = {
198
+ tool_call_id: logResult.toolCallId,
199
+ agent_pubkey: auth.pubkey,
200
+ action,
201
+ signed_log_tool_call: logResult.signedHex,
202
+ ...signedJudgeActionHex && { signed_judge_action: signedJudgeActionHex },
203
+ ...context && { context },
204
+ ...opts?.provider && { provider: opts.provider },
205
+ ...opts?.toolName && { tool_name: opts.toolName },
206
+ ...opts?.model && { model: opts.model }
207
+ };
208
+ const data = await postJson(url, body, opts);
196
209
  return {
197
210
  verdict: normalizeVerdict(data.verdict),
198
211
  action_type: String(data.action_type || ""),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atbash/sdk",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
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",