@absol-labs/agent 0.5.0 → 0.7.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 (76) hide show
  1. package/README.md +49 -10
  2. package/dist/discovery/registry.d.ts +260 -15
  3. package/dist/discovery/registry.d.ts.map +1 -1
  4. package/dist/discovery/registry.js +174 -31
  5. package/dist/discovery/registry.js.map +1 -1
  6. package/dist/frameworks/agentkit.js +1 -1
  7. package/dist/frameworks/agentkit.js.map +1 -1
  8. package/dist/frameworks/crewai.js +1 -1
  9. package/dist/frameworks/crewai.js.map +1 -1
  10. package/dist/gateway/caller-auth-gateway.d.ts +3 -1
  11. package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
  12. package/dist/gateway/caller-auth-gateway.js +9 -7
  13. package/dist/gateway/caller-auth-gateway.js.map +1 -1
  14. package/dist/gateway/http-server.d.ts +3 -1
  15. package/dist/gateway/http-server.d.ts.map +1 -1
  16. package/dist/gateway/http-server.js +15 -1
  17. package/dist/gateway/http-server.js.map +1 -1
  18. package/dist/index.d.ts +8 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +8 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp/server.js +2 -0
  23. package/dist/mcp/server.js.map +1 -1
  24. package/dist/sdk/invoke.d.ts +16 -2
  25. package/dist/sdk/invoke.d.ts.map +1 -1
  26. package/dist/sdk/invoke.js +117 -1
  27. package/dist/sdk/invoke.js.map +1 -1
  28. package/dist/wallet/autonomous-wallet-broker.d.ts +97 -0
  29. package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -0
  30. package/dist/wallet/autonomous-wallet-broker.js +468 -0
  31. package/dist/wallet/autonomous-wallet-broker.js.map +1 -0
  32. package/dist/wallet/autonomous-wallet-protocol.d.ts +56 -0
  33. package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -0
  34. package/dist/wallet/autonomous-wallet-protocol.js +15 -0
  35. package/dist/wallet/autonomous-wallet-protocol.js.map +1 -0
  36. package/dist/wallet/autonomous-wallet.d.ts +106 -0
  37. package/dist/wallet/autonomous-wallet.d.ts.map +1 -0
  38. package/dist/wallet/autonomous-wallet.js +494 -0
  39. package/dist/wallet/autonomous-wallet.js.map +1 -0
  40. package/dist/wallet/privy-broker-server-entry.d.ts +2 -0
  41. package/dist/wallet/privy-broker-server-entry.d.ts.map +1 -0
  42. package/dist/wallet/privy-broker-server-entry.js +8 -0
  43. package/dist/wallet/privy-broker-server-entry.js.map +1 -0
  44. package/dist/wallet/privy-broker-server.d.ts +29 -0
  45. package/dist/wallet/privy-broker-server.d.ts.map +1 -0
  46. package/dist/wallet/privy-broker-server.js +480 -0
  47. package/dist/wallet/privy-broker-server.js.map +1 -0
  48. package/dist/wallet/privy-session-broker.d.ts +109 -0
  49. package/dist/wallet/privy-session-broker.d.ts.map +1 -0
  50. package/dist/wallet/privy-session-broker.js +372 -0
  51. package/dist/wallet/privy-session-broker.js.map +1 -0
  52. package/dist/wallet/privy-session-provider.d.ts +21 -0
  53. package/dist/wallet/privy-session-provider.d.ts.map +1 -0
  54. package/dist/wallet/privy-session-provider.js +94 -0
  55. package/dist/wallet/privy-session-provider.js.map +1 -0
  56. package/dist/wallet/provider.d.ts +51 -2
  57. package/dist/wallet/provider.d.ts.map +1 -1
  58. package/dist/wallet/provider.js +138 -1
  59. package/dist/wallet/provider.js.map +1 -1
  60. package/package.json +4 -2
  61. package/src/discovery/registry.ts +213 -35
  62. package/src/frameworks/agentkit.ts +1 -1
  63. package/src/frameworks/crewai.ts +1 -1
  64. package/src/gateway/caller-auth-gateway.ts +13 -9
  65. package/src/gateway/http-server.ts +18 -1
  66. package/src/index.ts +78 -0
  67. package/src/mcp/server.ts +2 -0
  68. package/src/sdk/invoke.ts +186 -4
  69. package/src/wallet/autonomous-wallet-broker.ts +764 -0
  70. package/src/wallet/autonomous-wallet-protocol.ts +71 -0
  71. package/src/wallet/autonomous-wallet.ts +779 -0
  72. package/src/wallet/privy-broker-server-entry.ts +9 -0
  73. package/src/wallet/privy-broker-server.ts +573 -0
  74. package/src/wallet/privy-session-broker.ts +634 -0
  75. package/src/wallet/privy-session-provider.ts +129 -0
  76. package/src/wallet/provider.ts +260 -3
