@absol-labs/agent 0.8.0 → 0.9.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 (49) hide show
  1. package/dist/discovery/registry.d.ts +110 -305
  2. package/dist/discovery/registry.d.ts.map +1 -1
  3. package/dist/discovery/registry.js +141 -318
  4. package/dist/discovery/registry.js.map +1 -1
  5. package/dist/frameworks/agentkit.d.ts.map +1 -1
  6. package/dist/frameworks/agentkit.js +23 -6
  7. package/dist/frameworks/agentkit.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/wallet/cdp-sdk.d.ts +23 -0
  13. package/dist/wallet/cdp-sdk.d.ts.map +1 -0
  14. package/dist/wallet/cdp-sdk.js +27 -0
  15. package/dist/wallet/cdp-sdk.js.map +1 -0
  16. package/dist/wallet/provider.d.ts +1 -1
  17. package/dist/wallet/provider.d.ts.map +1 -1
  18. package/dist/wallet/provider.js +8 -3
  19. package/dist/wallet/provider.js.map +1 -1
  20. package/dist/zktls/reclaim-js-sdk.d.ts +24 -0
  21. package/dist/zktls/reclaim-js-sdk.d.ts.map +1 -0
  22. package/dist/zktls/reclaim-js-sdk.js +29 -0
  23. package/dist/zktls/reclaim-js-sdk.js.map +1 -0
  24. package/dist/zktls/reclaim.d.ts +14 -2
  25. package/dist/zktls/reclaim.d.ts.map +1 -1
  26. package/dist/zktls/reclaim.js +29 -6
  27. package/dist/zktls/reclaim.js.map +1 -1
  28. package/dist/zktls/t2-delivery-proof.d.ts +8 -1
  29. package/dist/zktls/t2-delivery-proof.d.ts.map +1 -1
  30. package/dist/zktls/t2-delivery-proof.js +22 -6
  31. package/dist/zktls/t2-delivery-proof.js.map +1 -1
  32. package/docs/agent-layer.md +150 -0
  33. package/docs/autonomous-privy-wallet.md +133 -0
  34. package/docs/crewai.md +70 -0
  35. package/docs/eliza.md +109 -0
  36. package/docs/langchain.md +63 -0
  37. package/docs/mcp-hosted.md +137 -0
  38. package/docs/privy-embedded-wallet.md +102 -0
  39. package/docs/quickstart.md +370 -0
  40. package/docs/threat-model.md +160 -0
  41. package/package.json +19 -6
  42. package/src/discovery/registry.ts +242 -414
  43. package/src/frameworks/agentkit.ts +24 -5
  44. package/src/index.ts +5 -0
  45. package/src/wallet/cdp-sdk.ts +33 -0
  46. package/src/wallet/provider.ts +16 -9
  47. package/src/zktls/reclaim-js-sdk.ts +50 -0
  48. package/src/zktls/reclaim.ts +57 -23
  49. package/src/zktls/t2-delivery-proof.ts +28 -10
@@ -14,6 +14,7 @@ import { isAddress, isHex } from "viem";
14
14
  import { z } from "zod";
15
15
 
16
16
  import {
17
+ RegistryUnavailableError,
17
18
  discoverServices as defaultDiscoverServices,
18
19
  type DiscoverServicesOptions,
19
20
  type ServiceListing,
@@ -281,12 +282,30 @@ export class MetrikActionProvider extends ActionProvider<WalletProvider> {
281
282
  _walletProvider: WalletProvider,
282
283
  args: z.infer<typeof discoverServicesSchema>,
283
284
  ): Promise<string> {
284
- const listings = await this.#discover({
285
- ...(args.category === undefined ? {} : { category: args.category }),
286
- ...(args.limit === undefined ? {} : { limit: args.limit }),
287
- });
285
+ let listings: ServiceListing[];
286
+ try {
287
+ listings = await this.#discover({
288
+ ...(args.category === undefined ? {} : { category: args.category }),
289
+ ...(args.limit === undefined ? {} : { limit: args.limit }),
290
+ });
291
+ } catch (error) {
292
+ // Discovery throws when the registry could not be READ at all. Every other
293
+ // action here returns a string, and more importantly an agent must be able to
294
+ // tell "the marketplace was never reached" from "the marketplace is empty" —
295
+ // collapsing them is how an agent concludes there is nothing to hire and gives
296
+ // up on a live marketplace. So report the failure as a failure, explicitly.
297
+ if (error instanceof RegistryUnavailableError) {
298
+ return (
299
+ "Could not reach the Metrik marketplace registry, so the set of available " +
300
+ "services is UNKNOWN — this is not the same as there being no services. " +
301
+ `Do not conclude nothing is hireable. Reason: ${error.message}`
302
+ );
303
+ }
304
+ throw error;
305
+ }
288
306
  if (listings.length === 0) {
289
- return "No verified Metrik services discovered.";
307
+ // Reachable and genuinely empty, or everything filtered out — a real answer.
308
+ return "No verified Metrik services discovered (the registry was reachable and returned no listing that passed verification).";
290
309
  }
