agent402-client 0.8.16 → 0.8.18
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 +20 -7
- package/index.js +33 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ instance) - the buy side of [Agentic Finance](https://agent402.tools/agentic-fin
|
|
|
5
5
|
agents paying per request over x402 or MPP. **Resolve a task to a tool, then call it - with payment handled for
|
|
6
6
|
you.** Free pure-CPU tools settle with a built-in proof-of-work (no wallet, zero
|
|
7
7
|
dependencies); wallet-only tools settle via an x402- or MPP-wrapped fetch you
|
|
8
|
-
provide, or through a prepaid credits key
|
|
8
|
+
provide, or through a prepaid credits key. Results are cached, and every
|
|
9
9
|
send carries an `Idempotency-Key` that is stable per client and per operation, so
|
|
10
10
|
a retried lost response replays the paid answer on the credits and proof-of-work
|
|
11
11
|
paths (the wallet path is different: see "Retries and double charges").
|
|
@@ -71,11 +71,14 @@ const a = new Agent402({ fetch: payFetch });
|
|
|
71
71
|
const article = await a.call("extract", { url: "https://agent402.tools/guides/x402-in-5-minutes" });
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
##
|
|
74
|
+
## Paying with a credits key
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
A prepaid credits key (`a402_...`; agent402.tools/credits says whether packs are on
|
|
77
|
+
sale) pays for Agent402's own services: pass it
|
|
77
78
|
as `creditsKey` and the SDK sends `Authorization: Bearer a402_...` on wallet-only
|
|
78
|
-
calls (the wallet-scoped routes, memory and usage, refuse it and need a wallet
|
|
79
|
+
calls (the wallet-scoped routes, memory and usage, refuse it and need a wallet, as do
|
|
80
|
+
the routes that buy from an outside seller: the route-execute tiers,
|
|
81
|
+
`seller-payability`, `decide-execute` and the flight routes); the server authorizes
|
|
79
82
|
against the key's balance before the handler runs and debits the list price only
|
|
80
83
|
on a successful (200) response (the `X-Credits-Balance` header carries what is
|
|
81
84
|
left; credits never expire). A refused call throws with the balance; nothing is
|
|
@@ -116,7 +119,17 @@ What the server does with it depends on how the call was paid:
|
|
|
116
119
|
dedupe). So on the wallet path a retry after a lost response can settle twice;
|
|
117
120
|
the `Idempotency-Key` cannot prevent that on its own. If that matters for your
|
|
118
121
|
workload, use a credits key for the tools you retry, or keep the signed
|
|
119
|
-
request and resend it yourself.
|
|
122
|
+
request and resend it yourself. A resent signed request needs no key: the
|
|
123
|
+
server answers a request re-sent with the same signed EVM payment, to the same
|
|
124
|
+
route with the same body, from its first answer inside the replay window,
|
|
125
|
+
with no second settlement, and marks it `X-Replayed-Answer: 1` (identity-bound
|
|
126
|
+
routes, routes with a lasting effect and streamed calls excepted).
|
|
127
|
+
- **Circle Gateway batched option:** where the server offers it on Arc or Base,
|
|
128
|
+
the 402 carries a second accept whose `extra.name` is `GatewayWalletBatched`.
|
|
129
|
+
This package pays the plain accept on those networks (the stock x402 client
|
|
130
|
+
takes the first accept it can pay, and the plain one is first); the batched
|
|
131
|
+
one needs a client that signs under the Gateway domain against a Circle
|
|
132
|
+
Gateway deposit.
|
|
120
133
|
|
|
121
134
|
## Workflows (skill packs)
|
|
122
135
|
|
|
@@ -215,7 +228,7 @@ that runs as one.
|
|
|
215
228
|
|
|
216
229
|
| Method | What |
|
|
217
230
|
|---|---|
|
|
218
|
-
| `new Agent402({ baseUrl?, fetch?, x402Client?, creditsKey?, cache?, fetchImpl?, maxPerCallUsd?, dailyLimitUsd?, maxPerHostUsd?, maxResponseBytes?, outputValidator?, respondAsync?, asyncTimeoutMs?, onProgress? })` | `fetch` is your x402- or MPP-wrapped fetch for paid tools (optional); `x402Client` is the `@x402/core` client that `fetch` wraps, so the caps are enforced on the payment that is signed (see below); `creditsKey` is a prepaid card-credits key (`a402_...`) used for paid tools when no `fetch` is given; `cache` (default `true`) memoizes deterministic results; the three USD caps set optional spending limits (see below); `maxResponseBytes` (default 32MB, `null` to disable) refuses an oversized response body before it is parsed; `outputValidator` binds a caller-supplied delivery check; `respondAsync` (default `"auto"`), `asyncTimeoutMs` (default 15 minutes) and `onProgress` control slow routes run as jobs (see above) |
|
|
231
|
+
| `new Agent402({ baseUrl?, fetch?, x402Client?, creditsKey?, cache?, fetchImpl?, maxPerCallUsd?, dailyLimitUsd?, maxPerHostUsd?, payNetworks?, maxResponseBytes?, outputValidator?, respondAsync?, asyncTimeoutMs?, onProgress? })` | `fetch` is your x402- or MPP-wrapped fetch for paid tools (optional); `x402Client` is the `@x402/core` client that `fetch` wraps, so the caps are enforced on the payment that is signed (see below); `payNetworks` (for example `["base"]`, the names `withNetworkPreference` takes) tells the caps which chains a pre-wrapped `fetch` without an `x402Client` pays on, so a call is counted at the dearest option on those chains (when none of a 402's options is on them, the dearest of all counts); `creditsKey` is a prepaid card-credits key (`a402_...`) used for paid tools when no `fetch` is given; `cache` (default `true`) memoizes deterministic results; the three USD caps set optional spending limits (see below); `maxResponseBytes` (default 32MB, `null` to disable) refuses an oversized response body before it is parsed; `outputValidator` binds a caller-supplied delivery check; `respondAsync` (default `"auto"`), `asyncTimeoutMs` (default 15 minutes) and `onProgress` control slow routes run as jobs (see above) |
|
|
219
232
|
| `await a.find(task, { k = 5 })` | Resolve a plain-language task to the best-matching tools on **this host** (route, price, schema, example) |
|
|
220
233
|
| `await a.route(task, { k?, include?, network? })` | Cross-seller Smart Order Router: rank eligible/routable seller rows from the host's current index (free, read-only; opaque results may include server-reported `executeVia`) |
|
|
221
234
|
| `await a.findWorkflows(task, { k = 2 })` | Resolve a task to matching multi-tool workflow templates (skill packs) |
|
|
@@ -361,7 +374,7 @@ each call reserves its amount synchronously, so N simultaneous calls can't each
|
|
|
361
374
|
pass against the same pre-commit total.
|
|
362
375
|
|
|
363
376
|
- **Zero dependencies** for the free/proof-of-work path (uses `node:crypto`).
|
|
364
|
-
- **Non-custodial:** paid settlement is your `@x402/fetch` / `mppx` fetch + wallet (or a prepaid credits key
|
|
377
|
+
- **Non-custodial:** paid settlement is your `@x402/fetch` / `mppx` fetch + wallet (or a prepaid credits key); this client never sees a private key.
|
|
365
378
|
- MIT licensed. Part of [Agent402](https://github.com/MikeyPetrillo/Agent402).
|
|
366
379
|
|
|
367
380
|
## Pick the settlement chain (`withNetworkPreference`)
|
package/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export { AsyncJobPendingError } from "./async-job.js";
|
|
|
30
30
|
// `User-Agent: agent402-client/<version>` - a standard header, no extra
|
|
31
31
|
// network calls - so a seller can attribute traffic (and settled payments)
|
|
32
32
|
// to this SDK. Product token only; nothing about the caller rides along.
|
|
33
|
-
const VERSION = "0.8.
|
|
33
|
+
const VERSION = "0.8.18";
|
|
34
34
|
const USER_AGENT = `agent402-client/${VERSION}`;
|
|
35
35
|
// 32MB: about a hundred times any realistic response from this catalog (the
|
|
36
36
|
// largest is a base64 image at a few MB), so it cannot break a legitimate
|
|
@@ -91,8 +91,11 @@ export class Agent402 {
|
|
|
91
91
|
* @param {number} [opts.maxPerHostUsd] hard ceiling on rolling-24h paid spend to one seller host (USD)
|
|
92
92
|
* @param {object} [opts.x402Client] the @x402/core x402Client your `fetch` wraps: the caps are then
|
|
93
93
|
* enforced on the payment that is signed (see guardX402Client)
|
|
94
|
-
* @param {string} [opts.
|
|
95
|
-
*
|
|
94
|
+
* @param {string[]} [opts.payNetworks] the chains your pre-wrapped `fetch` pays on (e.g. ["base"], the
|
|
95
|
+
* names withNetworkPreference takes): without an x402Client the
|
|
96
|
+
* caps count the dearest accept on these chains, not on every chain
|
|
97
|
+
* @param {string} [opts.creditsKey] a prepaid card-credits key (a402_...) - pays wallet-only tools on
|
|
98
|
+
* Agent402's own services when no payFetch is given
|
|
96
99
|
* @param {number|null} [opts.maxResponseBytes=33554432]
|
|
97
100
|
* Hard ceiling on a response body, enforced BEFORE it is parsed. null disables it.
|
|
98
101
|
* @param {{id:string, validate:function}} [opts.outputValidator]
|
|
@@ -109,7 +112,7 @@ export class Agent402 {
|
|
|
109
112
|
* ({ status, stage, progress, etaSeconds, ... }) while a job runs
|
|
110
113
|
*/
|
|
111
114
|
constructor({ baseUrl = "https://agent402.tools", fetch: payFetch, cache = true, fetchImpl = undefined, tlsDistrust = true,
|
|
112
|
-
maxPerCallUsd = null, dailyLimitUsd = null, maxPerHostUsd = null, creditsKey = null, x402Client = null,
|
|
115
|
+
maxPerCallUsd = null, dailyLimitUsd = null, maxPerHostUsd = null, creditsKey = null, x402Client = null, payNetworks = null,
|
|
113
116
|
maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES, outputValidator = null,
|
|
114
117
|
respondAsync = "auto", asyncTimeoutMs = DEFAULT_ASYNC_TIMEOUT_MS, onProgress = null } = {}) {
|
|
115
118
|
this.respondAsync = respondAsync;
|
|
@@ -155,6 +158,10 @@ export class Agent402 {
|
|
|
155
158
|
this._signCtx = new AsyncLocalStorage();
|
|
156
159
|
this._guarded = false;
|
|
157
160
|
if (x402Client) this.guardX402Client(x402Client);
|
|
161
|
+
// The chains a pre-wrapped fetch pays on, as CAIP-2 ids (null = unknown).
|
|
162
|
+
this._payNetworks = Array.isArray(payNetworks) && payNetworks.length
|
|
163
|
+
? new Set(payNetworks.map((n) => String(NETWORK_CAIP2[String(n).trim().toLowerCase()] || String(n).trim()).toLowerCase()))
|
|
164
|
+
: null;
|
|
158
165
|
// A response-size ceiling, enforced before parsing. See _readJson.
|
|
159
166
|
this.maxResponseBytes = maxResponseBytes === null ? null : (numOrNull(maxResponseBytes) ?? DEFAULT_MAX_RESPONSE_BYTES);
|
|
160
167
|
// Buyer-owned delivery policy. The callback stays entirely local and may
|
|
@@ -574,7 +581,7 @@ export class Agent402 {
|
|
|
574
581
|
}
|
|
575
582
|
const r = await send(); // no wallet - succeeds only on a FREE_MODE instance
|
|
576
583
|
if (r.ok) return this._deliverResponse(slug, r, cacheKey, cache, validator, { maxResponseBytes, paid: false });
|
|
577
|
-
throw this._fail(slug, r, `call "${slug}" failed: HTTP ${r.status} - wallet-only tool; construct with { fetch: payFetch } (an @x402/fetch-wrapped fetch) or { creditsKey } (a prepaid credits key
|
|
584
|
+
throw this._fail(slug, r, `call "${slug}" failed: HTTP ${r.status} - wallet-only tool; construct with { fetch: payFetch } (an @x402/fetch-wrapped fetch) or { creditsKey } (a prepaid credits key; routes that buy from an outside seller need a wallet)`);
|
|
578
585
|
}
|
|
579
586
|
|
|
580
587
|
// Free (compute-payable) tool: succeeds plainly on a FREE_MODE instance,
|
|
@@ -649,8 +656,11 @@ export class Agent402 {
|
|
|
649
656
|
* "guarded" (the signing guard holds every signature to the caps, so the
|
|
650
657
|
* cheapest known accept is what can be paid, and unknown ones are dropped
|
|
651
658
|
* there), "wallet" (no guard: the wallet may sign any accept, so the dearest
|
|
652
|
-
* one counts,
|
|
653
|
-
*
|
|
659
|
+
* one counts, among the chains in `payNetworks` when they are given, and one
|
|
660
|
+
* that cannot be priced is refused here), or "credits" (nothing is signed:
|
|
661
|
+
* the credits gate debits the route's own quote, and no accept is below it,
|
|
662
|
+
* since a chain premium or price floor only raises an accept, so the
|
|
663
|
+
* cheapest known accept counts).
|
|
654
664
|
* @returns {Promise<number>} the quoted amount, or `listUsd` when there is no readable 402 */
|
|
655
665
|
async _quotedUsd(send, listUsd, { slug = "", mode = "wallet" } = {}) {
|
|
656
666
|
if (!this._spendCapsConfigured()) return listUsd;
|
|
@@ -658,7 +668,14 @@ export class Agent402 {
|
|
|
658
668
|
try {
|
|
659
669
|
const pre = await send();
|
|
660
670
|
if (pre?.status !== 402) return listUsd;
|
|
661
|
-
|
|
671
|
+
let accepts = await challengeAccepts(pre);
|
|
672
|
+
if (mode === "wallet" && this._payNetworks && Array.isArray(accepts)) {
|
|
673
|
+
const onChains = accepts.filter((a) => this._payNetworks.has(String(a?.network || "").toLowerCase()));
|
|
674
|
+
// No option on the declared chains (or a name that maps to none): the
|
|
675
|
+
// wallet may still sign any of them, so the dearest of all counts.
|
|
676
|
+
if (onChains.length) accepts = onChains;
|
|
677
|
+
}
|
|
678
|
+
q = quoteOf(accepts);
|
|
662
679
|
} catch (e) {
|
|
663
680
|
// A redirect is refused here, before anything is reserved or signed.
|
|
664
681
|
if (e instanceof PaymentRedirectError) throw e;
|
|
@@ -671,7 +688,7 @@ export class Agent402 {
|
|
|
671
688
|
`refusing to pay for "${slug}" - ${q.max == null ? "no" : "a"} payment option it offers is in an asset this client cannot price, and a capped wallet signs only what it can price${mode === "wallet" ? " (pass your x402Client to guard signing and pay the options it can price)" : ""}`,
|
|
672
689
|
{ limit: "knownAsset", slug, priceUsd: null, unknownOptions: q.unknown });
|
|
673
690
|
}
|
|
674
|
-
const quoted = mode === "
|
|
691
|
+
const quoted = mode === "wallet" ? q.max : q.min;
|
|
675
692
|
// Larger of the two: an understated catalog must not lower the ceiling
|
|
676
693
|
// the cap is checked against.
|
|
677
694
|
return Math.max(listUsd, quoted);
|
|
@@ -955,8 +972,15 @@ export const NETWORK_CAIP2 = {
|
|
|
955
972
|
"base-sepolia": "eip155:84532",
|
|
956
973
|
robinhood: "eip155:4663",
|
|
957
974
|
arc: "eip155:5042",
|
|
975
|
+
monad: "eip155:143",
|
|
976
|
+
celo: "eip155:42220",
|
|
977
|
+
avalanche: "eip155:43114",
|
|
978
|
+
sei: "eip155:1329",
|
|
979
|
+
optimism: "eip155:10",
|
|
958
980
|
solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
959
981
|
"solana-devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
|
|
982
|
+
stellar: "stellar:pubnet",
|
|
983
|
+
algorand: "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=",
|
|
960
984
|
};
|
|
961
985
|
|
|
962
986
|
export function withNetworkPreference(client, networks) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent402-client",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.18",
|
|
4
4
|
"description": "Agent402 buyer SDK: resolve a task to a tool across 500+ pay-per-call endpoints and call it with payment handled - free via proof-of-work, or over x402 or MPP (a stock mppx fetch works) with a wallet you keep; the buy side of Agentic Finance. Caching, idempotent retries (Idempotency-Key), non-custodial, zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|