package/src/sdk/invoke.ts CHANGED
@@ -1,7 +1,16 @@
1
- import { type DeliveryReceiptDomainInput } from "@absol-labs/shared";
1
+ import {
2
+ deriveServiceRef,
3
+ recoverServiceBindingSigner,
4
+ recoverServiceDescriptorSigner,
5
+ signedServiceBindingSchema,
6
+ signedServiceDescriptorSchema,
7
+ type DeliveryReceiptDomainInput,
8
+ } from "@absol-labs/shared";
2
9
  import { MetrikClient } from "@absol-labs/sdk";
3
10
  import type { Address, Hex, LocalAccount } from "viem";
4
11
 
12
+ import type { ServiceListing } from "../discovery/registry.js";
13
+
5
14
  import {
6
15
  buildT2DeliveryProofSubmission,
7
16
  type BuildT2DeliveryProofResult,
@@ -89,6 +98,31 @@ export class InvokeBuyerMismatchError extends Error {
89
98
  }
90
99
  }
91
100
 
101
+ export class InvokeServiceRefMismatchError extends Error {
102
+ constructor(streamRef: Hex, listingRef: Hex) {
103
+ super(
104
+ `stream serviceRef ${streamRef} does not match listing serviceRef ${listingRef}`,
105
+ );
106
+ this.name = "InvokeServiceRefMismatchError";
107
+ }
108
+ }
109
+
110
+ export class InvokeAccessUrlError extends Error {
111
+ constructor(message: string) {
112
+ super(message);
113
+ this.name = "InvokeAccessUrlError";
114
+ }
115
+ }
116
+
117
+ export class InvokePathError extends Error {
118
+ constructor(path: string) {
119
+ super(
120
+ `invocation path must be origin-relative and start with one slash: ${path}`,
121
+ );
122
+ this.name = "InvokePathError";
123
+ }
124
+ }
125
+
92
126
  export interface CapabilityForOptions {
93
127
  readonly buyer: LocalAccount;
94
128
  readonly domain: InvocationCapabilityDomainInput;
@@ -142,8 +176,10 @@ export interface InvokeOptions {
142
176
  readonly buyer: LocalAccount;
143
177
  /** `{chainId, verifyingContract}` - the `StreamEscrowV2` the stream settles on. */
144
178
  readonly domain: InvocationCapabilityDomainInput;
145
- /** Base URL of the gateway-fronted service (from the service listing/descriptor). */
146
- readonly serviceBaseUrl: string;
179
+ /** Preferred: a cryptographically verified result from discoverServices(). */
180
+ readonly listing?: ServiceListing;
181
+ /** @deprecated Manual escape hatch. Verified listing routing is safer. */
182
+ readonly serviceBaseUrl?: string;
147
183
  readonly ttlSeconds?: number;
148
184
  readonly nonce?: Hex;
149
185
  readonly nowSeconds?: number;
@@ -168,6 +204,7 @@ export async function invoke(
168
204
  request: InvokeServiceInput,
169
205
  options: InvokeOptions,
170
206
  ): Promise<InvokeResult> {
207
+ assertOriginRelativePath(request.path);
171
208
  const stream = await options.streamReader.getStreamV2(streamId);
172
209
  const nowSeconds = options.nowSeconds ?? Math.floor(Date.now() / 1000);
173
210
 
@@ -185,6 +222,11 @@ export async function invoke(
185
222
  throw new InvokeStreamExpiredError(streamId, stream.expiresAt);
186
223
  }
187
224
 
225
+ const serviceBaseUrl = await resolveInvocationBaseUrl(
226
+ stream.serviceRef,
227
+ options,
228
+ );
229
+
188
230
  const capability = await capabilityFor(streamId, request, {
189
231
  buyer: options.buyer,
190
232
  domain: options.domain,
@@ -197,7 +239,10 @@ export async function invoke(
197
239
  });
198
240
 
199
241
  const header = encodeCapabilityHeader(capability);
200
- const url = new URL(request.path, options.serviceBaseUrl).toString();
242
+ const url = new URL(
243
+ request.path,
244
+ ensureTrailingSlash(serviceBaseUrl),
245
+ ).toString();
201
246
  const fetchImpl = options.fetchImpl ?? fetch;
202
247
  const response = await fetchImpl(url, {
203
248
  method: request.method,
@@ -219,6 +264,8 @@ export interface InvokeWithT2DeliveryProofOptions {
219
264
  readonly domain: DeliveryReceiptDomainInput;
220
265
  /** The T2 paid-route spec (absolute `url`, `responseMatches`, nonce injection point, ...). */
221
266
  readonly request: PaidRouteRequestSpec;
267
+ /** Verified listing. Gated T2 is rejected until proof-target pinning supports it. */
268
+ readonly listing?: ServiceListing;
222
269
  /** Which billing interval this delivery proof covers. */
223
270
  readonly intervalIndex: bigint;
224
271
  /** Oracle-issued anti-replay nonce, from `GET /delivery/nonce`. */
@@ -267,6 +314,22 @@ export async function invokeWithT2DeliveryProof(
267
314
  throw new InvokeStreamExpiredError(streamId, stream.expiresAt);
268
315
  }
269
316
 
317
+ if (options.listing !== undefined) {
318
+ const route = await verifyListingRoute(stream.serviceRef, options.listing);
319
+ if (route.access === "gated") {
320
+ throw new InvokeAccessUrlError(
321
+ "consumer-attested T2 invocation is not supported for gated listings",
322
+ );
323
+ }
324
+ const requestOrigin = new URL(options.request.url).origin;
325
+ const signedOrigin = new URL(route.url).origin;
326
+ if (requestOrigin !== signedOrigin) {
327
+ throw new InvokeAccessUrlError(
328
+ `T2 request origin ${requestOrigin} does not match signed listing origin ${signedOrigin}`,
329
+ );
330
+ }
331
+ }
332
+
270
333
  const path = new URL(options.request.url).pathname;
271
334
  const capability = await capabilityFor(
272
335
  streamId,
@@ -311,3 +374,122 @@ export async function invokeWithT2DeliveryProof(
311
374
 
312
375
  return { capability, stream, t2 };
313
376
  }
377
+
378
+ async function resolveInvocationBaseUrl(
379
+ streamRef: Hex,
380
+ options: InvokeOptions,
381
+ ): Promise<string> {
382
+ if (options.listing !== undefined) {
383
+ return (await verifyListingRoute(streamRef, options.listing)).url;
384
+ }
385
+ if (options.serviceBaseUrl === undefined) {
386
+ throw new InvokeAccessUrlError(
387
+ "a verified listing is required (or pass deprecated serviceBaseUrl explicitly)",
388
+ );
389
+ }
390
+ return requireHttpUrl(options.serviceBaseUrl, "serviceBaseUrl");
391
+ }
392
+
393
+ async function verifyListingRoute(
394
+ streamRef: Hex,
395
+ listing: ServiceListing,
396
+ ): Promise<{ readonly access: "public" | "gated"; readonly url: string }> {
397
+ if (streamRef.toLowerCase() !== listing.serviceRef.toLowerCase()) {
398
+ throw new InvokeServiceRefMismatchError(streamRef, listing.serviceRef);
399
+ }
400
+
401
+ const descriptor = signedServiceDescriptorSchema.safeParse(listing.signed);
402
+ if (descriptor.success) {
403
+ const signed = descriptor.data;
404
+ const derived = deriveServiceRef(signed.descriptor);
405
+ const signer = await recoverServiceDescriptorSigner(
406
+ signed.descriptor,
407
+ signed.signature as Hex,
408
+ );
409
+ const access = signed.descriptor.access ?? "public";
410
+ const url =
411
+ access === "gated"
412
+ ? signed.descriptor.callerAuth?.accessUrl
413
+ : (signed.descriptor.interface?.baseUrl ?? signed.descriptor.publicUrl);
414
+ if (
415
+ derived.toLowerCase() !== listing.serviceRef.toLowerCase() ||
416
+ signed.serviceRef.toLowerCase() !== listing.serviceRef.toLowerCase() ||
417
+ signer === null ||
418
+ signer.toLowerCase() !== signed.descriptor.operator.toLowerCase() ||
419
+ listing.operator.toLowerCase() !==
420
+ signed.descriptor.operator.toLowerCase() ||
421
+ listing.publicUrl !== signed.descriptor.publicUrl ||
422
+ listing.access !== access ||
423
+ url === undefined ||
424
+ listing.accessUrl !== url
425
+ ) {
426
+ throw new InvokeAccessUrlError(
427
+ "listing does not match its verified signed descriptor",
428
+ );
429
+ }
430
+ const verifiedUrl = requireHttpUrl(url, "signed listing access URL");
431
+ if (access === "gated" && new URL(verifiedUrl).protocol !== "https:") {
432
+ throw new InvokeAccessUrlError(
433
+ "signed gated listing access URL must use HTTPS",
434
+ );
435
+ }
436
+ return { access, url: verifiedUrl };
437
+ }
438
+
439
+ const binding = signedServiceBindingSchema.safeParse(listing.signed);
440
+ if (binding.success) {
441
+ const signed = binding.data;
442
+ const derived = deriveServiceRef(signed.binding);
443
+ const signer = await recoverServiceBindingSigner(
444
+ signed.binding,
445
+ signed.signature as Hex,
446
+ );
447
+ if (
448
+ derived.toLowerCase() !== listing.serviceRef.toLowerCase() ||
449
+ signed.serviceRef.toLowerCase() !== listing.serviceRef.toLowerCase() ||
450
+ signer === null ||
451
+ signer.toLowerCase() !== signed.binding.operator.toLowerCase() ||
452
+ listing.operator.toLowerCase() !==
453
+ signed.binding.operator.toLowerCase() ||
454
+ listing.publicUrl !== signed.binding.publicUrl ||
455
+ listing.access !== "public" ||
456
+ listing.accessUrl !== signed.binding.publicUrl
457
+ ) {
458
+ throw new InvokeAccessUrlError(
459
+ "listing does not match its verified signed binding",
460
+ );
461
+ }
462
+ return {
463
+ access: "public",
464
+ url: requireHttpUrl(
465
+ signed.binding.publicUrl,
466
+ "signed listing access URL",
467
+ ),
468
+ };
469
+ }
470
+
471
+ throw new InvokeAccessUrlError("listing signed record is invalid");
472
+ }
473
+
474
+ function requireHttpUrl(value: string, label: string): string {
475
+ let parsed: URL;
476
+ try {
477
+ parsed = new URL(value);
478
+ } catch {
479
+ throw new InvokeAccessUrlError(`${label} must be an absolute HTTP(S) URL`);
480
+ }
481
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
482
+ throw new InvokeAccessUrlError(`${label} must be an absolute HTTP(S) URL`);
483
+ }
484
+ return parsed.toString();
485
+ }
486
+
487
+ function assertOriginRelativePath(path: string): void {
488
+ if (!path.startsWith("/") || path.startsWith("//") || path.includes("#")) {
489
+ throw new InvokePathError(path);
490
+ }
491
+ }
492
+
493
+ function ensureTrailingSlash(value: string): string {
494
+ return value.endsWith("/") ? value : `${value}/`;
495
+ }