@blockrun/clawrouter 0.12.64 → 0.12.65

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
@@ -42464,7 +42464,19 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
42464
42464
  return async (input, init) => {
42465
42465
  const request = new Request(input, init);
42466
42466
  const urlPath = new URL(request.url).pathname;
42467
- const cached = !options?.skipPreAuth ? cache2.get(urlPath) : void 0;
42467
+ let requestModel = "";
42468
+ if (init?.body) {
42469
+ try {
42470
+ const bodyStr = init.body instanceof Uint8Array ? new TextDecoder().decode(init.body) : typeof init.body === "string" ? init.body : "";
42471
+ if (bodyStr) {
42472
+ const parsed = JSON.parse(bodyStr);
42473
+ requestModel = parsed.model ?? "";
42474
+ }
42475
+ } catch {
42476
+ }
42477
+ }
42478
+ const cacheKey2 = `${urlPath}:${requestModel}`;
42479
+ const cached = !options?.skipPreAuth ? cache2.get(cacheKey2) : void 0;
42468
42480
  if (cached && Date.now() - cached.cachedAt < ttlMs) {
42469
42481
  try {
42470
42482
  const payload2 = await client.createPaymentPayload(cached.paymentRequired);
@@ -42477,9 +42489,9 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
42477
42489
  if (response2.status !== 402) {
42478
42490
  return response2;
42479
42491
  }
42480
- cache2.delete(urlPath);
42492
+ cache2.delete(cacheKey2);
42481
42493
  } catch {
42482
- cache2.delete(urlPath);
42494
+ cache2.delete(cacheKey2);
42483
42495
  }
42484
42496
  }
42485
42497
  const clonedRequest = request.clone();
@@ -42502,7 +42514,7 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
42502
42514
  } catch {
42503
42515
  }
42504
42516
  paymentRequired = httpClient.getPaymentRequiredResponse(getHeader, body);
