@blockrun/clawrouter 0.12.25 → 0.12.27

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/dist/index.js CHANGED
@@ -1637,6 +1637,9 @@ var blockrunProvider = {
1637
1637
  // src/proxy.ts
1638
1638
  import { createServer } from "http";
1639
1639
  import { finished } from "stream";
1640
+ import { homedir as homedir4 } from "os";
1641
+ import { join as join5 } from "path";
1642
+ import { mkdir as mkdir3, writeFile as writeFile2, readFile, stat as fsStat } from "fs/promises";
1640
1643
  import { createPublicClient as createPublicClient2, http as http2 } from "viem";
1641
1644
  import { base as base2 } from "viem/chains";
1642
1645
  import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
@@ -5475,6 +5478,7 @@ ${lines.join("\n")}`;
5475
5478
  // src/proxy.ts
5476
5479
  var BLOCKRUN_API = "https://blockrun.ai/api";
5477
5480
  var BLOCKRUN_SOLANA_API = "https://sol.blockrun.ai/api";
5481
+ var IMAGE_DIR = join5(homedir4(), ".openclaw", "blockrun", "images");
5478
5482
  var AUTO_MODEL = "blockrun/auto";
5479
5483
  var ROUTING_PROFILES = /* @__PURE__ */ new Set([
5480
5484
  "blockrun/free",
@@ -5574,6 +5578,58 @@ function transformPaymentError(errorBody) {
5574
5578
  }
5575
5579
  }
5576
5580
  }
5581
+ if (parsed.error === "Payment verification failed" && parsed.code === "PAYMENT_INVALID" && parsed.debug) {
5582
+ const debugLower = parsed.debug.toLowerCase();
5583
+ const wallet = parsed.payer || "unknown";
5584
+ const shortWallet = wallet.length > 12 ? `${wallet.slice(0, 6)}...${wallet.slice(-4)}` : wallet;
5585
+ if (debugLower.includes("insufficient")) {
5586
+ return JSON.stringify({
5587
+ error: {
5588
+ message: "Insufficient Solana USDC balance.",
5589
+ type: "insufficient_funds",
5590
+ wallet,
5591
+ help: `Fund wallet ${shortWallet} with USDC on Solana, or switch to Base: /wallet base`
5592
+ }
5593
+ });
5594
+ }
5595
+ if (debugLower.includes("transaction_simulation_failed") || debugLower.includes("simulation")) {
5596
+ console.error(`[ClawRouter] Solana transaction simulation failed: ${parsed.debug}`);
5597
+ return JSON.stringify({
5598
+ error: {
5599
+ message: "Solana payment simulation failed. Retrying with a different model.",
5600
+ type: "transaction_simulation_failed",
5601
+ help: "This is usually temporary. If it persists, try: /model free"
5602
+ }
5603
+ });
5604
+ }
5605
+ if (debugLower.includes("invalid signature") || debugLower.includes("invalid_signature")) {
5606
+ return JSON.stringify({
5607
+ error: {
5608
+ message: "Solana payment signature invalid.",
5609
+ type: "invalid_payload",
5610
+ help: "Try again. If this persists, reinstall ClawRouter: curl -fsSL https://blockrun.ai/ClawRouter-update | bash"
5611
+ }
5612
+ });
5613
+ }
5614
+ if (debugLower.includes("expired")) {
5615
+ return JSON.stringify({
5616
+ error: {
5617
+ message: "Solana payment expired. Retrying.",
5618
+ type: "expired",
5619
+ help: "This is usually temporary."
5620
+ }
5621
+ });
5622
+ }
5623
+ console.error(`[ClawRouter] Solana payment verification failed: ${parsed.debug} payer=${wallet}`);
5624
+ return JSON.stringify({
5625
+ error: {
5626
+ message: `Solana payment verification failed: ${parsed.debug}`,
5627
+ type: "payment_invalid",
5628
+ wallet,
5629
+ help: "Try again or switch to Base: /wallet base"
5630
+ }
5631
+ });
5632
+ }
5577
5633
  if (parsed.error === "Settlement failed" || parsed.error === "Payment settlement failed" || parsed.details?.includes("Settlement failed") || parsed.details?.includes("transaction_simulation_failed")) {
5578
5634
  const details = parsed.details || "";
5579
5635
  const gasError = details.includes("unable to estimate gas");
@@ -6256,6 +6312,81 @@ async function startProxy(options) {
6256
6312
  res.end(JSON.stringify({ object: "list", data: models }));
6257
6313
  return;
6258
6314
  }
6315
+ if (req.url?.startsWith("/images/") && req.method === "GET") {
6316
+ const filename = req.url.slice("/images/".length).split("?")[0].replace(/[^a-zA-Z0-9._-]/g, "");
6317
+ if (!filename) {
6318
+ res.writeHead(400);
6319
+ res.end("Bad request");
6320
+ return;
6321
+ }
6322
+ const filePath = join5(IMAGE_DIR, filename);
6323
+ try {
6324
+ const s = await fsStat(filePath);
6325
+ if (!s.isFile()) throw new Error("not a file");
6326
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "png";
6327
+ const mime = { png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", webp: "image/webp", gif: "image/gif" };
6328
+ const data = await readFile(filePath);
6329
+ res.writeHead(200, { "Content-Type": mime[ext] ?? "application/octet-stream", "Content-Length": data.length });
6330
+ res.end(data);
6331
+ } catch {
6332
+ res.writeHead(404, { "Content-Type": "application/json" });
6333
+ res.end(JSON.stringify({ error: "Image not found" }));
6334
+ }
6335
+ return;
6336
+ }
6337
+ if (req.url === "/v1/images/generations" && req.method === "POST") {
6338
+ const chunks = [];
6339
+ for await (const chunk of req) {
6340
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
6341
+ }
6342
+ const reqBody = Buffer.concat(chunks);
6343
+ try {
6344
+ const upstream = await payFetch(`${apiBase}/v1/images/generations`, {
6345
+ method: "POST",
6346
+ headers: { "content-type": "application/json", "user-agent": USER_AGENT },
6347
+ body: reqBody
6348
+ });
6349
+ const text = await upstream.text();
6350
+ if (!upstream.ok) {
6351
+ res.writeHead(upstream.status, { "Content-Type": "application/json" });
6352
+ res.end(text);
6353
+ return;
6354
+ }
6355
+ let result;
6356
+ try {
6357
+ result = JSON.parse(text);
6358
+ } catch {
6359
+ res.writeHead(200, { "Content-Type": "application/json" });
6360
+ res.end(text);
6361
+ return;
6362
+ }
6363
+ if (result.data?.length) {
6364
+ await mkdir3(IMAGE_DIR, { recursive: true });
6365
+ const port2 = server.address()?.port ?? 8402;
6366
+ for (const img of result.data) {
6367
+ const m = img.url?.match(/^data:(image\/\w+);base64,(.+)$/);
6368
+ if (m) {
6369
+ const [, mimeType, b64] = m;
6370
+ const ext = mimeType === "image/jpeg" ? "jpg" : mimeType.split("/")[1] ?? "png";
6371
+ const filename = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}.${ext}`;
6372
+ await writeFile2(join5(IMAGE_DIR, filename), Buffer.from(b64, "base64"));
6373
+ img.url = `http://localhost:${port2}/images/${filename}`;
6374
+ console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
6375
+ }
6376
+ }
6377
+ }
6378
+ res.writeHead(200, { "Content-Type": "application/json" });
6379
+ res.end(JSON.stringify(result));
6380
+ } catch (err) {
6381
+ const msg = err instanceof Error ? err.message : String(err);
6382
+ console.error(`[ClawRouter] Image generation error: ${msg}`);
6383
+ if (!res.headersSent) {
6384
+ res.writeHead(502, { "Content-Type": "application/json" });
6385
+ res.end(JSON.stringify({ error: "Image generation failed", details: msg }));
6386
+ }
6387
+ }
6388
+ return;
6389
+ }
6259
6390
  if (req.url?.match(/^\/v1\/(?:x|partner)\//)) {
6260
6391
  try {
6261
6392
  await proxyPartnerRequest(req, res, apiBase, payFetch);
@@ -7665,8 +7796,8 @@ import {
7665
7796
  copyFileSync,
7666
7797
  renameSync
7667
7798
  } from "fs";
7668
- import { homedir as homedir5 } from "os";
7669
- import { join as join6 } from "path";
7799
+ import { homedir as homedir6 } from "os";
7800
+ import { join as join7 } from "path";
7670
7801
  import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
7671
7802
 
7672
7803
  // src/partners/registry.ts
@@ -7770,8 +7901,8 @@ init_solana_balance();
7770
7901
  // src/spend-control.ts
7771
7902
  import * as fs from "fs";
7772
7903
  import * as path from "path";
7773
- import { homedir as homedir4 } from "os";
7774
- var WALLET_DIR2 = path.join(homedir4(), ".openclaw", "blockrun");
7904
+ import { homedir as homedir5 } from "os";
7905
+ var WALLET_DIR2 = path.join(homedir5(), ".openclaw", "blockrun");
7775
7906
  var HOUR_MS = 60 * 60 * 1e3;
7776
7907
  var DAY_MS = 24 * HOUR_MS;
7777
7908
  var FileSpendControlStorage = class {
@@ -8097,8 +8228,8 @@ function isGatewayMode() {
8097
8228
  return args.includes("gateway");
8098
8229
  }
8099
8230
  function injectModelsConfig(logger) {
8100
- const configDir = join6(homedir5(), ".openclaw");
8101
- const configPath = join6(configDir, "openclaw.json");
8231
+ const configDir = join7(homedir6(), ".openclaw");
8232
+ const configPath = join7(configDir, "openclaw.json");
8102
8233
  let config = {};
8103
8234
  let needsWrite = false;
8104
8235
  if (!existsSync2(configDir)) {
@@ -8259,7 +8390,7 @@ function injectModelsConfig(logger) {
8259
8390
  }
8260
8391
  }
8261
8392
  function injectAuthProfile(logger) {
8262
- const agentsDir = join6(homedir5(), ".openclaw", "agents");
8393
+ const agentsDir = join7(homedir6(), ".openclaw", "agents");
8263
8394
  if (!existsSync2(agentsDir)) {
8264
8395
  try {
8265
8396
  mkdirSync2(agentsDir, { recursive: true });
@@ -8276,8 +8407,8 @@ function injectAuthProfile(logger) {
8276
8407
  agents = ["main", ...agents];
8277
8408
  }
8278
8409
  for (const agentId of agents) {
8279
- const authDir = join6(agentsDir, agentId, "agent");
8280
- const authPath = join6(authDir, "auth-profiles.json");
8410
+ const authDir = join7(agentsDir, agentId, "agent");
8411
+ const authPath = join7(authDir, "auth-profiles.json");
8281
8412
  if (!existsSync2(authDir)) {
8282
8413
  try {
8283
8414
  mkdirSync2(authDir, { recursive: true });