@atbash/sdk 0.2.1 → 0.3.2
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 +7 -7
- package/dist/index.cjs +76 -44
- package/dist/index.d.cts +17 -7
- package/dist/index.d.ts +17 -7
- package/dist/index.js +74 -43
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@ Requires Node.js 18 or higher. Server-side only — private keys are used for lo
|
|
|
13
13
|
## Quickstart
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import {
|
|
16
|
+
import { loadAgent, judgeAction } from "@atbash/sdk";
|
|
17
17
|
|
|
18
18
|
// 1. Load your agent identity — paste the private key from the Atbash
|
|
19
|
-
// dashboard (https://atbash.ai/risk-engine/agents).
|
|
19
|
+
// dashboard (https://atbash.ai/risk-engine/agents). loadAgent()
|
|
20
20
|
// validates the key and derives the matching public key for you.
|
|
21
|
-
const agent =
|
|
21
|
+
const agent = loadAgent(process.env.ATBASH_AGENT_PRIVKEY!);
|
|
22
22
|
|
|
23
23
|
// 2. Submit an action for judgment, before executing it.
|
|
24
24
|
// The SDK signs and broadcasts log_tool_call to the Chromia chain
|
|
@@ -60,11 +60,11 @@ If you need finer control, you can call `logToolCall()` and the judge API separa
|
|
|
60
60
|
Generate one programmatically for local development:
|
|
61
61
|
|
|
62
62
|
```ts
|
|
63
|
-
import { generateKeyPair,
|
|
63
|
+
import { generateKeyPair, loadAgent } from "@atbash/sdk";
|
|
64
64
|
|
|
65
65
|
const { privKey } = generateKeyPair();
|
|
66
66
|
console.log("Save this private key somewhere safe:", privKey);
|
|
67
|
-
const agent =
|
|
67
|
+
const agent = loadAgent(privKey);
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
For production, always create agents in the dashboard so operators can attach policy packs and manage tier / jail state.
|
|
@@ -175,14 +175,14 @@ interface JudgmentStatus {
|
|
|
175
175
|
### Agent identity
|
|
176
176
|
|
|
177
177
|
```ts
|
|
178
|
-
|
|
178
|
+
loadAgent(privkey: string): AgentAuth
|
|
179
179
|
generateKeyPair(): { privKey: string; pubKey: string }
|
|
180
180
|
derivePublicKey(privKeyHex: string): string
|
|
181
181
|
isValidPrivateKey(hex: string): boolean
|
|
182
182
|
toPubkeyHex(val: unknown): string
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
`
|
|
185
|
+
`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
186
|
|
|
187
187
|
### Query APIs
|
|
188
188
|
|
package/dist/index.cjs
CHANGED
|
@@ -33,7 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
DEFAULT_BLOCKCHAIN_RID: () => DEFAULT_BLOCKCHAIN_RID,
|
|
34
34
|
DEFAULT_CHROMIA_NODE_URLS: () => DEFAULT_CHROMIA_NODE_URLS,
|
|
35
35
|
DEFAULT_ENDPOINT: () => DEFAULT_ENDPOINT,
|
|
36
|
-
|
|
36
|
+
checkAgentExists: () => checkAgentExists,
|
|
37
37
|
derivePublicKey: () => derivePublicKey,
|
|
38
38
|
generateKeyPair: () => generateKeyPair,
|
|
39
39
|
getAgentDetail: () => getAgentDetail,
|
|
@@ -50,6 +50,7 @@ __export(index_exports, {
|
|
|
50
50
|
getToolCalls: () => getToolCalls,
|
|
51
51
|
isValidPrivateKey: () => isValidPrivateKey,
|
|
52
52
|
judgeAction: () => judgeAction,
|
|
53
|
+
loadAgent: () => loadAgent,
|
|
53
54
|
logToolCall: () => logToolCall,
|
|
54
55
|
toPubkeyHex: () => toPubkeyHex
|
|
55
56
|
});
|
|
@@ -59,7 +60,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
59
60
|
var import_crypto = require("crypto");
|
|
60
61
|
var import_postchain_client = __toESM(require("postchain-client"), 1);
|
|
61
62
|
var { createClient, encryption, newSignatureProvider } = import_postchain_client.default;
|
|
62
|
-
var DEFAULT_ENDPOINT = "https://
|
|
63
|
+
var DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
63
64
|
var DEFAULT_CHROMIA_NODE_URLS = [
|
|
64
65
|
"https://node6.testnet.chromia.com:7740",
|
|
65
66
|
"https://node7.testnet.chromia.com:7740",
|
|
@@ -82,7 +83,7 @@ function generateKeyPair() {
|
|
|
82
83
|
pubKey: ecdh.getPublicKey("hex", "compressed")
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
|
-
function
|
|
86
|
+
function loadAgent(privkey) {
|
|
86
87
|
const clean = privkey.replace(/^0x/, "").trim().toLowerCase();
|
|
87
88
|
if (!isValidPrivateKey(clean)) {
|
|
88
89
|
throw new Error(
|
|
@@ -109,41 +110,67 @@ function generateToolCallId() {
|
|
|
109
110
|
const rand = (0, import_crypto.randomBytes)(4).toString("hex");
|
|
110
111
|
return `tc-${ts}-${rand}`;
|
|
111
112
|
}
|
|
112
|
-
async function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
113
|
+
async function checkAgentExists(pubkey, opts) {
|
|
114
|
+
try {
|
|
115
|
+
const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
116
|
+
const data = await getJson(url, opts);
|
|
117
|
+
return Boolean(data.registered);
|
|
118
|
+
} catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
123
|
+
const exists = await checkAgentExists(auth.pubkey, clientOpts);
|
|
124
|
+
if (!exists) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
toolCallId: null,
|
|
128
|
+
error: "Agent not registered. Onboard the agent at the dashboard before submitting actions."
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
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
|
+
const toolCallId = generateToolCallId();
|
|
145
|
+
await client.signAndSendUniqueTransaction(
|
|
146
|
+
{
|
|
147
|
+
name: "log_tool_call",
|
|
148
|
+
args: [
|
|
149
|
+
toolCallId,
|
|
150
|
+
action,
|
|
151
|
+
context || "",
|
|
152
|
+
extra?.toolName || "",
|
|
153
|
+
extra?.toolArgsJson || ""
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
sigProvider
|
|
157
|
+
);
|
|
158
|
+
return { success: true, toolCallId };
|
|
159
|
+
} catch (err) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
toolCallId: null,
|
|
163
|
+
error: err instanceof Error ? err.message : "Failed to log tool call on-chain"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
140
166
|
}
|
|
141
167
|
function normalizeVerdict(raw) {
|
|
142
|
-
|
|
168
|
+
if (raw === null || raw === void 0) return "LOGGED";
|
|
169
|
+
const v = String(raw).toUpperCase();
|
|
143
170
|
if (v === "ALLOW" || v === "GREEN") return "ALLOW";
|
|
144
171
|
if (v === "HOLD" || v === "YELLOW") return "HOLD";
|
|
145
172
|
if (v === "BLOCK" || v === "RED") return "BLOCK";
|
|
146
|
-
return "
|
|
173
|
+
return "HOLD";
|
|
147
174
|
}
|
|
148
175
|
function normalizeStatus(raw) {
|
|
149
176
|
const s = String(raw || "").toLowerCase();
|
|
@@ -197,26 +224,30 @@ async function getJson(url, opts) {
|
|
|
197
224
|
return resp.json();
|
|
198
225
|
}
|
|
199
226
|
async function judgeAction(action, context, auth, opts) {
|
|
200
|
-
const
|
|
227
|
+
const logResult = await logToolCall(
|
|
201
228
|
action,
|
|
202
229
|
context,
|
|
203
230
|
auth,
|
|
204
231
|
opts?.chainOpts,
|
|
205
|
-
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson }
|
|
232
|
+
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
|
|
233
|
+
opts
|
|
206
234
|
);
|
|
235
|
+
if (!logResult.success || !logResult.toolCallId) {
|
|
236
|
+
throw new Error(logResult.error || "Failed to log tool call on-chain");
|
|
237
|
+
}
|
|
207
238
|
const url = `${baseUrl(opts)}/api/v1/judge`;
|
|
208
239
|
const data = await postJson(
|
|
209
240
|
url,
|
|
210
241
|
{
|
|
211
|
-
tool_call_id: toolCallId,
|
|
242
|
+
tool_call_id: logResult.toolCallId,
|
|
212
243
|
agent_pubkey: auth.pubkey,
|
|
213
244
|
action,
|
|
214
|
-
context
|
|
215
|
-
provider: opts
|
|
216
|
-
tool_name: opts
|
|
217
|
-
api_key: opts
|
|
218
|
-
endpoint_url: opts
|
|
219
|
-
model: opts
|
|
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 }
|
|
220
251
|
},
|
|
221
252
|
opts
|
|
222
253
|
);
|
|
@@ -227,7 +258,7 @@ async function judgeAction(action, context, auth, opts) {
|
|
|
227
258
|
confidence: Number(data.confidence ?? 0),
|
|
228
259
|
provider: String(data.provider || ""),
|
|
229
260
|
latency_ms: Number(data.latency_ms ?? 0),
|
|
230
|
-
tool_call_id: String(data.tool_call_id || toolCallId),
|
|
261
|
+
tool_call_id: String(data.tool_call_id || logResult.toolCallId),
|
|
231
262
|
on_chain: Boolean(data.on_chain)
|
|
232
263
|
};
|
|
233
264
|
}
|
|
@@ -351,7 +382,7 @@ async function getSafetyStats(opts) {
|
|
|
351
382
|
DEFAULT_BLOCKCHAIN_RID,
|
|
352
383
|
DEFAULT_CHROMIA_NODE_URLS,
|
|
353
384
|
DEFAULT_ENDPOINT,
|
|
354
|
-
|
|
385
|
+
checkAgentExists,
|
|
355
386
|
derivePublicKey,
|
|
356
387
|
generateKeyPair,
|
|
357
388
|
getAgentDetail,
|
|
@@ -368,6 +399,7 @@ async function getSafetyStats(opts) {
|
|
|
368
399
|
getToolCalls,
|
|
369
400
|
isValidPrivateKey,
|
|
370
401
|
judgeAction,
|
|
402
|
+
loadAgent,
|
|
371
403
|
logToolCall,
|
|
372
404
|
toPubkeyHex
|
|
373
405
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
declare const DEFAULT_ENDPOINT = "https://
|
|
1
|
+
declare const DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
2
2
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
3
3
|
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
4
|
-
type Verdict = "ALLOW" | "HOLD" | "BLOCK";
|
|
4
|
+
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "LOGGED";
|
|
5
5
|
type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
6
6
|
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
7
7
|
type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
|
|
@@ -19,7 +19,7 @@ interface AgentAuth {
|
|
|
19
19
|
pubkey: string;
|
|
20
20
|
privkey: string;
|
|
21
21
|
}
|
|
22
|
-
declare function
|
|
22
|
+
declare function loadAgent(privkey: string): AgentAuth;
|
|
23
23
|
declare function toPubkeyHex(val: unknown): string;
|
|
24
24
|
interface ClientOpts {
|
|
25
25
|
endpoint?: string;
|
|
@@ -29,16 +29,26 @@ interface ChainOpts {
|
|
|
29
29
|
nodeUrls?: string[];
|
|
30
30
|
blockchainRid?: string;
|
|
31
31
|
}
|
|
32
|
+
interface LogToolCallResult {
|
|
33
|
+
success: boolean;
|
|
34
|
+
toolCallId: string | null;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
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>;
|
|
32
42
|
/**
|
|
33
43
|
* Sign and broadcast `log_tool_call` to the Chromia chain.
|
|
34
44
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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.
|
|
37
47
|
*/
|
|
38
48
|
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
39
49
|
toolName?: string;
|
|
40
50
|
toolArgsJson?: string;
|
|
41
|
-
}): Promise<
|
|
51
|
+
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
42
52
|
interface JudgeResult {
|
|
43
53
|
verdict: Verdict;
|
|
44
54
|
action_type: ActionType;
|
|
@@ -137,4 +147,4 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
137
147
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
138
148
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
139
149
|
|
|
140
|
-
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 TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict,
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
declare const DEFAULT_ENDPOINT = "https://
|
|
1
|
+
declare const DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
2
2
|
declare const DEFAULT_CHROMIA_NODE_URLS: string[];
|
|
3
3
|
declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
|
|
4
|
-
type Verdict = "ALLOW" | "HOLD" | "BLOCK";
|
|
4
|
+
type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "LOGGED";
|
|
5
5
|
type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
|
|
6
6
|
type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
|
|
7
7
|
type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
|
|
@@ -19,7 +19,7 @@ interface AgentAuth {
|
|
|
19
19
|
pubkey: string;
|
|
20
20
|
privkey: string;
|
|
21
21
|
}
|
|
22
|
-
declare function
|
|
22
|
+
declare function loadAgent(privkey: string): AgentAuth;
|
|
23
23
|
declare function toPubkeyHex(val: unknown): string;
|
|
24
24
|
interface ClientOpts {
|
|
25
25
|
endpoint?: string;
|
|
@@ -29,16 +29,26 @@ interface ChainOpts {
|
|
|
29
29
|
nodeUrls?: string[];
|
|
30
30
|
blockchainRid?: string;
|
|
31
31
|
}
|
|
32
|
+
interface LogToolCallResult {
|
|
33
|
+
success: boolean;
|
|
34
|
+
toolCallId: string | null;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
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>;
|
|
32
42
|
/**
|
|
33
43
|
* Sign and broadcast `log_tool_call` to the Chromia chain.
|
|
34
44
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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.
|
|
37
47
|
*/
|
|
38
48
|
declare function logToolCall(action: string, context: string, auth: AgentAuth, chainOpts?: ChainOpts, extra?: {
|
|
39
49
|
toolName?: string;
|
|
40
50
|
toolArgsJson?: string;
|
|
41
|
-
}): Promise<
|
|
51
|
+
}, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
|
|
42
52
|
interface JudgeResult {
|
|
43
53
|
verdict: Verdict;
|
|
44
54
|
action_type: ActionType;
|
|
@@ -137,4 +147,4 @@ declare function getAgentDetail(agentPubkey: string, opts?: ClientOpts): Promise
|
|
|
137
147
|
declare function getAgentPolicy(agentPubkey: string, opts?: ClientOpts): Promise<AgentPolicy>;
|
|
138
148
|
declare function getSafetyStats(opts?: ClientOpts): Promise<Record<string, unknown>>;
|
|
139
149
|
|
|
140
|
-
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 TierInfo, type ToolCallFull, type ToolCallRecord, type Verdict,
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createECDH, randomBytes } from "crypto";
|
|
3
3
|
import postchain from "postchain-client";
|
|
4
4
|
var { createClient, encryption, newSignatureProvider } = postchain;
|
|
5
|
-
var DEFAULT_ENDPOINT = "https://
|
|
5
|
+
var DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
6
6
|
var DEFAULT_CHROMIA_NODE_URLS = [
|
|
7
7
|
"https://node6.testnet.chromia.com:7740",
|
|
8
8
|
"https://node7.testnet.chromia.com:7740",
|
|
@@ -25,7 +25,7 @@ function generateKeyPair() {
|
|
|
25
25
|
pubKey: ecdh.getPublicKey("hex", "compressed")
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
function
|
|
28
|
+
function loadAgent(privkey) {
|
|
29
29
|
const clean = privkey.replace(/^0x/, "").trim().toLowerCase();
|
|
30
30
|
if (!isValidPrivateKey(clean)) {
|
|
31
31
|
throw new Error(
|
|
@@ -52,41 +52,67 @@ function generateToolCallId() {
|
|
|
52
52
|
const rand = randomBytes(4).toString("hex");
|
|
53
53
|
return `tc-${ts}-${rand}`;
|
|
54
54
|
}
|
|
55
|
-
async function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
55
|
+
async function checkAgentExists(pubkey, opts) {
|
|
56
|
+
try {
|
|
57
|
+
const url = `${baseUrl(opts)}/api/ai/exists?pubkey=${encodeURIComponent(pubkey)}`;
|
|
58
|
+
const data = await getJson(url, opts);
|
|
59
|
+
return Boolean(data.registered);
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function logToolCall(action, context, auth, chainOpts, extra, clientOpts) {
|
|
65
|
+
const exists = await checkAgentExists(auth.pubkey, clientOpts);
|
|
66
|
+
if (!exists) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
toolCallId: null,
|
|
70
|
+
error: "Agent not registered. Onboard the agent at the dashboard before submitting actions."
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
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
|
+
const toolCallId = generateToolCallId();
|
|
87
|
+
await client.signAndSendUniqueTransaction(
|
|
88
|
+
{
|
|
89
|
+
name: "log_tool_call",
|
|
90
|
+
args: [
|
|
91
|
+
toolCallId,
|
|
92
|
+
action,
|
|
93
|
+
context || "",
|
|
94
|
+
extra?.toolName || "",
|
|
95
|
+
extra?.toolArgsJson || ""
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
sigProvider
|
|
99
|
+
);
|
|
100
|
+
return { success: true, toolCallId };
|
|
101
|
+
} catch (err) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
toolCallId: null,
|
|
105
|
+
error: err instanceof Error ? err.message : "Failed to log tool call on-chain"
|
|
106
|
+
};
|
|
107
|
+
}
|
|
83
108
|
}
|
|
84
109
|
function normalizeVerdict(raw) {
|
|
85
|
-
|
|
110
|
+
if (raw === null || raw === void 0) return "LOGGED";
|
|
111
|
+
const v = String(raw).toUpperCase();
|
|
86
112
|
if (v === "ALLOW" || v === "GREEN") return "ALLOW";
|
|
87
113
|
if (v === "HOLD" || v === "YELLOW") return "HOLD";
|
|
88
114
|
if (v === "BLOCK" || v === "RED") return "BLOCK";
|
|
89
|
-
return "
|
|
115
|
+
return "HOLD";
|
|
90
116
|
}
|
|
91
117
|
function normalizeStatus(raw) {
|
|
92
118
|
const s = String(raw || "").toLowerCase();
|
|
@@ -140,26 +166,30 @@ async function getJson(url, opts) {
|
|
|
140
166
|
return resp.json();
|
|
141
167
|
}
|
|
142
168
|
async function judgeAction(action, context, auth, opts) {
|
|
143
|
-
const
|
|
169
|
+
const logResult = await logToolCall(
|
|
144
170
|
action,
|
|
145
171
|
context,
|
|
146
172
|
auth,
|
|
147
173
|
opts?.chainOpts,
|
|
148
|
-
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson }
|
|
174
|
+
{ toolName: opts?.toolName, toolArgsJson: opts?.toolArgsJson },
|
|
175
|
+
opts
|
|
149
176
|
);
|
|
177
|
+
if (!logResult.success || !logResult.toolCallId) {
|
|
178
|
+
throw new Error(logResult.error || "Failed to log tool call on-chain");
|
|
179
|
+
}
|
|
150
180
|
const url = `${baseUrl(opts)}/api/v1/judge`;
|
|
151
181
|
const data = await postJson(
|
|
152
182
|
url,
|
|
153
183
|
{
|
|
154
|
-
tool_call_id: toolCallId,
|
|
184
|
+
tool_call_id: logResult.toolCallId,
|
|
155
185
|
agent_pubkey: auth.pubkey,
|
|
156
186
|
action,
|
|
157
|
-
context
|
|
158
|
-
provider: opts
|
|
159
|
-
tool_name: opts
|
|
160
|
-
api_key: opts
|
|
161
|
-
endpoint_url: opts
|
|
162
|
-
model: opts
|
|
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 }
|
|
163
193
|
},
|
|
164
194
|
opts
|
|
165
195
|
);
|
|
@@ -170,7 +200,7 @@ async function judgeAction(action, context, auth, opts) {
|
|
|
170
200
|
confidence: Number(data.confidence ?? 0),
|
|
171
201
|
provider: String(data.provider || ""),
|
|
172
202
|
latency_ms: Number(data.latency_ms ?? 0),
|
|
173
|
-
tool_call_id: String(data.tool_call_id || toolCallId),
|
|
203
|
+
tool_call_id: String(data.tool_call_id || logResult.toolCallId),
|
|
174
204
|
on_chain: Boolean(data.on_chain)
|
|
175
205
|
};
|
|
176
206
|
}
|
|
@@ -293,7 +323,7 @@ export {
|
|
|
293
323
|
DEFAULT_BLOCKCHAIN_RID,
|
|
294
324
|
DEFAULT_CHROMIA_NODE_URLS,
|
|
295
325
|
DEFAULT_ENDPOINT,
|
|
296
|
-
|
|
326
|
+
checkAgentExists,
|
|
297
327
|
derivePublicKey,
|
|
298
328
|
generateKeyPair,
|
|
299
329
|
getAgentDetail,
|
|
@@ -310,6 +340,7 @@ export {
|
|
|
310
340
|
getToolCalls,
|
|
311
341
|
isValidPrivateKey,
|
|
312
342
|
judgeAction,
|
|
343
|
+
loadAgent,
|
|
313
344
|
logToolCall,
|
|
314
345
|
toPubkeyHex
|
|
315
346
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atbash/sdk",
|
|
3
|
-
"version": "0.2
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.2",
|
|
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",
|
|
7
7
|
"license": "SEE LICENSE IN LICENSE",
|