@belticlabs/agent-risk-sdk 0.6.0 → 0.8.0

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.
@@ -1,6 +1,6 @@
1
1
  import { LanguageModelMiddleware, ToolSet } from 'ai';
2
- import { S as Session } from '../session-Dcof4UIn.js';
3
- import '../index-IfY4XCvJ.js';
2
+ import { S as Session } from '../session-DTIzd1EQ.js';
3
+ import '../index-CBUSXzgG.js';
4
4
  import 'zod';
5
5
 
6
6
  declare function middleware(session: Session): LanguageModelMiddleware;
package/dist/ai/index.js CHANGED
@@ -1,13 +1,12 @@
1
1
  import {
2
2
  recordCall
3
- } from "../chunk-ZMPKY7AX.js";
3
+ } from "../chunk-JGVVQUXQ.js";
4
4
  import {
5
5
  toJson,
6
- toJsonObject
7
- } from "../chunk-FQDHFTVR.js";
8
- import {
6
+ toJsonObject,
9
7
  uuidv7
10
- } from "../chunk-77D74TWX.js";
8
+ } from "../chunk-MWXXX35V.js";
9
+ import "../chunk-PDE55ZZV.js";
11
10
 
12
11
  // src/ai/index.ts
13
12
  var PARAM_KEYS = [
@@ -28,10 +27,12 @@ function middleware(session) {
28
27
  const stream = await session.stream();
29
28
  if (!stream) return doGenerate();
30
29
  return recordCall(
31
- stream,
32
- "llm_call",
33
- uuidv7(),
34
- { provider: model.provider, modelId: model.modelId, params: pick(params) },
30
+ stream.llmCall({
31
+ callId: uuidv7(),
32
+ provider: model.provider,
33
+ modelId: model.modelId,
34
+ params: pick(params)
35
+ }),
35
36
  doGenerate,
36
37
  (result) => ({
37
38
  content: toJson(result.content),
@@ -44,14 +45,13 @@ function middleware(session) {
44
45
  wrapStream: async ({ doStream, params, model }) => {
45
46
  const evidence = await session.stream();
46
47
  if (!evidence) return doStream();
47
- const callId = uuidv7();
48
- const started = Date.now();
49
- await evidence.emit("llm_call.start", {
50
- callId,
48
+ const span = evidence.llmCall({
49
+ callId: uuidv7(),
51
50
  provider: model.provider,
52
51
  modelId: model.modelId,
53
52
  params: pick(params)
54
53
  });
54
+ await span.opened;
55
55
  const { stream, ...rest } = await doStream();
56
56
  const parts = [];
57
57
  let finish = {};
@@ -64,12 +64,10 @@ function middleware(session) {
64
64
  controller.enqueue(part);
65
65
  },
66
66
  flush: async () => {
67
- await evidence.emit("llm_call.end", {
68
- callId,
67
+ await span.end({
69
68
  content: toJson(parts),
70
69
  ...finish.finishReason ? { finishReason: finish.finishReason } : {},
71
- ...finish.usage ? { usage: toJsonObject(finish.usage) } : {},
72
- durationMs: Date.now() - started
70
+ ...finish.usage ? { usage: toJsonObject(finish.usage) } : {}
73
71
  });
74
72
  }
75
73
  });
@@ -90,10 +88,7 @@ function wrapTool(session, toolName, tool) {
90
88
  const stream = await session.stream();
91
89
  if (!stream) return original(input, options);
92
90
  return recordCall(
93
- stream,
94
- "tool_call",
95
- options.toolCallId,
96
- { toolName, input: toJson(input), transport: "local" },
91
+ stream.toolCall({ callId: options.toolCallId, toolName, input: toJson(input) }),
97
92
  async () => {
98
93
  const output = await original(input, options);
99
94
  return output && typeof output === "object" && Symbol.asyncIterator in output ? collect(output) : output;
@@ -0,0 +1,103 @@
1
+ import {
2
+ toJsonObject
3
+ } from "./chunk-MWXXX35V.js";
4
+ import {
5
+ Money
6
+ } from "./chunk-PDE55ZZV.js";
7
+
8
+ // src/x402/binding.ts
9
+ var SESSION_EXTENSION = "beltic.sessionId";
10
+ var SESSION_HEADER = "Beltic-Session-Id";
11
+ function sessionIdOf(extensions) {
12
+ const v = extensions?.[SESSION_EXTENSION];
13
+ return typeof v === "string" && v.length > 0 ? v : null;
14
+ }
15
+
16
+ // src/core/payment-moment.ts
17
+ function summaryOf(m) {
18
+ return {
19
+ protocol: m.protocol,
20
+ payee: m.payee,
21
+ amount: { value: m.amount.value, currency: m.amount.currency },
22
+ ...m.payer ? { payer: m.payer } : {}
23
+ };
24
+ }
25
+
26
+ // src/x402/moments.ts
27
+ import { z } from "zod";
28
+ function summary(accepts, opts = {}) {
29
+ const payer = opts.payer?.toLowerCase();
30
+ return {
31
+ protocol: "x402",
32
+ payee: accepts?.payTo ?? "unknown",
33
+ amount: {
34
+ value: accepts?.amount ?? "0",
35
+ currency: accepts ? Money.x402Currency(accepts.network ?? "unknown", accepts.asset ?? "unknown") : "unknown"
36
+ },
37
+ ...payer ? { payer } : {}
38
+ };
39
+ }
40
+ function fromAccepts(a, artifact, raw, payer) {
41
+ return { ...summary(a, { payer }), artifact, raw };
42
+ }
43
+ function payerOf(payload) {
44
+ const p = payload.payload ?? {};
45
+ const auth = p.authorization;
46
+ const candidates = [
47
+ auth?.from,
48
+ p.from,
49
+ p.payer,
50
+ p.signer,
51
+ p.permit?.owner
52
+ ];
53
+ const hit = candidates.find((c) => typeof c === "string" && c.length > 0);
54
+ return typeof hit === "string" ? hit.toLowerCase() : void 0;
55
+ }
56
+ var x402Moments = {
57
+ summary,
58
+ /** The 402 challenge as the buyer saw it, from the `PAYMENT-REQUIRED` header. */
59
+ required(required) {
60
+ return fromAccepts(required.accepts?.[0], "http-402", toJsonObject(required));
61
+ },
62
+ /** The requirements the seller's resource server resolved for a request. */
63
+ requirements(req) {
64
+ return fromAccepts(req, "http-402", toJsonObject(req));
65
+ },
66
+ /** A route's static `accepts` config, before any payment header exists. */
67
+ route(route, raw) {
68
+ const accepts = route ?? {};
69
+ const extra = accepts.extra;
70
+ return fromAccepts(
71
+ {
72
+ payTo: typeof accepts.payTo === "string" ? accepts.payTo : "dynamic",
73
+ amount: PriceSchema.parse(accepts.price),
74
+ network: accepts.network,
75
+ asset: extra?.asset ?? "route"
76
+ },
77
+ "http-402",
78
+ raw
79
+ );
80
+ },
81
+ /** The signed payment the buyer presented, with the requirement it accepted. */
82
+ payload(payload) {
83
+ return fromAccepts(
84
+ payload.accepted,
85
+ "payment-signature",
86
+ toJsonObject(payload),
87
+ payerOf(payload)
88
+ );
89
+ }
90
+ };
91
+ var PriceSchema = z.union([
92
+ z.string().transform((s) => s.replace(/[^0-9.]/g, "") || "0"),
93
+ z.number().transform(String),
94
+ z.object({ amount: z.string() }).transform((p) => p.amount)
95
+ ]).catch("0");
96
+
97
+ export {
98
+ summaryOf,
99
+ SESSION_EXTENSION,
100
+ SESSION_HEADER,
101
+ sessionIdOf,
102
+ x402Moments
103
+ };
@@ -20,8 +20,7 @@ function openCall(stream, kind, callId, start) {
20
20
  fail: (error, outcome = {}) => close({ error: errorOf(error), ...outcome })
21
21
  };
22
22
  }
23
- async function recordCall(stream, kind, callId, start, run, end = () => ({})) {
24
- const span = openCall(stream, kind, callId, start);
23
+ async function recordCall(span, run, end = () => ({})) {
25
24
  await span.opened;
26
25
  try {
27
26
  const result = await run();
@@ -9,28 +9,6 @@ function uuidv7(now = Date.now()) {
9
9
  return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
10
10
  }
11
11
 
12
- // ../canon/src/base58.ts
13
- var ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
14
- var MAP = new Map([...ALPHABET].map((c, i) => [c, i]));
15
- function base58Encode(bytes) {
16
- let zeros = 0;
17
- while (zeros < bytes.length && bytes[zeros] === 0) zeros++;
18
- const digits = [];
19
- for (let i = zeros; i < bytes.length; i++) {
20
- let carry = bytes[i];
21
- for (let j = 0; j < digits.length; j++) {
22
- carry += digits[j] << 8;
23
- digits[j] = carry % 58;
24
- carry = carry / 58 | 0;
25
- }
26
- while (carry > 0) {
27
- digits.push(carry % 58);
28
- carry = carry / 58 | 0;
29
- }
30
- }
31
- return "1".repeat(zeros) + digits.reverse().map((d) => ALPHABET[d]).join("");
32
- }
33
-
34
12
  // ../canon/src/encoding.ts
35
13
  function toHex(buf) {
36
14
  return Buffer.from(buf).toString("hex");
@@ -293,6 +271,28 @@ var Chain = class _Chain {
293
271
  }
294
272
  };
295
273
 
274
+ // ../canon/src/base58.ts
275
+ var ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
276
+ var MAP = new Map([...ALPHABET].map((c, i) => [c, i]));
277
+ function base58Encode(bytes) {
278
+ let zeros = 0;
279
+ while (zeros < bytes.length && bytes[zeros] === 0) zeros++;
280
+ const digits = [];
281
+ for (let i = zeros; i < bytes.length; i++) {
282
+ let carry = bytes[i];
283
+ for (let j = 0; j < digits.length; j++) {
284
+ carry += digits[j] << 8;
285
+ digits[j] = carry % 58;
286
+ carry = carry / 58 | 0;
287
+ }
288
+ while (carry > 0) {
289
+ digits.push(carry % 58);
290
+ carry = carry / 58 | 0;
291
+ }
292
+ }
293
+ return "1".repeat(zeros) + digits.reverse().map((d) => ALPHABET[d]).join("");
294
+ }
295
+
296
296
  // ../canon/src/did-key.ts
297
297
  var ED25519_PUB_MULTICODEC = Buffer.from([237, 1]);
298
298
  var PREFIX = "did:key:z";
@@ -301,6 +301,34 @@ function didKeyFromEd25519(publicKey) {
301
301
  return PREFIX + base58Encode(Buffer.concat([ED25519_PUB_MULTICODEC, Buffer.from(publicKey)]));
302
302
  }
303
303
 
304
+ // ../canon/src/session-id.ts
305
+ import { randomBytes as randomBytes2 } from "crypto";
306
+
307
+ // src/core/json.ts
308
+ function toJson(value) {
309
+ if (value === null || value === void 0) return null;
310
+ if (typeof value === "string" || typeof value === "boolean") return value;
311
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
312
+ if (typeof value === "bigint") return value.toString();
313
+ if (value instanceof Uint8Array) return { $bytes: Buffer.from(value).toString("base64") };
314
+ if (value instanceof Date) return value.toISOString();
315
+ if (value instanceof URL) return value.toString();
316
+ if (Array.isArray(value)) return value.map(toJson);
317
+ if (typeof value === "object") {
318
+ const out = {};
319
+ for (const [k, v] of Object.entries(value)) {
320
+ if (v === void 0 || typeof v === "function") continue;
321
+ out[k] = toJson(v);
322
+ }
323
+ return out;
324
+ }
325
+ return null;
326
+ }
327
+ function toJsonObject(value) {
328
+ const j = toJson(value);
329
+ return j && typeof j === "object" && !Array.isArray(j) ? j : { value: j };
330
+ }
331
+
304
332
  export {
305
333
  toHex,
306
334
  fromHex,
@@ -310,5 +338,7 @@ export {
310
338
  memorySigner,
311
339
  Chain,
312
340
  didKeyFromEd25519,
313
- uuidv7
341
+ uuidv7,
342
+ toJson,
343
+ toJsonObject
314
344
  };
@@ -0,0 +1,57 @@
1
+ import {
2
+ SESSION_HEADER,
3
+ sessionIdOf,
4
+ summaryOf,
5
+ x402Moments
6
+ } from "./chunk-DI3LZR65.js";
7
+ import {
8
+ payloadDigest
9
+ } from "./chunk-MWXXX35V.js";
10
+
11
+ // src/x402/adapter.ts
12
+ function attachX402(beltic, server, http) {
13
+ const inFlight = /* @__PURE__ */ new Map();
14
+ http?.onProtectedRequest(async (ctx, route) => {
15
+ if (ctx.paymentHeader) return;
16
+ const bound = ctx.adapter.getHeader(SESSION_HEADER) ?? ctx.adapter.getHeader(SESSION_HEADER.toLowerCase());
17
+ if (!bound) return;
18
+ const stream = await beltic.streams.ensure(bound);
19
+ const accepts = Array.isArray(route.accepts) ? route.accepts[0] : route.accepts;
20
+ await stream.emit(
21
+ "payment.requested",
22
+ x402Moments.route(accepts, {
23
+ path: ctx.path,
24
+ method: ctx.method,
25
+ route: JSON.parse(JSON.stringify(route))
26
+ })
27
+ );
28
+ });
29
+ server.onBeforeVerify(async (ctx) => {
30
+ const payload = ctx.paymentPayload;
31
+ const requirements = ctx.requirements;
32
+ const stream = await beltic.streams.ensure(sessionIdOf(payload.extensions));
33
+ if (stream.born === "seller")
34
+ await stream.emit("payment.requested", x402Moments.requirements(requirements));
35
+ const presented = x402Moments.payload(payload);
36
+ await stream.emit("payment.presented", presented);
37
+ inFlight.set(payloadDigest(payload), stream);
38
+ const decision = await beltic.evaluate(stream.id, summaryOf(presented));
39
+ if (decision.absent || decision.allowed) return;
40
+ return {
41
+ abort: true,
42
+ reason: `BELTIC_${decision.value}`,
43
+ message: decision.reasonCodes.join(",")
44
+ };
45
+ });
46
+ server.onAfterSettle(async (ctx) => {
47
+ const key = payloadDigest(ctx.paymentPayload);
48
+ const stream = inFlight.get(key);
49
+ if (!stream) return;
50
+ inFlight.delete(key);
51
+ if (ctx.result.success) await stream.close("settled", { transaction: ctx.result.transaction });
52
+ });
53
+ }
54
+
55
+ export {
56
+ attachX402
57
+ };