agent402-client 0.8.3 → 0.8.4

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 (3) hide show
  1. package/README.md +2 -1
  2. package/index.js +21 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -147,7 +147,8 @@ const { query, include, results } = await a.route(task, {
147
147
  include: "external", // all | external | local
148
148
  network: "robinhood", // optional chain filter (short name or CAIP-2)
149
149
  });
150
- // results[]: opaque server rows - { seller, slug, url, priceUsd, executeVia?, ... }
150
+ // results[]: opaque server rows - { seller, slug, url, priceUsd, routerDispatchEligible, routerDispatchReason,
151
+ // executeVia? (only when executeViaCallableNow is true) | executeViaWhenEligible?, ... }
151
152
 
152
153
  // executeVia quotes which route-execute* tier fits a row's underlying price.
153
154
  // It does NOT bind that row: the tier re-resolves an eligible match under its
package/index.js CHANGED
@@ -23,12 +23,13 @@ import { createHash, randomBytes } from "node:crypto";
23
23
  // `User-Agent: agent402-client/<version>` - a standard header, no extra
24
24
  // network calls - so a seller can attribute traffic (and settled payments)
25
25
  // to this SDK. Product token only; nothing about the caller rides along.
26
- const VERSION = "0.8.3";
26
+ const VERSION = "0.8.4";
27
27
  const USER_AGENT = `agent402-client/${VERSION}`;
28
28
  // 32MB: about a hundred times any realistic response from this catalog (the
29
29
  // largest is a base64 image at a few MB), so it cannot break a legitimate
30
30
  // caller, while still stopping the class it exists for. A ceiling that is off
31
31
  // by default protects nobody, so this one is on; pass null to disable it.
32
+ const FAILURE_DETAIL_MAX_CHARS = 2_000;
32
33
  const DEFAULT_MAX_RESPONSE_BYTES = 32 * 1024 * 1024;
33
34
 
34
35
  const leadingZeroBits = (buf) => { let n = 0; for (const b of buf) { if (b === 0) { n += 8; continue; } n += Math.clz32(b) - 24; break; } return n; };
@@ -365,7 +366,7 @@ export class Agent402 {
365
366
  let settled = false;
366
367
  try {
367
368
  const r = await send({}, this.payFetch);
368
- if (!r.ok) throw new Error(`call "${slug}" failed: HTTP ${r.status}`);
369
+ if (!r.ok) throw new Error(await this._failureDetail(slug, r));
369
370
  this._spendSettle(reservation); // confirm the reservation as settled spend
370
371
  settled = true;
371
372
  return this._deliverResponse(slug, r, cacheKey, cache, validator, { maxResponseBytes, paid: true });
@@ -390,7 +391,7 @@ export class Agent402 {
390
391
  const body = await r.json().catch(() => ({}));
391
392
  throw new Error(`call "${slug}" refused by credits: ${body.error || "payment required"}${body.balanceUsd != null ? ` (balance $${body.balanceUsd})` : ""} - top up at ${body.topup || `${this.baseUrl}/credits`}`);
392
393
  }
393
- if (!r.ok) throw new Error(`call "${slug}" failed: HTTP ${r.status}`);
394
+ if (!r.ok) throw new Error(await this._failureDetail(slug, r));
394
395
  this._spendSettle(reservation);
395
396
  settled = true;
396
397
  return this._deliverResponse(slug, r, cacheKey, cache, validator, { maxResponseBytes, paid: true });
@@ -409,7 +410,7 @@ export class Agent402 {
409
410
  const chal = await this._powChallenge(slug);
410
411
  r = await send({ "X-Pow-Solution": Agent402.solvePow(chal) });
411
412
  }
412
- if (!r.ok) throw new Error(`call "${slug}" failed after proof-of-work: HTTP ${r.status}`);
413
+ if (!r.ok) throw new Error(await this._failureDetail(slug, r, " after proof-of-work"));
413
414
  return this._deliverResponse(slug, r, cacheKey, cache, validator, { maxResponseBytes, paid: false });
414
415
  }
415
416
 
@@ -475,6 +476,22 @@ export class Agent402 {
475
476
  }
476
477
  }
477
478
 
479
+ /** The message for a failed call CARRIES THE SELLER'S OWN DETAIL. Agent402's
480
+ * 4xx bodies are self-explaining ({error, tool, expected}); a message that
481
+ * said only "HTTP 400" threw that away, and an agent reading it could not
482
+ * correct its input (elizaOS registry review, 2026-09-14). Bounded, and a
483
+ * body that is not JSON contributes nothing but its status. */
484
+ async _failureDetail(slug, r, when = "") {
485
+ let detail = "";
486
+ try {
487
+ const body = await r.json();
488
+ const msg = body?.error ?? body?.message ?? body?.detail;
489
+ if (msg != null) detail = ` - ${typeof msg === "string" ? msg : JSON.stringify(msg)}`;
490
+ if (body?.expected != null) detail += ` (expected: ${JSON.stringify(body.expected)})`;
491
+ } catch { /* not JSON: the status is the whole story */ }
492
+ return `call "${slug}" failed${when}: HTTP ${r.status}${detail.slice(0, FAILURE_DETAIL_MAX_CHARS)}`;
493
+ }
494
+
478
495
  /** True if any spending ceiling is configured (worth preflighting the 402). */
479
496
  _spendCapsConfigured() {
480
497
  const s = this._spend;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent402-client",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
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",