@absol-labs/agent 0.3.2 → 0.5.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.
Files changed (59) hide show
  1. package/README.md +378 -168
  2. package/dist/capability/invocation-capability.d.ts +184 -0
  3. package/dist/capability/invocation-capability.d.ts.map +1 -0
  4. package/dist/capability/invocation-capability.js +183 -0
  5. package/dist/capability/invocation-capability.js.map +1 -0
  6. package/dist/frameworks/agentkit.js +2 -2
  7. package/dist/frameworks/agentkit.js.map +1 -1
  8. package/dist/frameworks/eliza.js +2 -2
  9. package/dist/frameworks/eliza.js.map +1 -1
  10. package/dist/frameworks/langchain.js +2 -2
  11. package/dist/frameworks/langchain.js.map +1 -1
  12. package/dist/gateway/caller-auth-gateway.d.ts +106 -0
  13. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -0
  14. package/dist/gateway/caller-auth-gateway.js +189 -0
  15. package/dist/gateway/caller-auth-gateway.js.map +1 -0
  16. package/dist/gateway/http-server.d.ts +49 -0
  17. package/dist/gateway/http-server.d.ts.map +1 -0
  18. package/dist/gateway/http-server.js +227 -0
  19. package/dist/gateway/http-server.js.map +1 -0
  20. package/dist/gateway/server-entry.d.ts +2 -0
  21. package/dist/gateway/server-entry.d.ts.map +1 -0
  22. package/dist/gateway/server-entry.js +30 -0
  23. package/dist/gateway/server-entry.js.map +1 -0
  24. package/dist/index.d.ts +7 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +7 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/mcp/server.js +2 -2
  29. package/dist/mcp/server.js.map +1 -1
  30. package/dist/sdk/invoke.d.ts +122 -0
  31. package/dist/sdk/invoke.d.ts.map +1 -0
  32. package/dist/sdk/invoke.js +158 -0
  33. package/dist/sdk/invoke.js.map +1 -0
  34. package/dist/wallet/lifecycle.d.ts +101 -0
  35. package/dist/wallet/lifecycle.d.ts.map +1 -0
  36. package/dist/wallet/lifecycle.js +57 -0
  37. package/dist/wallet/lifecycle.js.map +1 -0
  38. package/dist/zktls/reclaim.d.ts +84 -5
  39. package/dist/zktls/reclaim.d.ts.map +1 -1
  40. package/dist/zktls/reclaim.js +47 -3
  41. package/dist/zktls/reclaim.js.map +1 -1
  42. package/dist/zktls/t2-delivery-proof.d.ts +296 -0
  43. package/dist/zktls/t2-delivery-proof.d.ts.map +1 -0
  44. package/dist/zktls/t2-delivery-proof.js +336 -0
  45. package/dist/zktls/t2-delivery-proof.js.map +1 -0
  46. package/package.json +6 -3
  47. package/src/capability/invocation-capability.ts +255 -0
  48. package/src/frameworks/agentkit.ts +2 -2
  49. package/src/frameworks/eliza.ts +2 -2
  50. package/src/frameworks/langchain.ts +2 -2
  51. package/src/gateway/caller-auth-gateway.ts +328 -0
  52. package/src/gateway/http-server.ts +325 -0
  53. package/src/gateway/server-entry.ts +38 -0
  54. package/src/index.ts +103 -0
  55. package/src/mcp/server.ts +2 -2
  56. package/src/sdk/invoke.ts +313 -0
  57. package/src/wallet/lifecycle.ts +158 -0
  58. package/src/zktls/reclaim.ts +88 -8
  59. package/src/zktls/t2-delivery-proof.ts +559 -0