291
310
  const lines = listings.map(
292
311
  (listing) =>
package/src/index.ts CHANGED
@@ -46,13 +46,18 @@ export {
46
46
  } from "./x402/facilitator.js";
47
47
 
48
48
  export {
49
+ DEFAULT_METRIK_PUBLIC_REGISTRY_URL,
49
50
  DEFAULT_METRIK_REGISTRY_URL,
50
51
  DEMO_SEED_LISTING,
51
52
  DEMO_SEED_SERVICE_REF,
52
53
  LIVE_DATA_SEED_LISTING,
53
54
  LIVE_DATA_SEED_SERVICE_REF,
55
+ RegistryUnavailableError,
54
56
  discoverServices,
57
+ discoverServicesDetailed,
58
+ type DiscoverResult,
55
59
  type DiscoverServicesOptions,
60
+ type DiscoveredService,
56
61
  type ServiceListing,
57
62
  } from "./discovery/registry.js";
58
63
 
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `@coinbase/cdp-sdk` is an OPTIONAL peer dependency: only consumers that use the
3
+ * Coinbase CDP wallet path need it, and it carries a very large transitive graph
4
+ * (it was the main contributor to the 18 -> ~515 package jump a consumer saw just
5
+ * for hiring and invoking a service). The top-level "@absol-labs/agent" barrel
6
+ * DOES reach `./provider.ts`, so that module must import the SDK's TYPES only
7
+ * (`import type`, erased at compile time) and load the runtime module lazily
8
+ * through this loader at the point of first use.
9
+ *
10
+ * This is the same contract as `../zktls/reclaim-js-sdk.ts`, and it is enforced
11
+ * by the barrel-reachability guard in `test/flat-install.test.ts`: a static value
12
+ * import of an optional peer from any barrel-reachable module fails that test.
13
+ *
14
+ * Deliberately NOT a top-level `await import(...)` (the pattern used by
15
+ * `../frameworks/agentkit.ts`): those modules are not barrel-reachable, this one
16
+ * is, and a top-level await would re-introduce the hard dependency at
17
+ * barrel-import time — precisely the regression that issue #79 was filed for.
18
+ */
19
+
20
+ type CdpSdkModule = typeof import("@coinbase/cdp-sdk");
21
+
22
+ let modulePromise: Promise<CdpSdkModule> | undefined;
23
+
24
+ /** Memoized lazy load with an actionable missing-peer error. */
25
+ export async function loadCdpSdk(): Promise<CdpSdkModule> {
26
+ modulePromise ??= import("@coinbase/cdp-sdk").catch((error: unknown) => {
27
+ throw new Error(
28
+ "@absol-labs/agent CDP wallet support requires the optional peer dependency '@coinbase/cdp-sdk'. Install it with `npm install @coinbase/cdp-sdk`, or use a different wallet mode (the autonomous Privy wallet and an injected account both work without it).",
29
+ { cause: error },
30
+ );
31
+ });
32
+ return await modulePromise;
33
+ }
@@ -1,9 +1,10 @@
1
1
  import { type StreamProofClientConfig } from "@absol-labs/sdk";
2
- import {
3
- CdpClient,
4
- type EvmServerAccount,
5
- type EvmSmartAccount,
6
- } from "@coinbase/cdp-sdk";
2
+ // `@coinbase/cdp-sdk` is an OPTIONAL peer dependency: TYPES only here (erased at
3
+ // compile time), the runtime module via `loadCdpSdk()` at the point of first use.
4
+ // This module IS reachable from the package barrel, so a value import here would
5
+ // re-introduce the hard dependency for every consumer. See ./cdp-sdk.ts.
6
+ import type { EvmServerAccount, EvmSmartAccount } from "@coinbase/cdp-sdk";
7
+ import { loadCdpSdk } from "./cdp-sdk.js";
7
8
  import {
8
9
  custom,
9
10
  toHex,
@@ -173,9 +174,12 @@ export async function resolveAgentWallet(
173
174
  };
174
175
  }
175
176
 
176
- const cdpClient = (options.createCdpClient ?? defaultCdpClientFactory)(
177
- input.cdp,
178
- );
177
+ // An injected factory keeps its synchronous public signature; only the DEFAULT
178
+ // path is async, because it lazily loads the optional @coinbase/cdp-sdk peer.
179
+ const cdpClient =
180
+ options.createCdpClient === undefined
181
+ ? await defaultCdpClientFactory(input.cdp)
182
+ : options.createCdpClient(input.cdp);
179
183
  const owner = await cdpClient.evm.getOrCreateAccount({
180
184
  name: input.cdp.ownerName,
181
185
  });
@@ -338,7 +342,10 @@ export function parseAgentWalletEnv(
338
342
  };
339
343
  }
