@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.
- package/README.md +49 -10
- package/dist/discovery/registry.d.ts +260 -15
- package/dist/discovery/registry.d.ts.map +1 -1
- package/dist/discovery/registry.js +174 -31
- package/dist/discovery/registry.js.map +1 -1
- package/dist/frameworks/agentkit.js +1 -1
- package/dist/frameworks/agentkit.js.map +1 -1
- package/dist/frameworks/crewai.js +1 -1
- package/dist/frameworks/crewai.js.map +1 -1
- package/dist/gateway/caller-auth-gateway.d.ts +3 -1
- package/dist/gateway/caller-auth-gateway.d.ts.map +1 -1
- package/dist/gateway/caller-auth-gateway.js +9 -7
- package/dist/gateway/caller-auth-gateway.js.map +1 -1
- package/dist/gateway/http-server.d.ts +3 -1
- package/dist/gateway/http-server.d.ts.map +1 -1
- package/dist/gateway/http-server.js +15 -1
- package/dist/gateway/http-server.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/sdk/invoke.d.ts +16 -2
- package/dist/sdk/invoke.d.ts.map +1 -1
- package/dist/sdk/invoke.js +117 -1
- package/dist/sdk/invoke.js.map +1 -1
- package/dist/wallet/autonomous-wallet-broker.d.ts +97 -0
- package/dist/wallet/autonomous-wallet-broker.d.ts.map +1 -0
- package/dist/wallet/autonomous-wallet-broker.js +468 -0
- package/dist/wallet/autonomous-wallet-broker.js.map +1 -0
- package/dist/wallet/autonomous-wallet-protocol.d.ts +56 -0
- package/dist/wallet/autonomous-wallet-protocol.d.ts.map +1 -0
- package/dist/wallet/autonomous-wallet-protocol.js +15 -0
- package/dist/wallet/autonomous-wallet-protocol.js.map +1 -0
- package/dist/wallet/autonomous-wallet.d.ts +106 -0
- package/dist/wallet/autonomous-wallet.d.ts.map +1 -0
- package/dist/wallet/autonomous-wallet.js +494 -0
- package/dist/wallet/autonomous-wallet.js.map +1 -0
- package/dist/wallet/privy-broker-server-entry.d.ts +2 -0
- package/dist/wallet/privy-broker-server-entry.d.ts.map +1 -0
- package/dist/wallet/privy-broker-server-entry.js +8 -0
- package/dist/wallet/privy-broker-server-entry.js.map +1 -0
- package/dist/wallet/privy-broker-server.d.ts +29 -0
- package/dist/wallet/privy-broker-server.d.ts.map +1 -0
- package/dist/wallet/privy-broker-server.js +480 -0
- package/dist/wallet/privy-broker-server.js.map +1 -0
- package/dist/wallet/privy-session-broker.d.ts +109 -0
- package/dist/wallet/privy-session-broker.d.ts.map +1 -0
- package/dist/wallet/privy-session-broker.js +372 -0
- package/dist/wallet/privy-session-broker.js.map +1 -0
- package/dist/wallet/privy-session-provider.d.ts +21 -0
- package/dist/wallet/privy-session-provider.d.ts.map +1 -0
- package/dist/wallet/privy-session-provider.js +94 -0
- package/dist/wallet/privy-session-provider.js.map +1 -0
- package/dist/wallet/provider.d.ts +51 -2
- package/dist/wallet/provider.d.ts.map +1 -1
- package/dist/wallet/provider.js +138 -1
- package/dist/wallet/provider.js.map +1 -1
- package/package.json +4 -2
- package/src/discovery/registry.ts +213 -35
- package/src/frameworks/agentkit.ts +1 -1
- package/src/frameworks/crewai.ts +1 -1
- package/src/gateway/caller-auth-gateway.ts +13 -9
- package/src/gateway/http-server.ts +18 -1
- package/src/index.ts +78 -0
- package/src/mcp/server.ts +2 -0
- package/src/sdk/invoke.ts +186 -4
- package/src/wallet/autonomous-wallet-broker.ts +764 -0
- package/src/wallet/autonomous-wallet-protocol.ts +71 -0
- package/src/wallet/autonomous-wallet.ts +779 -0
- package/src/wallet/privy-broker-server-entry.ts +9 -0
- package/src/wallet/privy-broker-server.ts +573 -0
- package/src/wallet/privy-session-broker.ts +634 -0
- package/src/wallet/privy-session-provider.ts +129 -0
- package/src/wallet/provider.ts +260 -3
package/src/sdk/invoke.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import {
|
|
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
|
-
/**
|
|
146
|
-
readonly
|
|
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(
|
|
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
|
+
}
|