@@ -0,0 +1,336 @@
1
+ import { canonicalJson, deliveryReceiptSchema, signDeliveryReceipt, } from "@absol-labs/shared";
2
+ import { getHttpProviderClaimParamsFromProof, getProviderHashRequirementsFromSpec, verifyProof, } from "@reclaimprotocol/js-sdk";
3
+ import { keccak256, stringToBytes, } from "viem";
4
+ import { z } from "zod";
5
+ import { asErrorMessage, buildDeliveryContextEnvelopeV2, defaultReclaimClientFactory, deliveryContextEnvelopeV2Schema, parseReclaimProofEnv, ResponseProofUnavailableError, ResponseProofVerificationError, toRequestSpec, } from "./reclaim.js";
6
+ /**
7
+ * T2 consumer zkTLS delivery envelope (issue #24, metrik-protocol#67 DECISION).
8
+ *
9
+ * This is the BUYER-side counterpart to `streamproof-oracle`'s T2 accrue-on-proof
10
+ * ingest (`src/delivery/proof-ingest.ts`). Given the stream identity, an
11
+ * oracle-issued nonce (`GET /delivery/nonce`), and the paid-route request spec,
12
+ * it: (1) proves the paid route via a pluggable zkTLS attestor with the nonce
13
+ * bound into the request and the Metrik v2 envelope bound into
14
+ * `claimData.context`; (2) signs a `DeliveryReceipt` (`@absol-labs/shared`)
15
+ * committing to that proof; and (3) returns the exact `POST /delivery/proof`
16
+ * request body the oracle's `deliveryProofRequestSchema` expects.
17
+ *
18
+ * The attestor is pluggable (`DeliveryProofAttestor`) specifically so this can
19
+ * be tested WITHOUT a live Reclaim App Secret (agent#22 is the human-intervention
20
+ * issue for that credential) - the default production attestor
21
+ * (`createReclaimT2AttestorFromEnv`) still requires it.
22
+ */
23
+ const bytes32Hex = /^0x[0-9a-fA-F]{64}$/;
24
+ const evmAddress = /^0x[0-9a-fA-F]{40}$/;
25
+ const hexSignature = /^0x[0-9a-fA-F]+$/;
26
+ export class PaidRouteNonceInjectionError extends Error {
27
+ constructor(message) {
28
+ super(message);
29
+ this.name = "PaidRouteNonceInjectionError";
30
+ }
31
+ }
32
+ /** Injects the oracle-issued nonce into the paid-route request (query or body only). */
33
+ function injectNonce(spec, nonce) {
34
+ if (spec.nonceInjection.in === "query") {
35
+ let url;
36
+ try {
37
+ url = new URL(spec.url);
38
+ }
39
+ catch (cause) {
40
+ throw new PaidRouteNonceInjectionError(`paid route url is not a valid absolute URL: ${asErrorMessage(cause)}`);
41
+ }
42
+ url.searchParams.set(spec.nonceInjection.name, nonce);
43
+ return { url: url.toString(), body: spec.body };
44
+ }
45
+ const placeholder = spec.nonceInjection.placeholder;
46
+ const body = spec.body ?? "";
47
+ if (!body.includes(placeholder)) {
48
+ throw new PaidRouteNonceInjectionError(`paid route body does not contain the nonce placeholder "${placeholder}"`);
49
+ }
50
+ return { url: spec.url, body: body.split(placeholder).join(nonce) };
51
+ }
52
+ const reclaimT2UrlSchema = z.string().url();
53
+ /**
54
+ * Production `DeliveryProofAttestor`: drives the real Reclaim zkFetch + proof
55
+ * verification pipeline (mirrors `ReclaimConsumerProofService` in `reclaim.ts`,
56
+ * but binds the FLAT T2 v2 envelope directly as `context` instead of the v1
57
+ * `{contextAddress, contextMessage}` wrapper).
58
+ */
59
+ export class ReclaimDeliveryProofAttestor {
60
+ client;
61
+ config;
62
+ verifyProofImpl;
63
+ constructor(config, options = {}) {
64
+ this.config = {
65
+ ...config,
66
+ logs: config.logs ?? false,
67
+ };
68
+ this.client = (options.createClient ?? defaultReclaimClientFactory)(this.config.applicationId, this.config.applicationSecret, this.config.logs ?? false);
69
+ this.verifyProofImpl = options.verifyProof ?? verifyProof;
70
+ }
71
+ async proveDeliveryResponse(input) {
72
+ reclaimT2UrlSchema.parse(input.url);
73
+ if (input.responseMatches.length === 0) {
74
+ throw new Error("at least one response match is required");
75
+ }
76
+ const context = deliveryContextEnvelopeV2Schema.parse(input.context);
77
+ const parsed = { ...input, context };
78
+ const method = parsed.method ?? "GET";
79
+ const proof = await this.client
80
+ .zkFetch(parsed.url, {
81
+ method,
82
+ ...(parsed.body === undefined ? {} : { body: parsed.body }),
83
+ ...(parsed.headers === undefined ? {} : { headers: parsed.headers }),
84
+ ...(parsed.geoLocation === undefined
85
+ ? {}
86
+ : { geoLocation: parsed.geoLocation }),
87
+ context: parsed.context,
88
+ ...(parsed.useTee === undefined ? {} : { useTee: parsed.useTee }),
89
+ ...(parsed.zkEngine === undefined
90
+ ? {}
91
+ : { zkEngine: parsed.zkEngine }),
92
+ }, {
93
+ ...(parsed.secretHeaders === undefined
94
+ ? {}
95
+ : { headers: parsed.secretHeaders }),
96
+ responseMatches: parsed.responseMatches,
97
+ ...(parsed.responseRedactions === undefined
98
+ ? {}
99
+ : { responseRedactions: parsed.responseRedactions }),
100
+ ...(parsed.cookie === undefined ? {} : { cookieStr: parsed.cookie }),
101
+ ...(parsed.secretParamValues === undefined
102
+ ? {}
103
+ : { paramValues: parsed.secretParamValues }),
104
+ })
105
+ .catch((error) => {
106
+ throw new ResponseProofUnavailableError(`failed to generate T2 zkTLS delivery proof: ${asErrorMessage(error)}`);
107
+ });
108
+ if (proof === undefined) {
109
+ throw new ResponseProofUnavailableError("reclaim returned no zkTLS delivery proof");
110
+ }
111
+ const verification = await this.verifyProofImpl(proof, {
112
+ ...getProviderHashRequirementsFromSpec({
113
+ requests: [toRequestSpec(parsed, method)],
114
+ }),
115
+ ...(parsed.useTee === true
116
+ ? { teeAttestation: { appSecret: this.config.applicationSecret } }
117
+ : {}),
118
+ });
119
+ if (!verification.isVerified) {
120
+ throw new ResponseProofVerificationError(`T2 zkTLS delivery proof verification failed: ${asErrorMessage(verification.error)}`);
121
+ }
122
+ const trusted = verification.data[0];
123
+ if (trusted === undefined) {
124
+ throw new ResponseProofVerificationError("T2 zkTLS delivery proof verification returned no trusted data");
125
+ }
126
+ const request = getHttpProviderClaimParamsFromProof(proof);
127
+ return {
128
+ proof,
129
+ request: {
130
+ url: request.url,
131
+ method: request.method,
132
+ body: request.body === "" ? null : (request.body ?? null),
133
+ responseMatches: request.responseMatches.map((match) => ({
134
+ value: match.value,
135
+ type: match.type,
136
+ invert: match.invert,
137
+ isOptional: match.isOptional,
138
+ })),
139
+ responseRedactions: request.responseRedactions.map((redaction) => ({
140
+ regex: redaction.regex,
141
+ jsonPath: redaction.jsonPath,
142
+ xPath: redaction.xPath,
143
+ hash: redaction.hash,
144
+ })),
145
+ },
146
+ verification: {
147
+ context: trusted.context,
148
+ extractedParameters: trusted.extractedParameters,
149
+ publicData: verification.publicData[0] ?? null,
150
+ isTeeAttestationVerified: verification.isTeeAttestationVerified ?? false,
151
+ isAttestorTeeAttestationVerified: verification.isAttestorTeeAttestationVerified ?? false,
152
+ },
153
+ };
154
+ }
155
+ }
156
+ /** `null` when `RECLAIM_APP_ID`/`RECLAIM_APP_SECRET` are not configured (see agent#22). */
157
+ export function createReclaimT2AttestorFromEnv(env = process.env) {
158
+ const parsed = parseReclaimProofEnv(env);
159
+ if (parsed === null)
160
+ return null;
161
+ return new ReclaimDeliveryProofAttestor(parsed);
162
+ }
163
+ const wireDeliveryReceiptSchema = z
164
+ .object({
165
+ streamId: z.union([
166
+ z.string().regex(bytes32Hex),
167
+ z.string().regex(/^\d+$/),
168
+ ]),
169
+ serviceRef: z
170
+ .string()
171
+ .regex(bytes32Hex, "must be a 32-byte hex serviceRef"),
172
+ operator: z.string().regex(evmAddress, "must be an EVM address"),
173
+ intervalIndex: z
174
+ .string()
175
+ .regex(/^\d+$/, "must be a non-negative integer string"),
176
+ nonce: z.string().regex(bytes32Hex, "must be a 32-byte hex nonce"),
177
+ reclaimProofId: z
178
+ .string()
179
+ .regex(bytes32Hex, "must be a 32-byte hex identifier"),
180
+ reclaimOwner: z.string().regex(evmAddress, "must be an EVM address"),
181
+ reclaimTimestamp: z
182
+ .string()
183
+ .regex(/^\d+$/, "must be a non-negative integer string"),
184
+ reclaimEpoch: z
185
+ .string()
186
+ .regex(/^\d+$/, "must be a non-negative integer string"),
187
+ canonicalRequestHash: z
188
+ .string()
189
+ .regex(bytes32Hex, "must be a 32-byte hex hash"),
190
+ canonicalBodyHash: z
191
+ .string()
192
+ .regex(bytes32Hex, "must be a 32-byte hex hash"),
193
+ })
194
+ .strict();
195
+ const reclaimProviderClaimDataSchema = z
196
+ .object({
197
+ provider: z.string().min(1),
198
+ parameters: z.string().min(1),
199
+ context: z.string(),
200
+ owner: z.string().regex(evmAddress, "must be an EVM address"),
201
+ timestampS: z.number().int().nonnegative(),
202
+ epoch: z.number().int().nonnegative(),
203
+ identifier: z
204
+ .string()
205
+ .regex(bytes32Hex, "must be a 32-byte hex identifier"),
206
+ })
207
+ .strict();
208
+ const reclaimProofWireSchema = z
209
+ .object({
210
+ identifier: z
211
+ .string()
212
+ .regex(bytes32Hex, "must be a 32-byte hex identifier"),
213
+ claimData: reclaimProviderClaimDataSchema,
214
+ signatures: z.array(z.string().regex(hexSignature)).min(1),
215
+ })
216
+ .strict();
217
+ /**
218
+ * `POST /delivery/proof` request body - mirrors the oracle's own
219
+ * `deliveryProofRequestSchema` (`streamproof-oracle/src/delivery/dto.ts`)
220
+ * field-for-field. Kept as a local copy (same convention the oracle itself
221
+ * uses for `@absol-labs/shared` shapes) rather than an import, since the two
222
+ * repos do not share a package for this DTO.
223
+ */
224
+ export const deliveryProofRequestBodySchema = z
225
+ .object({
226
+ receipt: wireDeliveryReceiptSchema,
227
+ signature: z.string().regex(hexSignature, "must be a hex signature"),
228
+ proof: reclaimProofWireSchema,
229
+ })
230
+ .strict();
231
+ /** Converts a bigint-typed `DeliveryReceipt` to the oracle's decimal-string wire shape. */
232
+ export function toWireDeliveryReceipt(receipt) {
233
+ return {
234
+ streamId: receipt.streamId.toString(),
235
+ serviceRef: receipt.serviceRef,
236
+ operator: receipt.operator,
237
+ intervalIndex: receipt.intervalIndex.toString(),
238
+ nonce: receipt.nonce,
239
+ reclaimProofId: receipt.reclaimProofId,
240
+ reclaimOwner: receipt.reclaimOwner,
241
+ reclaimTimestamp: receipt.reclaimTimestamp.toString(),
242
+ reclaimEpoch: receipt.reclaimEpoch.toString(),
243
+ canonicalRequestHash: receipt.canonicalRequestHash,
244
+ canonicalBodyHash: receipt.canonicalBodyHash,
245
+ };
246
+ }
247
+ /** Deterministic keccak256 over the canonical (sorted-key) JSON of `value`. */
248
+ function hashCanonical(value) {
249
+ return keccak256(stringToBytes(canonicalJson(value)));
250
+ }
251
+ export class NoDeliveryAttestorConfiguredError extends Error {
252
+ constructor() {
253
+ super("no zkTLS delivery attestor configured: set RECLAIM_APP_ID/RECLAIM_APP_SECRET " +
254
+ "(see agent#22) or pass an explicit `attestor`");
255
+ this.name = "NoDeliveryAttestorConfiguredError";
256
+ }
257
+ }
258
+ /**
259
+ * Produces a complete T2 delivery proof envelope: proves the paid route with
260
+ * the oracle-issued nonce bound into both the request and the Reclaim
261
+ * `claimData.context`, signs a `DeliveryReceipt` committing to that proof, and
262
+ * returns the exact body for `POST /delivery/proof`.
263
+ */
264
+ export async function buildT2DeliveryProofSubmission(input) {
265
+ const issuedAt = input.issuedAt ?? Math.floor(Date.now() / 1000);
266
+ if (input.intervalIndex > BigInt(Number.MAX_SAFE_INTEGER)) {
267
+ throw new RangeError("intervalIndex exceeds Number.MAX_SAFE_INTEGER");
268
+ }
269
+ const envelope = buildDeliveryContextEnvelopeV2({
270
+ streamId: input.streamId,
271
+ operator: input.operator,
272
+ serviceRef: input.serviceRef,
273
+ ...(input.mandateId === undefined ? {} : { mandateId: input.mandateId }),
274
+ nonce: input.nonce,
275
+ intervalIndex: Number(input.intervalIndex),
276
+ issuedAt,
277
+ });
278
+ const injected = injectNonce(input.request, input.nonce);
279
+ const attestor = input.attestor ?? createReclaimT2AttestorFromEnv();
280
+ if (attestor === null) {
281
+ throw new NoDeliveryAttestorConfiguredError();
282
+ }
283
+ const proved = await attestor.proveDeliveryResponse({
284
+ url: injected.url,
285
+ method: input.request.method,
286
+ body: injected.body,
287
+ headers: input.request.headers,
288
+ secretHeaders: input.request.secretHeaders,
289
+ responseMatches: input.request.responseMatches,
290
+ responseRedactions: input.request.responseRedactions,
291
+ cookie: input.request.cookie,
292
+ secretParamValues: input.request.secretParamValues,
293
+ geoLocation: input.request.geoLocation,
294
+ useTee: input.request.useTee,
295
+ zkEngine: input.request.zkEngine,
296
+ context: envelope,
297
+ });
298
+ const { proof } = proved;
299
+ // Deterministically bind BOTH the exact proven request (method/url/body, post
300
+ // nonce-injection) and the exact PROVEN (redacted/extracted) response content
301
+ // into the receipt, so the receipt is verifiable dispute evidence even though
302
+ // the oracle itself does not re-derive these hashes today.
303
+ const canonicalRequestHash = hashCanonical({
304
+ method: proved.request.method,
305
+ url: proved.request.url,
306
+ body: proved.request.body,
307
+ });
308
+ const canonicalBodyHash = hashCanonical({
309
+ extractedParameters: proved.verification.extractedParameters,
310
+ });
311
+ const receipt = deliveryReceiptSchema.parse({
312
+ streamId: BigInt(input.streamId),
313
+ serviceRef: input.serviceRef,
314
+ operator: input.operator,
315
+ intervalIndex: input.intervalIndex,
316
+ nonce: input.nonce,
317
+ reclaimProofId: proof.identifier,
318
+ reclaimOwner: proof.claimData.owner,
319
+ reclaimTimestamp: BigInt(proof.claimData.timestampS),
320
+ reclaimEpoch: BigInt(proof.claimData.epoch),
321
+ canonicalRequestHash,
322
+ canonicalBodyHash,
323
+ });
324
+ const signature = await signDeliveryReceipt(receipt, input.domain, input.buyer);
325
+ const body = deliveryProofRequestBodySchema.parse({
326
+ receipt: toWireDeliveryReceipt(receipt),
327
+ signature,
328
+ proof: {
329
+ identifier: proof.identifier,
330
+ claimData: proof.claimData,
331
+ signatures: proof.signatures,
332
+ },
333
+ });
334
+ return { body, receipt, signature, proof, envelope };
335
+ }
336
+ //# sourceMappingURL=t2-delivery-proof.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"t2-delivery-proof.js","sourceRoot":"","sources":["../../src/zktls/t2-delivery-proof.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absol-labs/agent",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "Metrik agent layer: x402 verified-streaming payments, an MCP server, framework tools, and spend mandates so AI agents can hire and pay verified services safely.",
5
5
  "license": "MIT",