42505
- cache2.set(urlPath, { paymentRequired, cachedAt: Date.now() });
42517
+ cache2.set(cacheKey2, { paymentRequired, cachedAt: Date.now() });
42506
42518
  } catch (error) {
42507
42519
  throw new Error(
42508
42520
  `Failed to parse payment requirements: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -46862,12 +46874,7 @@ async function checkForUpdates() {
46862
46874
  import { readFileSync, writeFileSync, mkdirSync } from "fs";
46863
46875
  import { join as join7, dirname as dirname2 } from "path";
46864
46876
  import { homedir as homedir4 } from "os";
46865
- var DEFAULT_FILE_PATH = join7(
46866
- homedir4(),
46867
- ".openclaw",
46868
- "blockrun",
46869
- "exclude-models.json"
46870
- );
46877
+ var DEFAULT_FILE_PATH = join7(homedir4(), ".openclaw", "blockrun", "exclude-models.json");
46871
46878
  function loadExcludeList(filePath = DEFAULT_FILE_PATH) {
46872
46879
  try {
46873
46880
  const raw = readFileSync(filePath, "utf-8");
@@ -47272,8 +47279,7 @@ function categorizeError(status, body) {
47272
47279
  if (status === 401) return "auth_failure";
47273
47280
  if (status === 402) return "payment_error";
47274
47281
  if (status === 403) {
47275
- if (/plan.*limit|quota.*exceeded|subscription|allowance/i.test(body))
47276
- return "quota_exceeded";
47282
+ if (/plan.*limit|quota.*exceeded|subscription|allowance/i.test(body)) return "quota_exceeded";
47277
47283
  return "auth_failure";
47278
47284
  }
47279
47285
  if (status === 429) return "rate_limited";
@@ -49560,6 +49566,7 @@ data: [DONE]
49560
49566
  let upstream;
49561
49567
  let lastError;
49562
49568
  let actualModelUsed = modelId;
49569
+ const failedAttempts = [];
49563
49570
  for (let i = 0; i < modelsToTry.length; i++) {
49564
49571
  const tryModel = modelsToTry[i];
49565
49572
  const isLastAttempt = i === modelsToTry.length - 1;
@@ -49608,6 +49615,11 @@ data: [DONE]
49608
49615
  body: result.errorBody || "Unknown error",
49609
49616
  status: result.errorStatus || 500
49610
49617
  };
49618
+ failedAttempts.push({
49619
+ model: tryModel,
49620
+ reason: result.errorCategory || `HTTP ${result.errorStatus || 500}`,
49621
+ status: result.errorStatus || 500
49622
+ });
49611
49623
  if (result.isProviderError && !isLastAttempt) {
49612
49624
  const isExplicitModelError = !routingDecision;
49613
49625
  const isUnknownExplicitModel = isExplicitModelError && /unknown.*model|invalid.*model/i.test(result.errorBody || "");
@@ -49745,7 +49757,10 @@ data: [DONE]
49745
49757
  }
49746
49758
  }
49747
49759
  if (!upstream) {
49748
- const rawErrBody = lastError?.body || "All models in fallback chain failed";
49760
+ const attemptSummary = failedAttempts.length > 0 ? failedAttempts.map((a) => `${a.model} (${a.reason})`).join(", ") : "unknown";
49761
+ const structuredMessage = failedAttempts.length > 0 ? `All ${failedAttempts.length} models failed. Tried: ${attemptSummary}` : "All models in fallback chain failed";
49762
+ console.log(`[ClawRouter] ${structuredMessage}`);
49763
+ const rawErrBody = lastError?.body || structuredMessage;
49749
49764
  const errStatus = lastError?.status || 502;
49750
49765
  const transformedErr = transformPaymentError(rawErrBody);
49751
49766
  if (headersSentEarly) {
@@ -49804,7 +49819,7 @@ data: [DONE]
49804
49819
  id: rsp.id ?? `chatcmpl-${Date.now()}`,
49805
49820
  object: "chat.completion.chunk",
49806
49821
  created: rsp.created ?? Math.floor(Date.now() / 1e3),
49807
- model: rsp.model ?? "unknown",
49822
+ model: actualModelUsed || rsp.model || "unknown",
49808
49823
  system_fingerprint: null
49809
49824
  };
49810
49825
  if (rsp.choices && Array.isArray(rsp.choices)) {
@@ -49919,6 +49934,13 @@ data: [DONE]
49919
49934
  responseChunks.push(Buffer.from(sseData));
49920
49935
  }
49921
49936
  }
49937
+ if (routingDecision) {
49938
+ const costComment = `: cost=$${routingDecision.costEstimate.toFixed(4)} savings=${(routingDecision.savings * 100).toFixed(0)}% model=${actualModelUsed} tier=${routingDecision.tier}
49939
+
49940
+ `;
49941
+ safeWrite(res, costComment);
49942
+ responseChunks.push(Buffer.from(costComment));
49943
+ }
49922
49944
  safeWrite(res, "data: [DONE]\n\n");
49923
49945
  responseChunks.push(Buffer.from("data: [DONE]\n\n"));
49924
49946
  res.end();
@@ -49947,6 +49969,10 @@ data: [DONE]
49947
49969
  responseHeaders["x-clawrouter-agentic-score"] = routingDecision.agenticScore.toFixed(2);
49948
49970
  }
49949
49971
  }
49972
+ if (routingDecision) {
49973
+ responseHeaders["x-clawrouter-cost"] = routingDecision.costEstimate.toFixed(6);
49974
+ responseHeaders["x-clawrouter-savings"] = `${(routingDecision.savings * 100).toFixed(0)}%`;
49975
+ }
49950
49976
  const bodyParts = [];
49951
49977
  if (upstream.body) {
49952
49978
  const chunks = await readBodyWithTimeout(upstream.body);
@@ -49977,6 +50003,16 @@ data: [DONE]
49977
50003
  }
49978
50004
  budgetDowngradeNotice = void 0;
49979
50005
  }
50006
+ if (actualModelUsed && responseBody.length > 0) {
50007
+ try {
50008
+ const parsed = JSON.parse(responseBody.toString());
50009
+ if (parsed.model !== void 0) {
50010
+ parsed.model = actualModelUsed;
50011
+ responseBody = Buffer.from(JSON.stringify(parsed));
50012
+ }
50013
+ } catch {
50014
+ }
50015
+ }
49980
50016
  if (budgetDowngradeHeaderMode) {
49981
50017
  responseHeaders["x-clawrouter-budget-downgrade"] = "1";
49982
50018
  responseHeaders["x-clawrouter-budget-mode"] = budgetDowngradeHeaderMode;
@@ -50802,7 +50838,9 @@ async function startProxyInBackground(api) {
50802
50838
  activeProxyHandle = proxy;
50803
50839
  const startupExclusions = loadExcludeList();
50804
50840
  if (startupExclusions.size > 0) {
50805
- api.logger.info(`Model exclusions active (${startupExclusions.size}): ${[...startupExclusions].join(", ")}`);
50841
+ api.logger.info(
50842
+ `Model exclusions active (${startupExclusions.size}): ${[...startupExclusions].join(", ")}`
50843
+ );
50806
50844
  }
50807
50845
  api.logger.info(`ClawRouter ready \u2014 smart routing enabled`);
50808
50846
  api.logger.info(`Pricing: Simple ~$0.001 | Code ~$0.01 | Complex ~$0.05 | Free: $0`);
@@ -50891,7 +50929,10 @@ Use /exclude remove <model> to unblock.`
50891
50929
  }
50892
50930
  if (subcommand === "add") {
50893
50931
  if (!modelArg) {
50894
- return { text: "Usage: /exclude add <model>\nExample: /exclude add nvidia/gpt-oss-120b", isError: true };
50932
+ return {
50933
+ text: "Usage: /exclude add <model>\nExample: /exclude add nvidia/gpt-oss-120b",
50934
+ isError: true
50935
+ };
50895
50936
  }
50896
50937
  const resolved = addExclusion(modelArg);
50897
50938
  const list = loadExcludeList();