@atbash/sdk 0.3.3 → 0.3.5
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 +45 -50
- package/dist/index.cjs +64 -51
- package/dist/index.d.cts +47 -46
- package/dist/index.d.ts +47 -46
- package/dist/index.js +64 -51
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @atbash/sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for the
|
|
3
|
+
TypeScript SDK for Atbash — the safety layer that evaluates AI agent actions against operator-defined policies before execution.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,16 +8,16 @@ TypeScript SDK for the Atbash judge and risk-engine APIs. Evaluate agent actions
|
|
|
8
8
|
npm install @atbash/sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Requires Node.js 18
|
|
11
|
+
Requires Node.js 18+. Server-side only — private keys are used for local signing and must never be exposed to browsers.
|
|
12
12
|
|
|
13
13
|
## Quickstart
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
import { loadAgent, judgeAction } from "@atbash/sdk";
|
|
17
17
|
|
|
18
|
-
// 1. Load your agent identity
|
|
19
|
-
//
|
|
20
|
-
//
|
|
18
|
+
// 1. Load your agent identity using the private key you saved during
|
|
19
|
+
// agent creation. loadAgent() validates the key and derives the
|
|
20
|
+
// matching public key for you.
|
|
21
21
|
const agent = loadAgent(process.env.ATBASH_AGENT_PRIVKEY!);
|
|
22
22
|
|
|
23
23
|
// 2. Submit an action for judgment, before executing it.
|
|
@@ -57,7 +57,11 @@ If you need finer control, you can call `logToolCall()` and the judge API separa
|
|
|
57
57
|
|
|
58
58
|
### Don't have an agent yet?
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
There are two ways to create an agent:
|
|
61
|
+
|
|
62
|
+
1. **Dashboard (recommended)** — create an agent at [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents). The dashboard generates the keypair, assigns the agent to your org, and lets you attach a policy pack — all in one step.
|
|
63
|
+
|
|
64
|
+
2. **Programmatic** — generate a new keypair locally or bring an existing secp256k1 private key from another platform, then onboard it via the dashboard:
|
|
61
65
|
|
|
62
66
|
```ts
|
|
63
67
|
import { generateKeyPair, loadAgent } from "@atbash/sdk";
|
|
@@ -67,7 +71,7 @@ console.log("Save this private key somewhere safe:", privKey);
|
|
|
67
71
|
const agent = loadAgent(privKey);
|
|
68
72
|
```
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
> **Note:** After generating a key programmatically, you must still onboard the agent at [atbash.ai/risk-engine/agents](https://atbash.ai/risk-engine/agents) — assign it to an org and attach a policy pack before `judgeAction` will work.
|
|
71
75
|
|
|
72
76
|
### Secret storage
|
|
73
77
|
|
|
@@ -88,6 +92,8 @@ Every `judgeAction` call returns one of three verdicts:
|
|
|
88
92
|
| `HOLD` | Requires operator review | Pause — poll `getJudgmentStatus` until resolved |
|
|
89
93
|
| `BLOCK` | Violates a red line | Abort — agent is jailed in Enforcement tier |
|
|
90
94
|
|
|
95
|
+
> **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.
|
|
96
|
+
|
|
91
97
|
## API
|
|
92
98
|
|
|
93
99
|
### Judge
|
|
@@ -122,8 +128,8 @@ interface JudgeOptions {
|
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
interface ChainOpts {
|
|
125
|
-
nodeUrls?: string[]; // Chromia node URLs (
|
|
126
|
-
blockchainRid?: string; // Blockchain RID (
|
|
131
|
+
nodeUrls?: string[]; // Chromia node URLs (uses the default nodeurls)
|
|
132
|
+
blockchainRid?: string; // Blockchain RID (uses the default chromia rid)
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
interface JudgeResult {
|
|
@@ -147,10 +153,10 @@ logToolCall(
|
|
|
147
153
|
auth: AgentAuth,
|
|
148
154
|
chainOpts?: ChainOpts,
|
|
149
155
|
extra?: { toolName?: string; toolArgsJson?: string },
|
|
150
|
-
): Promise<
|
|
156
|
+
): Promise<LogToolCallResult>
|
|
151
157
|
```
|
|
152
158
|
|
|
153
|
-
Sign
|
|
159
|
+
Sign `log_tool_call` on the Chromia chain. Returns `{ success, toolCallId, error? }`. Use this if you need to separate the on-chain logging step from the verdict request.
|
|
154
160
|
|
|
155
161
|
### Poll judgment status
|
|
156
162
|
|
|
@@ -184,39 +190,32 @@ toPubkeyHex(val: unknown): string
|
|
|
184
190
|
|
|
185
191
|
`loadAgent(privkey)` is the canonical loader — pass in the private key from the dashboard, get back `{ pubkey, privkey }` ready for `judgeAction`. It accepts `0x`-prefixed, padded, or mixed-case input and throws on malformed keys. Use `generateKeyPair()` only for local development; for production, create agents in the dashboard so operators can attach policies.
|
|
186
192
|
|
|
187
|
-
###
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
```ts
|
|
215
|
-
interface ClientOpts {
|
|
216
|
-
endpoint?: string; // Default: https://atbash.ai
|
|
217
|
-
timeout?: number;
|
|
218
|
-
}
|
|
219
|
-
```
|
|
193
|
+
### Operations
|
|
194
|
+
|
|
195
|
+
Functions that sign transactions and write to the Chromia blockchain.
|
|
196
|
+
|
|
197
|
+
| Function | Use case |
|
|
198
|
+
|----------|----------|
|
|
199
|
+
| `judgeAction(action, context, auth, opts?)` | Sign `log_tool_call` on-chain + request a verdict from the judge API |
|
|
200
|
+
| `logToolCall(action, context, auth, ...)` | Sign and broadcast `log_tool_call` to chain without requesting a verdict |
|
|
201
|
+
|
|
202
|
+
### Queries
|
|
203
|
+
|
|
204
|
+
| Function | Use case |
|
|
205
|
+
|----------|----------|
|
|
206
|
+
| `checkAgentExists(pubkey, opts?)` | Check if an agent is onboarded before signing |
|
|
207
|
+
| `getJudgmentStatus(judgmentId, opts?)` | Poll whether a held action has been approved or rejected |
|
|
208
|
+
| `getToolCalls(maxCount)` | List recent tool calls across all agents |
|
|
209
|
+
| `getOrgToolCalls(orgName, maxCount)` | List tool calls for a specific org |
|
|
210
|
+
| `getAgentToolCalls(pubkey, maxCount)` | List tool calls for a specific agent |
|
|
211
|
+
| `getToolCallCount()` | Get total number of tool calls on-chain |
|
|
212
|
+
| `getToolCallFull(toolCallId)` | Get full details of a single tool call (verdict, context, timing) |
|
|
213
|
+
| `getOrgTierInfo(orgName)` | Check an org's tier and whether verdicts are enabled |
|
|
214
|
+
| `getAgentDetail(pubkey)` | Get agent metadata (org, status, creation date) |
|
|
215
|
+
| `getAgentPolicy(pubkey)` | Check agent's policy pack and jail status |
|
|
216
|
+
| `getPendingHeldActions(orgName, maxCount)` | List actions waiting for operator approval |
|
|
217
|
+
| `getHeldActionReviews(orgName, maxCount)` | List completed operator reviews |
|
|
218
|
+
| `getSafetyStats()` | Get chain-wide safety statistics (total judgments, verdicts, etc.) |
|
|
220
219
|
|
|
221
220
|
## Configuration
|
|
222
221
|
|
|
@@ -235,14 +234,10 @@ const result = await judgeAction(action, context, auth, {
|
|
|
235
234
|
model: "gpt-4o",
|
|
236
235
|
});
|
|
237
236
|
|
|
238
|
-
// Custom Chromia chain (e.g. production RID)
|
|
239
|
-
const result = await judgeAction(action, context, auth, {
|
|
240
|
-
chainOpts: {
|
|
241
|
-
blockchainRid: "YOUR_PRODUCTION_BLOCKCHAIN_RID",
|
|
242
|
-
},
|
|
243
|
-
});
|
|
244
237
|
```
|
|
245
238
|
|
|
239
|
+
> **Advanced:** The SDK connects to the default Atbash Chromia chain. To use a different chain, pass `chainOpts` with custom `nodeUrls` and `blockchainRid` in `JudgeOptions`.
|
|
240
|
+
|
|
246
241
|
## Integration patterns
|
|
247
242
|
|
|
248
243
|
### Pre-execution gate
|
package/dist/index.cjs
CHANGED
|
@@ -110,14 +110,29 @@ 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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return Boolean(data.registered);
|
|
118
|
-
} catch {
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
133
|
+
const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
134
|
+
const data = await getJson(url, opts);
|
|
135
|
+
return Boolean(data.registered);
|
|
121
136
|
}
|
|
122
137
|
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
123
138
|
const exists = await checkAgentExists(auth.pubkey, clientOpts);
|
|
@@ -129,38 +144,25 @@ async function logToolCall(action, context, auth, chainOpts, extra, clientOpts)
|
|
|
129
144
|
};
|
|
130
145
|
}
|
|
131
146
|
try {
|
|
132
|
-
const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
|
|
133
|
-
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
134
|
-
const client = await createClient({
|
|
135
|
-
nodeUrlPool: nodeUrls,
|
|
136
|
-
blockchainRid
|
|
137
|
-
});
|
|
138
|
-
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
139
|
-
const keyPair = encryption.makeKeyPair(privKeyBuf);
|
|
140
|
-
const sigProvider = newSignatureProvider({
|
|
141
|
-
privKey: keyPair.privKey,
|
|
142
|
-
pubKey: keyPair.pubKey
|
|
143
|
-
});
|
|
144
147
|
const toolCallId = generateToolCallId();
|
|
145
|
-
await
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
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
|
|
157
159
|
);
|
|
158
|
-
return { success: true, toolCallId };
|
|
160
|
+
return { success: true, toolCallId, signedHex };
|
|
159
161
|
} catch (err) {
|
|
160
162
|
return {
|
|
161
163
|
success: false,
|
|
162
164
|
toolCallId: null,
|
|
163
|
-
error: err instanceof Error ? err.message : "Failed to
|
|
165
|
+
error: err instanceof Error ? err.message : "Failed to sign log_tool_call"
|
|
164
166
|
};
|
|
165
167
|
}
|
|
166
168
|
}
|
|
@@ -215,6 +217,7 @@ async function postJson(url, body, opts) {
|
|
|
215
217
|
async function getJson(url, opts) {
|
|
216
218
|
const resp = await fetch(url, {
|
|
217
219
|
method: "GET",
|
|
220
|
+
headers: { Accept: "application/json" },
|
|
218
221
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
219
222
|
});
|
|
220
223
|
if (!resp.ok) {
|
|
@@ -223,7 +226,10 @@ async function getJson(url, opts) {
|
|
|
223
226
|
}
|
|
224
227
|
return resp.json();
|
|
225
228
|
}
|
|
226
|
-
async function judgeAction(action, context, auth, opts) {
|
|
229
|
+
async function judgeAction(action, context = "", auth, opts) {
|
|
230
|
+
if (!action || !action.trim()) {
|
|
231
|
+
throw new Error("action is required and cannot be empty.");
|
|
232
|
+
}
|
|
227
233
|
const logResult = await logToolCall(
|
|
228
234
|
action,
|
|
229
235
|
context,
|
|
@@ -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
|
|
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
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
2
|
-
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
3
|
-
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
4
1
|
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
|
|
5
2
|
type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
6
3
|
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
@@ -9,18 +6,10 @@ type PubkeyValue = string | Buffer | {
|
|
|
9
6
|
data: number[];
|
|
10
7
|
};
|
|
11
8
|
type JudgmentStatusState = "pending" | "answered" | "error";
|
|
12
|
-
declare function isValidPrivateKey(hex: string): boolean;
|
|
13
|
-
declare function derivePublicKey(privKeyHex: string): string;
|
|
14
|
-
declare function generateKeyPair(): {
|
|
15
|
-
privKey: string;
|
|
16
|
-
pubKey: string;
|
|
17
|
-
};
|
|
18
9
|
interface AgentAuth {
|
|
19
10
|
pubkey: string;
|
|
20
11
|
privkey: string;
|
|
21
12
|
}
|
|
22
|
-
declare function loadAgent(privkey: string): AgentAuth;
|
|
23
|
-
declare function toPubkeyHex(val: unknown): string;
|
|
24
13
|
interface ClientOpts {
|
|
25
14
|
endpoint?: string;
|
|
26
15
|
timeout?: number;
|
|
@@ -32,23 +21,9 @@ interface ChainOpts {
|
|
|
32
21
|
interface LogToolCallResult {
|
|
33
22
|
success: boolean;
|
|
34
23
|
toolCallId: string | null;
|
|
24
|
+
signedHex?: string;
|
|
35
25
|
error?: string;
|
|
36
26
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Check if an agent is onboarded before signing anything.
|
|
39
|
-
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
40
|
-
*/
|
|
41
|
-
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* Sign and broadcast `log_tool_call` to the Chromia chain.
|
|
44
|
-
*
|
|
45
|
-
* Checks that the agent is onboarded before signing. The agent's private
|
|
46
|
-
* key is used to sign the transaction locally — never sent over the network.
|
|
47
|
-
*/
|
|
48
|
-
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
49
|
-
toolName?: string;
|
|
50
|
-
toolArgsJson?: string;
|
|
51
|
-
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
52
27
|
interface JudgeResult {
|
|
53
28
|
verdict: Verdict;
|
|
54
29
|
action_type: ActionType;
|
|
@@ -59,6 +34,22 @@ interface JudgeResult {
|
|
|
59
34
|
tool_call_id: string;
|
|
60
35
|
on_chain: boolean;
|
|
61
36
|
}
|
|
37
|
+
interface JudgeOptions extends ClientOpts {
|
|
38
|
+
provider?: Provider;
|
|
39
|
+
model?: string;
|
|
40
|
+
toolName?: string;
|
|
41
|
+
toolArgsJson?: string;
|
|
42
|
+
chainOpts?: ChainOpts;
|
|
43
|
+
}
|
|
44
|
+
interface JudgmentStatus {
|
|
45
|
+
status: JudgmentStatusState;
|
|
46
|
+
verdict: Verdict;
|
|
47
|
+
reason: string;
|
|
48
|
+
judgmentId: string;
|
|
49
|
+
onChain?: boolean;
|
|
50
|
+
cached?: boolean;
|
|
51
|
+
responseTimeMs?: number;
|
|
52
|
+
}
|
|
62
53
|
interface TierInfo {
|
|
63
54
|
org_name: string;
|
|
64
55
|
tier: Tier;
|
|
@@ -109,31 +100,41 @@ interface HeldActionReview {
|
|
|
109
100
|
reviewed_at: number;
|
|
110
101
|
created_at: number;
|
|
111
102
|
}
|
|
112
|
-
interface JudgmentStatus {
|
|
113
|
-
status: JudgmentStatusState;
|
|
114
|
-
verdict: Verdict;
|
|
115
|
-
reason: string;
|
|
116
|
-
judgmentId: string;
|
|
117
|
-
onChain?: boolean;
|
|
118
|
-
cached?: boolean;
|
|
119
|
-
responseTimeMs?: number;
|
|
120
|
-
}
|
|
121
|
-
interface JudgeOptions extends ClientOpts {
|
|
122
|
-
provider?: Provider;
|
|
123
|
-
apiKey?: string;
|
|
124
|
-
providerEndpoint?: string;
|
|
125
|
-
model?: string;
|
|
126
|
-
toolName?: string;
|
|
127
|
-
toolArgsJson?: string;
|
|
128
|
-
chainOpts?: ChainOpts;
|
|
129
|
-
}
|
|
130
103
|
interface AgentPolicy {
|
|
131
104
|
policy: string;
|
|
132
105
|
is_jailed: boolean;
|
|
133
106
|
is_custom: boolean;
|
|
134
107
|
default_policy: string;
|
|
135
108
|
}
|
|
136
|
-
|
|
109
|
+
|
|
110
|
+
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
111
|
+
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
112
|
+
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
113
|
+
declare function isValidPrivateKey(hex: string): boolean;
|
|
114
|
+
declare function derivePublicKey(privKeyHex: string): string;
|
|
115
|
+
declare function generateKeyPair(): {
|
|
116
|
+
privKey: string;
|
|
117
|
+
pubKey: string;
|
|
118
|
+
};
|
|
119
|
+
declare function loadAgent(privkey: string): AgentAuth;
|
|
120
|
+
declare function toPubkeyHex(val: unknown): string;
|
|
121
|
+
/**
|
|
122
|
+
* Check if an agent is onboarded before signing anything.
|
|
123
|
+
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
124
|
+
*/
|
|
125
|
+
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* Sign `log_tool_call` locally and return the signed transaction hex.
|
|
128
|
+
*
|
|
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
|
+
*/
|
|
133
|
+
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
134
|
+
toolName?: string;
|
|
135
|
+
toolArgsJson?: string;
|
|
136
|
+
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
137
|
+
declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
|
|
137
138
|
declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
|
|
138
139
|
declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
139
140
|
declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
@@ -147,4 +148,4 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
147
148
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
148
149
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
149
150
|
|
|
150
|
-
export { type AgentAuth, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type HeldAction, type HeldActionReview, type JudgeOptions, type JudgeResult, type JudgmentStatus, type LogToolCallResult, type TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict, checkAgentExists, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, logToolCall, toPubkeyHex };
|
|
151
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type HeldAction, type HeldActionReview, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict, checkAgentExists, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, logToolCall, toPubkeyHex };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
2
|
-
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
3
|
-
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
4
1
|
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
|
|
5
2
|
type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
6
3
|
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
@@ -9,18 +6,10 @@ type PubkeyValue = string | Buffer | {
|
|
|
9
6
|
data: number[];
|
|
10
7
|
};
|
|
11
8
|
type JudgmentStatusState = "pending" | "answered" | "error";
|
|
12
|
-
declare function isValidPrivateKey(hex: string): boolean;
|
|
13
|
-
declare function derivePublicKey(privKeyHex: string): string;
|
|
14
|
-
declare function generateKeyPair(): {
|
|
15
|
-
privKey: string;
|
|
16
|
-
pubKey: string;
|
|
17
|
-
};
|
|
18
9
|
interface AgentAuth {
|
|
19
10
|
pubkey: string;
|
|
20
11
|
privkey: string;
|
|
21
12
|
}
|
|
22
|
-
declare function loadAgent(privkey: string): AgentAuth;
|
|
23
|
-
declare function toPubkeyHex(val: unknown): string;
|
|
24
13
|
interface ClientOpts {
|
|
25
14
|
endpoint?: string;
|
|
26
15
|
timeout?: number;
|
|
@@ -32,23 +21,9 @@ interface ChainOpts {
|
|
|
32
21
|
interface LogToolCallResult {
|
|
33
22
|
success: boolean;
|
|
34
23
|
toolCallId: string | null;
|
|
24
|
+
signedHex?: string;
|
|
35
25
|
error?: string;
|
|
36
26
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Check if an agent is onboarded before signing anything.
|
|
39
|
-
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
40
|
-
*/
|
|
41
|
-
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* Sign and broadcast `log_tool_call` to the Chromia chain.
|
|
44
|
-
*
|
|
45
|
-
* Checks that the agent is onboarded before signing. The agent's private
|
|
46
|
-
* key is used to sign the transaction locally — never sent over the network.
|
|
47
|
-
*/
|
|
48
|
-
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
49
|
-
toolName?: string;
|
|
50
|
-
toolArgsJson?: string;
|
|
51
|
-
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
52
27
|
interface JudgeResult {
|
|
53
28
|
verdict: Verdict;
|
|
54
29
|
action_type: ActionType;
|
|
@@ -59,6 +34,22 @@ interface JudgeResult {
|
|
|
59
34
|
tool_call_id: string;
|
|
60
35
|
on_chain: boolean;
|
|
61
36
|
}
|
|
37
|
+
interface JudgeOptions extends ClientOpts {
|
|
38
|
+
provider?: Provider;
|
|
39
|
+
model?: string;
|
|
40
|
+
toolName?: string;
|
|
41
|
+
toolArgsJson?: string;
|
|
42
|
+
chainOpts?: ChainOpts;
|
|
43
|
+
}
|
|
44
|
+
interface JudgmentStatus {
|
|
45
|
+
status: JudgmentStatusState;
|
|
46
|
+
verdict: Verdict;
|
|
47
|
+
reason: string;
|
|
48
|
+
judgmentId: string;
|
|
49
|
+
onChain?: boolean;
|
|
50
|
+
cached?: boolean;
|
|
51
|
+
responseTimeMs?: number;
|
|
52
|
+
}
|
|
62
53
|
interface TierInfo {
|
|
63
54
|
org_name: string;
|
|
64
55
|
tier: Tier;
|
|
@@ -109,31 +100,41 @@ interface HeldActionReview {
|
|
|
109
100
|
reviewed_at: number;
|
|
110
101
|
created_at: number;
|
|
111
102
|
}
|
|
112
|
-
interface JudgmentStatus {
|
|
113
|
-
status: JudgmentStatusState;
|
|
114
|
-
verdict: Verdict;
|
|
115
|
-
reason: string;
|
|
116
|
-
judgmentId: string;
|
|
117
|
-
onChain?: boolean;
|
|
118
|
-
cached?: boolean;
|
|
119
|
-
responseTimeMs?: number;
|
|
120
|
-
}
|
|
121
|
-
interface JudgeOptions extends ClientOpts {
|
|
122
|
-
provider?: Provider;
|
|
123
|
-
apiKey?: string;
|
|
124
|
-
providerEndpoint?: string;
|
|
125
|
-
model?: string;
|
|
126
|
-
toolName?: string;
|
|
127
|
-
toolArgsJson?: string;
|
|
128
|
-
chainOpts?: ChainOpts;
|
|
129
|
-
}
|
|
130
103
|
interface AgentPolicy {
|
|
131
104
|
policy: string;
|
|
132
105
|
is_jailed: boolean;
|
|
133
106
|
is_custom: boolean;
|
|
134
107
|
default_policy: string;
|
|
135
108
|
}
|
|
136
|
-
|
|
109
|
+
|
|
110
|
+
declare const DEFAULT_ENDPOINT = "https://atbash.ai";
|
|
111
|
+
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
112
|
+
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
113
|
+
declare function isValidPrivateKey(hex: string): boolean;
|
|
114
|
+
declare function derivePublicKey(privKeyHex: string): string;
|
|
115
|
+
declare function generateKeyPair(): {
|
|
116
|
+
privKey: string;
|
|
117
|
+
pubKey: string;
|
|
118
|
+
};
|
|
119
|
+
declare function loadAgent(privkey: string): AgentAuth;
|
|
120
|
+
declare function toPubkeyHex(val: unknown): string;
|
|
121
|
+
/**
|
|
122
|
+
* Check if an agent is onboarded before signing anything.
|
|
123
|
+
* Calls GET /api/ai/exists?pubkey=<66-hex>
|
|
124
|
+
*/
|
|
125
|
+
declare function checkAgentExists(pubkey: string, opts?: ClientOpts): Promise<boolean>;
|
|
126
|
+
/**
|
|
127
|
+
* Sign `log_tool_call` locally and return the signed transaction hex.
|
|
128
|
+
*
|
|
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
|
+
*/
|
|
133
|
+
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
134
|
+
toolName?: string;
|
|
135
|
+
toolArgsJson?: string;
|
|
136
|
+
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
137
|
+
declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
|
|
137
138
|
declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
|
|
138
139
|
declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
139
140
|
declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
|
|
@@ -147,4 +148,4 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
147
148
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
148
149
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
149
150
|
|
|
150
|
-
export { type AgentAuth, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type HeldAction, type HeldActionReview, type JudgeOptions, type JudgeResult, type JudgmentStatus, type LogToolCallResult, type TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict, checkAgentExists, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, logToolCall, toPubkeyHex };
|
|
151
|
+
export { type ActionType, type AgentAuth, type AgentPolicy, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type HeldAction, type HeldActionReview, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict, checkAgentExists, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, logToolCall, toPubkeyHex };
|
package/dist/index.js
CHANGED
|
@@ -52,14 +52,29 @@ 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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return Boolean(data.registered);
|
|
60
|
-
} catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
75
|
+
const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
76
|
+
const data = await getJson(url, opts);
|
|
77
|
+
return Boolean(data.registered);
|
|
63
78
|
}
|
|
64
79
|
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
65
80
|
const exists = await checkAgentExists(auth.pubkey, clientOpts);
|
|
@@ -71,38 +86,25 @@ async function logToolCall(action, context, auth, chainOpts, extra, clientOpts)
|
|
|
71
86
|
};
|
|
72
87
|
}
|
|
73
88
|
try {
|
|
74
|
-
const nodeUrls = chainOpts?.nodeUrls ?? DEFAULT_CHROMIA_NODE_URLS;
|
|
75
|
-
const blockchainRid = chainOpts?.blockchainRid ?? DEFAULT_BLOCKCHAIN_RID;
|
|
76
|
-
const client = await createClient({
|
|
77
|
-
nodeUrlPool: nodeUrls,
|
|
78
|
-
blockchainRid
|
|
79
|
-
});
|
|
80
|
-
const privKeyBuf = Buffer.from(auth.privkey, "hex");
|
|
81
|
-
const keyPair = encryption.makeKeyPair(privKeyBuf);
|
|
82
|
-
const sigProvider = newSignatureProvider({
|
|
83
|
-
privKey: keyPair.privKey,
|
|
84
|
-
pubKey: keyPair.pubKey
|
|
85
|
-
});
|
|
86
89
|
const toolCallId = generateToolCallId();
|
|
87
|
-
await
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
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
|
|
99
101
|
);
|
|
100
|
-
return { success: true, toolCallId };
|
|
102
|
+
return { success: true, toolCallId, signedHex };
|
|
101
103
|
} catch (err) {
|
|
102
104
|
return {
|
|
103
105
|
success: false,
|
|
104
106
|
toolCallId: null,
|
|
105
|
-
error: err instanceof Error ? err.message : "Failed to
|
|
107
|
+
error: err instanceof Error ? err.message : "Failed to sign log_tool_call"
|
|
106
108
|
};
|
|
107
109
|
}
|
|
108
110
|
}
|
|
@@ -157,6 +159,7 @@ async function postJson(url, body, opts) {
|
|
|
157
159
|
async function getJson(url, opts) {
|
|
158
160
|
const resp = await fetch(url, {
|
|
159
161
|
method: "GET",
|
|
162
|
+
headers: { Accept: "application/json" },
|
|
160
163
|
signal: opts?.timeout ? AbortSignal.timeout(opts.timeout) : void 0
|
|
161
164
|
});
|
|
162
165
|
if (!resp.ok) {
|
|
@@ -165,7 +168,10 @@ async function getJson(url, opts) {
|
|
|
165
168
|
}
|
|
166
169
|
return resp.json();
|
|
167
170
|
}
|
|
168
|
-
async function judgeAction(action, context, auth, opts) {
|
|
171
|
+
async function judgeAction(action, context = "", auth, opts) {
|
|
172
|
+
if (!action || !action.trim()) {
|
|
173
|
+
throw new Error("action is required and cannot be empty.");
|
|
174
|
+
}
|
|
169
175
|
const logResult = await logToolCall(
|
|
170
176
|
action,
|
|
171
177
|
context,
|
|
@@ -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
|
|
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
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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.
|
|
3
|
+
"version": "0.3.5",
|
|
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",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
29
30
|
"release": "npm version patch --no-git-tag-version && npm run build && npx npm@10 publish --access public"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|