6
6
  "author": "Absol Labs",
@@ -66,8 +66,8 @@
66
66
  "pnpm": "9.15.x"
67
67
  },
68
68
  "dependencies": {
69
- "@absol-labs/sdk": "^0.4.0",
70
- "@absol-labs/shared": "^0.7.1",
69
+ "@absol-labs/sdk": "^0.7.0",
70
+ "@absol-labs/shared": "^0.11.0",
71
71
  "@coinbase/cdp-sdk": "^1.51.2",
72
72
  "@modelcontextprotocol/sdk": "^1.29.0",
73
73
  "@reclaimprotocol/js-sdk": "^5.6.0",
@@ -108,9 +108,12 @@
108
108
  "build:e2e": "tsc -p tsconfig.e2e.build.json",
109
109
  "mcp:stdio": "tsx src/mcp/stdio.ts",
110
110
  "mcp:http": "tsx src/mcp/http-server.ts",
111
+ "gateway": "tsx src/gateway/server-entry.ts",
111
112
  "e2e:cdp": "node dist-e2e/scripts/e2e-cdp.js",
113
+ "e2e:hire": "tsx scripts/e2e-hire.ts",
112
114
  "l2:proof": "node scripts/l2-proof.mjs",
113
115
  "test": "vitest run",
116
+ "test:package": "node scripts/test-packed-package.mjs",
114
117
  "typecheck": "tsc -p tsconfig.json --noEmit",
115
118
  "typecheck:e2e": "tsc -p tsconfig.e2e.json --noEmit",
116
119
  "lint": "tsc -p tsconfig.json --noEmit",
@@ -0,0 +1,255 @@
1
+ import { randomBytes } from "node:crypto";
2
+
3
+ import {
4
+ getAddress,
5
+ isAddress,
6
+ isHex,
7
+ keccak256,
8
+ recoverTypedDataAddress,
9
+ stringToBytes,
10
+ type Address,
11
+ type Hex,
12
+ type LocalAccount,
13
+ } from "viem";
14
+ import { z } from "zod";
15
+
16
+ /**
17
+ * `InvocationCapability` — the stream-bound EIP-712 credential that closes the
18
+ * "pay -> use" loop (metrik-protocol#62/#63/#64).
19
+ *
20
+ * A buyer who has opened an active, funded stream signs one of these per
21
+ * service call: "I, `buyer`, authorize exactly `method` `pathHash` against
22
+ * `serviceRef` under stream `streamId`, once, before `expiry`." The seller's
23
+ * gateway (`../gateway/caller-auth-gateway.ts`) recovers the signer, cross
24
+ * checks it against the on-chain stream, and enforces the nonce/expiry/route
25
+ * binding before proxying the call upstream.
26
+ *
27
+ * Deliberately kept LOCAL to `@absol-labs/agent` for this MVP slice (per
28
+ * metrik-agent#64) rather than added to `@absol-labs/shared` - it is never
29
+ * read on-chain (no contract parses it), so there is no cross-repo byte
30
+ * compatibility requirement the way there is for `DeliveryReceipt`.
31
+ */
32
+
33
+ const addressSchema = z
34
+ .string()
35
+ .refine((value) => isAddress(value), "must be an EVM address");
36
+ const bytes32Schema = z
37
+ .string()
38
+ .refine(
39
+ (value) => isHex(value, { strict: true }) && value.length === 66,
40
+ "must be bytes32 hex",
41
+ );
42
+ const signatureSchema = z
43
+ .string()
44
+ .refine(
45
+ (value) => isHex(value, { strict: true }) && value.length === 132,
46
+ "must be a 65-byte signature",
47
+ );
48
+
49
+ /** HTTP methods a capability may authorize. */
50
+ export const httpMethodSchema = z.enum([
51
+ "GET",
52
+ "POST",
53
+ "PUT",
54
+ "PATCH",
55
+ "DELETE",
56
+ "HEAD",
57
+ "OPTIONS",
58
+ ]);
59
+ export type HttpMethod = z.infer<typeof httpMethodSchema>;
60
+
61
+ export const invocationCapabilitySchema = z.object({
62
+ /** The on-chain `StreamEscrowV2` stream this capability draws authority from. */
63
+ streamId: bytes32Schema,
64
+ /** Must equal `stream.buyer` and the EIP-712 signer. */
65
+ buyer: addressSchema,
66
+ /** Must equal the target service's `serviceRef` (and the stream's). */
67
+ serviceRef: bytes32Schema,
68
+ /** The single HTTP method this capability authorizes. */
69
+ method: httpMethodSchema,
70
+ /** `keccak256` of the exact request path this capability authorizes. */
71
+ pathHash: bytes32Schema,
72
+ /** Single-use anti-replay nonce. */
73
+ nonce: bytes32Schema,
74
+ /** Unix seconds after which the capability is no longer valid. */
75
+ expiry: z.number().int().positive(),
76
+ });
77
+ export type InvocationCapability = z.infer<typeof invocationCapabilitySchema>;
78
+
79
+ export const signedInvocationCapabilitySchema =
80
+ invocationCapabilitySchema.extend({
81
+ signature: signatureSchema,
82
+ });
83
+ export type SignedInvocationCapability = z.infer<
84
+ typeof signedInvocationCapabilitySchema
85
+ >;
86
+
87
+ /** Chain-bound domain: a capability for one chain/escrow can never be replayed against another. */
88
+ export interface InvocationCapabilityDomainInput {
89
+ readonly chainId: number;
90
+ /** The `StreamEscrowV2` the stream settles on. */
91
+ readonly verifyingContract: Address;
92
+ }
93
+
94
+ export const invocationCapabilityDomainName =
95
+ "Metrik Invocation Capability" as const;
96
+ export const invocationCapabilityDomainVersion = "1" as const;
97
+
98
+ export const invocationCapabilityTypedData = {
99
+ InvocationCapability: [
100
+ { name: "streamId", type: "bytes32" },
101
+ { name: "buyer", type: "address" },
102
+ { name: "serviceRef", type: "bytes32" },
103
+ { name: "method", type: "string" },
104
+ { name: "pathHash", type: "bytes32" },
105
+ { name: "nonce", type: "bytes32" },
106
+ { name: "expiry", type: "uint64" },
107
+ ],
108
+ } as const;
109
+
110
+ /** Default single-use lifetime for a freshly-issued capability. Deliberately short. */
111
+ export const DEFAULT_CAPABILITY_TTL_SECONDS = 60;
112
+
113
+ /** Header a buyer's request carries the signed capability in. */
114
+ export const CAPABILITY_HEADER_NAME = "x-metrik-capability";
115
+
116
+ export function createInvocationCapabilityEip712Domain(
117
+ domain: InvocationCapabilityDomainInput,
118
+ ) {
119
+ return {
120
+ name: invocationCapabilityDomainName,
121
+ version: invocationCapabilityDomainVersion,
122
+ chainId: domain.chainId,
123
+ verifyingContract: getAddress(domain.verifyingContract),
124
+ } as const;
125
+ }
126
+
127
+ /**
128
+ * `keccak256` of the exact request path this capability authorizes (e.g.
129
+ * `/v1/infer`). Path only - no scheme/host/query/fragment - so the signer and
130
+ * the gateway hash the identical canonical string regardless of how each side
131
+ * received the full URL.
132
+ */
133
+ export function hashInvocationPath(path: string): Hex {
134
+ return keccak256(stringToBytes(normalizeInvocationPath(path)));
135
+ }
136
+
137
+ /** Strips query/fragment and any trailing slash (except the root) for a stable canonical form. */
138
+ export function normalizeInvocationPath(path: string): string {
139
+ const withoutFragment = path.split("#")[0] ?? "";
140
+ const withoutQuery = withoutFragment.split("?")[0] ?? "";
141
+ if (withoutQuery.length === 0) {
142
+ return "/";
143
+ }
144
+ if (withoutQuery.length > 1 && withoutQuery.endsWith("/")) {
145
+ return withoutQuery.slice(0, -1);
146
+ }
147
+ return withoutQuery;
148
+ }
149
+
150
+ function invocationCapabilityMessage(capability: InvocationCapability) {
151
+ const parsed = invocationCapabilitySchema.parse(capability);
152
+ return {
153
+ streamId: parsed.streamId as Hex,
154
+ buyer: getAddress(parsed.buyer),
155
+ serviceRef: parsed.serviceRef as Hex,
156
+ method: parsed.method,
157
+ pathHash: parsed.pathHash as Hex,
158
+ nonce: parsed.nonce as Hex,
159
+ expiry: BigInt(parsed.expiry),
160
+ };
161
+ }
162
+
163
+ export function buildInvocationCapabilityTypedData(
164
+ capability: InvocationCapability,
165
+ domain: InvocationCapabilityDomainInput,
166
+ ) {
167
+ return {
168
+ domain: createInvocationCapabilityEip712Domain(domain),
169
+ types: invocationCapabilityTypedData,
170
+ primaryType: "InvocationCapability" as const,
171
+ message: invocationCapabilityMessage(capability),
172
+ };
173
+ }
174
+
175
+ /** Signs an `InvocationCapability` with the buyer's own wallet. */
176
+ export async function signInvocationCapability(
177
+ capability: InvocationCapability,
178
+ domain: InvocationCapabilityDomainInput,
179
+ account: LocalAccount,
180
+ ): Promise<Hex> {
181
+ const typedData = buildInvocationCapabilityTypedData(capability, domain);
182
+ return account.signTypedData(typedData);
183
+ }
184
+
185
+ /** Recovers the EIP-712 signer of a capability. Throws on a malformed signature. */
186
+ export async function recoverInvocationCapabilitySigner(
187
+ capability: InvocationCapability,
188
+ domain: InvocationCapabilityDomainInput,
189
+ signature: Hex,
190
+ ): Promise<Address> {
191
+ const typedData = buildInvocationCapabilityTypedData(capability, domain);
192
+ return recoverTypedDataAddress({ ...typedData, signature });
193
+ }
194
+
195
+ /** Cryptographically random 32-byte single-use nonce. */
196
+ export function generateCapabilityNonce(): Hex {
197
+ return `0x${randomBytes(32).toString("hex")}` as Hex;
198
+ }
199
+
200
+ export class InvalidCapabilityHeaderError extends Error {
201
+ constructor(message: string, options?: { readonly cause?: unknown }) {
202
+ super(message, options);
203
+ this.name = "InvalidCapabilityHeaderError";
204
+ }
205
+ }
206
+
207
+ /** Encodes a signed capability as an opaque, header-safe (base64url) string. */
208
+ export function encodeCapabilityHeader(
209
+ signed: SignedInvocationCapability,
210
+ ): string {
211
+ const parsed = signedInvocationCapabilitySchema.parse(signed);
212
+ const json = JSON.stringify({
213
+ streamId: parsed.streamId,
214
+ buyer: parsed.buyer,
215
+ serviceRef: parsed.serviceRef,
216
+ method: parsed.method,
217
+ pathHash: parsed.pathHash,
218
+ nonce: parsed.nonce,
219
+ expiry: parsed.expiry,
220
+ signature: parsed.signature,
221
+ });
222
+ return Buffer.from(json, "utf8").toString("base64url");
223
+ }
224
+
225
+ /** Decodes and schema-validates a capability header value. Fails closed on any malformation. */
226
+ export function decodeCapabilityHeader(
227
+ headerValue: string,
228
+ ): SignedInvocationCapability {
229
+ let json: string;
230
+ try {
231
+ json = Buffer.from(headerValue, "base64url").toString("utf8");
232
+ } catch (cause) {
233
+ throw new InvalidCapabilityHeaderError(
234
+ "malformed base64 capability header",
235
+ { cause },
236
+ );
237
+ }
238
+
239
+ let raw: unknown;
240
+ try {
241
+ raw = JSON.parse(json);
242
+ } catch (cause) {
243
+ throw new InvalidCapabilityHeaderError("malformed JSON capability header", {
244
+ cause,
245
+ });
246
+ }
247
+
248
+ const result = signedInvocationCapabilitySchema.safeParse(raw);
249
+ if (!result.success) {
250
+ throw new InvalidCapabilityHeaderError(
251
+ `invalid capability shape: ${result.error.message}`,
252
+ );
253
+ }
254
+ return result.data;
255
+ }
@@ -365,7 +365,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
365
365
  @CreateAction({
366
366
  name: "check_stream_status",
367
367
  description:
368
- "Read a Metrik stream's status: verified accrued amount, whether it is active or paused (two failed checks auto-pause), claimable-by-seller, and reclaimable-by-buyer USDC.",
368
+ "Read a Metrik stream's status, verified accrued amount, claimable-by-seller, and reclaimable-by-buyer USDC. In V2, failed or unproven intervals do not advance cumulative entitlement; the stream remains active until buyer close or expiry.",
369
369
  schema: checkStreamStatusSchema,
370
370
  })
371
371
  async checkStreamStatus(
@@ -390,7 +390,7 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
390
390
  @CreateAction({
391
391
  name: "reclaim_unspent",
392
392
  description:
393
- "Reclaim unspent escrowed USDC from a Metrik stream back to the buyer. Set closeFirst to close an active stream before reclaiming. Runs under the same signed mandate controls.",
393
+ "Reclaim unspent escrowed USDC from a Metrik stream back to the buyer. Set closeFirst to close an active stream before reclaiming. V2 reclaim follows checkpoint finalization or escape-window rules. Runs under the same signed mandate controls.",
394
394
  schema: reclaimUnspentSchema,
395
395
  })
396
396
  async reclaimUnspent(