340
344
 
341
- function defaultCdpClientFactory(config: CdpWalletConfig): CdpClientLike {
345
+ async function defaultCdpClientFactory(
346
+ config: CdpWalletConfig,
347
+ ): Promise<CdpClientLike> {
348
+ const { CdpClient } = await loadCdpSdk();
342
349
  return new CdpClient({
343
350
  ...(config.apiKeyId === undefined ? {} : { apiKeyId: config.apiKeyId }),
344
351
  ...(config.apiKeySecret === undefined
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `@reclaimprotocol/js-sdk` is an OPTIONAL peer dependency: only consumers that
3
+ * actually generate/verify zkTLS delivery proofs (T2, issue #24) need it, and it
4
+ * carries a large transitive graph. The top-level "@absol-labs/agent" barrel
5
+ * DOES re-export the zkTLS modules, so those modules must import the SDK's
6
+ * TYPES only (`import type`, erased at compile time) and load the runtime module
7
+ * lazily through this loader at the point of first use.
8
+ *
9
+ * Deliberately NOT a top-level `await import(...)` (the pattern used by
10
+ * `../frameworks/langchain.ts`): that module is not barrel-reachable, this one
11
+ * is, and a top-level await would re-introduce the hard dependency at
12
+ * barrel-import time.
13
+ */
14
+
15
+ type ReclaimJsSdkModule = typeof import("@reclaimprotocol/js-sdk");
16
+
17
+ let modulePromise: Promise<ReclaimJsSdkModule> | undefined;
18
+
19
+ /** Memoized lazy load with an actionable missing-peer error. */
20
+ export async function loadReclaimJsSdk(): Promise<ReclaimJsSdkModule> {
21
+ modulePromise ??= import("@reclaimprotocol/js-sdk").catch(
22
+ (error: unknown) => {
23
+ throw new Error(
24
+ "@absol-labs/agent zkTLS delivery-proof support requires the optional peer dependency '@reclaimprotocol/js-sdk'. Install it with `npm install @reclaimprotocol/js-sdk`.",
25
+ { cause: error },
26
+ );
27
+ },
28
+ );
29
+ return await modulePromise;
30
+ }
31
+
32
+ /**
33
+ * `@reclaimprotocol/zk-fetch` is the companion optional peer used to PRODUCE
34
+ * proofs (the SDK above verifies them). Same contract, same actionable error.
35
+ */
36
+ type ReclaimZkFetchModule = typeof import("@reclaimprotocol/zk-fetch");
37
+
38
+ let zkFetchModulePromise: Promise<ReclaimZkFetchModule> | undefined;
39
+
40
+ export async function loadReclaimZkFetch(): Promise<ReclaimZkFetchModule> {
41
+ zkFetchModulePromise ??= import("@reclaimprotocol/zk-fetch").catch(
42
+ (error: unknown) => {
43
+ throw new Error(
44
+ "@absol-labs/agent zkTLS delivery-proof support requires the optional peer dependency '@reclaimprotocol/zk-fetch'. Install it with `npm install @reclaimprotocol/zk-fetch`.",
45
+ { cause: error },
46
+ );
47
+ },
48
+ );
49
+ return await zkFetchModulePromise;
50
+ }
@@ -1,13 +1,16 @@
1
- import {
2
- getHttpProviderClaimParamsFromProof,
3
- getProviderHashRequirementsFromSpec,
1
+ // `@reclaimprotocol/js-sdk` is an OPTIONAL peer dependency: TYPES only here
2
+ // (erased at compile time), runtime values via `loadReclaimJsSdk()` at the point
3
+ // of first use. See ./reclaim-js-sdk.ts.
4
+ import type {
4
5
  verifyProof,
5
- type Proof as ReclaimProtocolProof,
6
- type RequestSpec,
7
- type VerifyProofResult,
6
+ Proof as ReclaimProtocolProof,
7
+ RequestSpec,
8
+ VerifyProofResult,
8
9
  } from "@reclaimprotocol/js-sdk";
9
10
  import { z } from "zod";
10
11
 
12
+ import { loadReclaimJsSdk, loadReclaimZkFetch } from "./reclaim-js-sdk.js";
13
+
11
14
  const addressSchema = z.string().regex(/^0x[0-9a-fA-F]{40}$/);
12
15
  const bytes32Schema = z.string().regex(/^0x[0-9a-fA-F]{64}$/);
13
16
  const httpMethodSchema = z.enum(["GET", "POST", "PUT"]);
@@ -172,7 +175,14 @@ const reclaimProofInputSchema = z.object({
172
175
  export class ReclaimConsumerProofService implements ConsumerDeliveryProofService {
173
176
  private readonly client: ReclaimClientLike;
174
177
  private readonly config: ReclaimProofServiceConfig;
175
- private readonly verifyProofImpl: VerifyProofFn;
178
+ /**
179
+ * Caller-supplied verifier, if any. NOT defaulted in the constructor: the real
180
+ * `verifyProof` lives in the optional peer `@reclaimprotocol/js-sdk`, which is
181
+ * loaded lazily at first use so that merely constructing this service — or
182
+ * importing the package barrel — never requires the peer to be installed.
183
+ * Resolved in {@link resolveVerifyProof}.
184
+ */
185
+ private readonly verifyProofOverride: VerifyProofFn | undefined;
176
186
 
177
187
  constructor(
178
188
  config: ReclaimProofServiceConfig,
@@ -194,7 +204,16 @@ export class ReclaimConsumerProofService implements ConsumerDeliveryProofService
194
204
  this.config.applicationSecret,
195
205
  this.config.logs ?? false,
196
206
  );
197
- this.verifyProofImpl = options.verifyProof ?? verifyProof;
207
+ this.verifyProofOverride = options.verifyProof;
208
+ }
209
+
210
+ /**
211
+ * The verifier to use: a caller-supplied override, else the optional peer's
212
+ * `verifyProof`, loaded on first use with an actionable missing-peer error.
213
+ */
214
+ private async resolveVerifyProof(): Promise<VerifyProofFn> {
215
+ if (this.verifyProofOverride !== undefined) return this.verifyProofOverride;
216
+ return (await loadReclaimJsSdk()).verifyProof;
198
217
  }
199
218
 
200
219
  async proveConsumedHttpsResponse(
@@ -244,8 +263,15 @@ export class ReclaimConsumerProofService implements ConsumerDeliveryProofService
244
263
  );
245
264
  }
246
265
 
247
- const verification = await this.verifyProofImpl(proof, {
248
- ...getProviderHashRequirementsFromSpec({
266
+ // Both the verifier and the provider-hash helper live in the optional peer;
267
+ // load it once here rather than importing it at module scope.
268
+ const [verifyProofFn, reclaimSdk] = await Promise.all([
269
+ this.resolveVerifyProof(),
270
+ loadReclaimJsSdk(),
271
+ ]);
272
+
273
+ const verification = await verifyProofFn(proof, {
274
+ ...reclaimSdk.getProviderHashRequirementsFromSpec({
249
275
  requests: [toRequestSpec(parsed, method)],
250
276
  }),
251
277
  ...(parsed.useTee === true
@@ -271,25 +297,33 @@ export class ReclaimConsumerProofService implements ConsumerDeliveryProofService
271
297
  );
272
298
  }
273
299
 
274
- const request = getHttpProviderClaimParamsFromProof(proof);
300
+ // Same optional peer, already memoized by the loader above.
301
+ const request = reclaimSdk.getHttpProviderClaimParamsFromProof(proof);
302
+ type ClaimParams = ReturnType<
303
+ typeof reclaimSdk.getHttpProviderClaimParamsFromProof
304
+ >;
275
305
  return {
276
306
  proof,
277
307
  request: {
278
308
  url: request.url,
279
309
  method: request.method as "GET" | "POST" | "PUT",
280
310
  body: request.body === "" ? null : (request.body ?? null),
281
- responseMatches: request.responseMatches.map((match) => ({
282
- value: match.value,
283
- type: match.type,
284
- invert: match.invert,
285
- isOptional: match.isOptional,
286
- })),
287
- responseRedactions: request.responseRedactions.map((redaction) => ({
288
- regex: redaction.regex,
289
- jsonPath: redaction.jsonPath,
290
- xPath: redaction.xPath,
291
- hash: redaction.hash,
292
- })),
311
+ responseMatches: request.responseMatches.map(
312
+ (match: ClaimParams["responseMatches"][number]) => ({
313
+ value: match.value,
314
+ type: match.type,
315
+ invert: match.invert,
316
+ isOptional: match.isOptional,
317
+ }),
318
+ ),
319
+ responseRedactions: request.responseRedactions.map(
320
+ (redaction: ClaimParams["responseRedactions"][number]) => ({
321
+ regex: redaction.regex,
322
+ jsonPath: redaction.jsonPath,
323
+ xPath: redaction.xPath,
324
+ hash: redaction.hash,
325
+ }),
326
+ ),
293
327
  },
294
328
  verification: {
295
329
  context: trusted.context,
@@ -5,11 +5,12 @@ import {
5
5
  type DeliveryReceipt,
6
6
  type DeliveryReceiptDomainInput,
7
7
  } from "@absol-labs/shared";
8
- import {
9
- getHttpProviderClaimParamsFromProof,
10
- getProviderHashRequirementsFromSpec,
11
- verifyProof,
12
- } from "@reclaimprotocol/js-sdk";
8
+ // `@reclaimprotocol/js-sdk` is an OPTIONAL peer dependency and this module IS
9
+ // reachable from the package barrel, so it may import TYPES only (erased at
10
+ // compile time); runtime values come from `loadReclaimJsSdk()` at first use.
11
+ // Enforced by the barrel-reachability guard in test/flat-install.test.ts.
12
+ import type { verifyProof } from "@reclaimprotocol/js-sdk";
13
+ import { loadReclaimJsSdk } from "./reclaim-js-sdk.js";
13
14
  import {
14
15
  keccak256,
15
16
  stringToBytes,
@@ -167,7 +168,12 @@ const reclaimT2UrlSchema = z.string().url();
167
168
  export class ReclaimDeliveryProofAttestor implements DeliveryProofAttestor {
168
169
  private readonly client: ReclaimClientLike;
169
170
  private readonly config: ReclaimProofServiceConfig;
170
- private readonly verifyProofImpl: VerifyProofFn;
171
+ /**
172
+ * Caller-supplied verifier, if any. NOT defaulted in the constructor: the real
173
+ * `verifyProof` lives in the optional peer, loaded lazily at first use so that
174
+ * constructing this service never requires the peer to be installed.
175
+ */
176
+ private readonly verifyProofOverride: VerifyProofFn | undefined;
171
177
 
172
178
  constructor(
173
179
  config: ReclaimProofServiceConfig,
@@ -189,7 +195,13 @@ export class ReclaimDeliveryProofAttestor implements DeliveryProofAttestor {
189
195
  this.config.applicationSecret,
190
196
  this.config.logs ?? false,
191
197
  );
192
- this.verifyProofImpl = options.verifyProof ?? verifyProof;
198
+ this.verifyProofOverride = options.verifyProof;
199
+ }
200
+
201
+ /** Override if given, else the optional peer's `verifyProof`, loaded on demand. */
202
+ private async resolveVerifyProof(): Promise<VerifyProofFn> {
203
+ if (this.verifyProofOverride !== undefined) return this.verifyProofOverride;
204
+ return (await loadReclaimJsSdk()).verifyProof;
193
205
  }
194
206
 
195
207
  async proveDeliveryResponse(
@@ -245,8 +257,14 @@ export class ReclaimDeliveryProofAttestor implements DeliveryProofAttestor {
245
257
  );
246
258
  }
247
259
 
248
- const verification = await this.verifyProofImpl(proof, {
249
- ...getProviderHashRequirementsFromSpec({
260
+ // Verifier and provider-hash helper both live in the optional peer; load once.
261
+ const [verifyProofFn, reclaimSdk] = await Promise.all([
262
+ this.resolveVerifyProof(),
263
+ loadReclaimJsSdk(),
264
+ ]);
265
+
266
+ const verification = await verifyProofFn(proof, {
267
+ ...reclaimSdk.getProviderHashRequirementsFromSpec({
250
268
  requests: [toRequestSpec(parsed, method)],
251
269
  }),
252
270
  ...(parsed.useTee === true
@@ -266,7 +284,7 @@ export class ReclaimDeliveryProofAttestor implements DeliveryProofAttestor {
266
284
  );
267
285
  }
268
286
 
269
- const request = getHttpProviderClaimParamsFromProof(proof);
287
+ const request = reclaimSdk.getHttpProviderClaimParamsFromProof(proof);
270
288
  return {
271
289
  proof,
272
290
  request: {