@blockrun/clawrouter 0.12.11 → 0.12.13

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/cli.js CHANGED
@@ -48,7 +48,7 @@ function createPayFetchWithPreAuth(baseFetch, client, ttlMs = DEFAULT_TTL_MS, op
48
48
  const responseText = await Promise.race([
49
49
  response.text(),
50
50
  new Promise(
51
- (_, reject) => setTimeout(() => reject(new Error("Body read timeout")), 6e4)
51
+ (_, reject) => setTimeout(() => reject(new Error("Body read timeout")), 3e4)
52
52
  )
53
53
  ]);
54
54
  if (responseText) body = JSON.parse(responseText);
@@ -4987,23 +4987,27 @@ var HEALTH_CHECK_TIMEOUT_MS = 2e3;
4987
4987
  var RATE_LIMIT_COOLDOWN_MS = 6e4;
4988
4988
  var PORT_RETRY_ATTEMPTS = 5;
4989
4989
  var PORT_RETRY_DELAY_MS = 1e3;
4990
- var BODY_READ_TIMEOUT_MS = 6e4;
4991
- async function readBodyWithTimeout(body, timeoutMs = BODY_READ_TIMEOUT_MS) {
4990
+ var MODEL_BODY_READ_TIMEOUT_MS = 3e5;
4991
+ var ERROR_BODY_READ_TIMEOUT_MS = 3e4;
4992
+ async function readBodyWithTimeout(body, timeoutMs = MODEL_BODY_READ_TIMEOUT_MS) {
4992
4993
  if (!body) return [];
4993
4994
  const reader = body.getReader();
4994
4995
  const chunks = [];
4996
+ let timer;
4995
4997
  try {
4996
4998
  while (true) {
4997
4999
  const result = await Promise.race([
4998
5000
  reader.read(),
4999
- new Promise(
5000
- (_, reject) => setTimeout(() => reject(new Error("Body read timeout")), timeoutMs)
5001
- )
5001
+ new Promise((_, reject) => {
5002
+ timer = setTimeout(() => reject(new Error("Body read timeout")), timeoutMs);
5003
+ })
5002
5004
  ]);
5005
+ clearTimeout(timer);
5003
5006
  if (result.done) break;
5004
5007
  chunks.push(result.value);
5005
5008
  }
5006
5009
  } finally {
5010
+ clearTimeout(timer);
5007
5011
  reader.releaseLock();
5008
5012
  }
5009
5013
  return chunks;
@@ -5108,6 +5112,8 @@ function canWrite(res) {
5108
5112
  }
5109
5113
  function safeWrite(res, data) {
5110
5114
  if (!canWrite(res)) {
5115
+ const bytes = typeof data === "string" ? Buffer.byteLength(data) : data.length;
5116
+ console.warn(`[ClawRouter] safeWrite: socket not writable, dropping ${bytes} bytes`);
5111
5117
  return false;
5112
5118
  }
5113
5119
  return res.write(data);
@@ -5507,7 +5513,7 @@ async function proxyPartnerRequest(req, res, apiBase, payFetch) {
5507
5513
  });
5508
5514
  res.writeHead(upstream.status, responseHeaders);
5509
5515
  if (upstream.body) {
5510
- const chunks = await readBodyWithTimeout(upstream.body);
5516
+ const chunks = await readBodyWithTimeout(upstream.body, ERROR_BODY_READ_TIMEOUT_MS);
5511
5517
  for (const chunk of chunks) {
5512
5518
  safeWrite(res, Buffer.from(chunk));
5513
5519
  }
@@ -5957,7 +5963,7 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
5957
5963
  signal
5958
5964
  });
5959
5965
  if (response.status !== 200) {
5960
- const errorBodyChunks = await readBodyWithTimeout(response.body);
5966
+ const errorBodyChunks = await readBodyWithTimeout(response.body, ERROR_BODY_READ_TIMEOUT_MS);
5961
5967
  const errorBody = Buffer.concat(errorBodyChunks).toString();
5962
5968
  const isProviderErr = isProviderError(response.status, errorBody);
5963
5969
  return {
@@ -5970,7 +5976,7 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
5970
5976
  const contentType = response.headers.get("content-type") || "";
5971
5977
  if (contentType.includes("json") || contentType.includes("text")) {
5972
5978
  try {
5973
- const clonedChunks = await readBodyWithTimeout(response.clone().body);
5979
+ const clonedChunks = await readBodyWithTimeout(response.clone().body, ERROR_BODY_READ_TIMEOUT_MS);
5974
5980
  const responseBody = Buffer.concat(clonedChunks).toString();
5975
5981
  const degradedReason = detectDegradedSuccessResponse(responseBody);
5976
5982
  if (degradedReason) {
@@ -6771,6 +6777,20 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
6771
6777
  if (result.isProviderError && !isLastAttempt) {
6772
6778
  if (result.errorStatus === 429) {
6773
6779
  markRateLimited(tryModel);
6780
+ try {
6781
+ const parsed = JSON.parse(result.errorBody || "{}");
6782
+ if (parsed.update_available) {
6783
+ console.log("");
6784
+ console.log(
6785
+ `\x1B[33m\u2B06\uFE0F ClawRouter ${parsed.update_available} available (you have ${VERSION})\x1B[0m`
6786
+ );
6787
+ console.log(
6788
+ ` Run: \x1B[36mcurl -fsSL ${parsed.update_url || "https://blockrun.ai/ClawRouter-update"} | bash\x1B[0m`
6789
+ );
6790
+ console.log("");
6791
+ }
6792
+ } catch {
6793
+ }
6774
6794
  }
6775
6795
  const isPaymentErr = /payment.*verification.*failed|payment.*settlement.*failed|insufficient.*funds|transaction_simulation_failed/i.test(
6776
6796
  result.errorBody || ""