@blockrun/clawrouter 0.12.254 → 0.12.256

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/dist/cli.js +39 -12
  2. package/dist/index.js +39 -12
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -39252,6 +39252,26 @@ var init_stats = __esm({
39252
39252
  }
39253
39253
  });
39254
39254
 
39255
+ // src/timestamp-strip.ts
39256
+ function stripLeadingTextBlockTimestamp(blocks) {
39257
+ let stripped = false;
39258
+ return blocks.map((block) => {
39259
+ if (!stripped && block !== null && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
39260
+ stripped = true;
39261
+ const b = block;
39262
+ return { ...b, text: b.text.replace(TIMESTAMP_PATTERN, "") };
39263
+ }
39264
+ return block;
39265
+ });
39266
+ }
39267
+ var TIMESTAMP_PATTERN;
39268
+ var init_timestamp_strip = __esm({
39269
+ "src/timestamp-strip.ts"() {
39270
+ "use strict";
39271
+ TIMESTAMP_PATTERN = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39272
+ }
39273
+ });
39274
+
39255
39275
  // src/dedup.ts
39256
39276
  import { createHash } from "crypto";
39257
39277
  function canonicalize(obj) {
@@ -39278,19 +39298,21 @@ function stripTimestamps(obj) {
39278
39298
  for (const [key2, value] of Object.entries(obj)) {
39279
39299
  if (key2 === "content" && typeof value === "string") {
39280
39300
  result[key2] = value.replace(TIMESTAMP_PATTERN, "");
39301
+ } else if (key2 === "content" && Array.isArray(value)) {
39302
+ result[key2] = stripLeadingTextBlockTimestamp(value.map(stripTimestamps));
39281
39303
  } else {
39282
39304
  result[key2] = stripTimestamps(value);
39283
39305
  }
39284
39306
  }
39285
39307
  return result;
39286
39308
  }
39287
- var DEFAULT_TTL_MS2, MAX_BODY_SIZE, TIMESTAMP_PATTERN, RequestDeduplicator;
39309
+ var DEFAULT_TTL_MS2, MAX_BODY_SIZE, RequestDeduplicator;
39288
39310
  var init_dedup = __esm({
39289
39311
  "src/dedup.ts"() {
39290
39312
  "use strict";
39313
+ init_timestamp_strip();
39291
39314
  DEFAULT_TTL_MS2 = 3e4;
39292
39315
  MAX_BODY_SIZE = 1048576;
39293
- TIMESTAMP_PATTERN = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39294
39316
  RequestDeduplicator = class {
39295
39317
  inflight = /* @__PURE__ */ new Map();
39296
39318
  completed = /* @__PURE__ */ new Map();
@@ -39408,7 +39430,10 @@ function normalizeForCache(obj) {
39408
39430
  if (typeof msg === "object" && msg !== null) {
39409
39431
  const m = msg;
39410
39432
  if (typeof m.content === "string") {
39411
- return { ...m, content: m.content.replace(TIMESTAMP_PATTERN2, "") };
39433
+ return { ...m, content: m.content.replace(TIMESTAMP_PATTERN, "") };
39434
+ }
39435
+ if (Array.isArray(m.content)) {
39436
+ return { ...m, content: stripLeadingTextBlockTimestamp(m.content) };
39412
39437
  }
39413
39438
  }
39414
39439
  return msg;
@@ -39419,10 +39444,11 @@ function normalizeForCache(obj) {
39419
39444
  }
39420
39445
  return result;
39421
39446
  }
39422
- var DEFAULT_CONFIG, TIMESTAMP_PATTERN2, ResponseCache;
39447
+ var DEFAULT_CONFIG, ResponseCache;
39423
39448
  var init_response_cache = __esm({
39424
39449
  "src/response-cache.ts"() {
39425
39450
  "use strict";
39451
+ init_timestamp_strip();
39426
39452
  DEFAULT_CONFIG = {
39427
39453
  maxSize: 200,
39428
39454
  defaultTTL: 600,
@@ -39430,7 +39456,6 @@ var init_response_cache = __esm({
39430
39456
  // 1MB
39431
39457
  enabled: true
39432
39458
  };
39433
- TIMESTAMP_PATTERN2 = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39434
39459
  ResponseCache = class {
39435
39460
  cache = /* @__PURE__ */ new Map();
39436
39461
  expirationHeap = [];
@@ -90441,7 +90466,7 @@ async function startProxy(options) {
90441
90466
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90442
90467
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
90443
90468
  try {
90444
- const imgResp = await fetch(img.url);
90469
+ const imgResp = await fetch(img.url, { signal: clientAbort.signal });
90445
90470
  if (imgResp.ok) {
90446
90471
  const contentType = imgResp.headers.get("content-type") ?? "image/png";
90447
90472
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
@@ -90523,6 +90548,7 @@ async function startProxy(options) {
90523
90548
  img2imgCost = estimateImageCost(img2imgModel, parsed.size, parsed.n || 1);
90524
90549
  reqBody = JSON.stringify(parsed);
90525
90550
  } catch (parseErr) {
90551
+ if (clientAbort.signal.aborted) return;
90526
90552
  const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
90527
90553
  res.writeHead(400, { "Content-Type": "application/json" });
90528
90554
  res.end(JSON.stringify({ error: "Invalid request", details: msg }));
@@ -90563,7 +90589,7 @@ async function startProxy(options) {
90563
90589
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90564
90590
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
90565
90591
  try {
90566
- const imgResp = await fetch(img.url);
90592
+ const imgResp = await fetch(img.url, { signal: clientAbort.signal });
90567
90593
  if (imgResp.ok) {
90568
90594
  const contentType = imgResp.headers.get("content-type") ?? "image/png";
90569
90595
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
@@ -90809,7 +90835,7 @@ async function startProxy(options) {
90809
90835
  for (const clip of finalResult.data) {
90810
90836
  if (clip.url?.startsWith("https://") || clip.url?.startsWith("http://")) {
90811
90837
  try {
90812
- const videoResp = await fetch(clip.url);
90838
+ const videoResp = await fetch(clip.url, { signal: clientAbort.signal });
90813
90839
  if (videoResp.ok) {
90814
90840
  const contentType = videoResp.headers.get("content-type") ?? "video/mp4";
90815
90841
  const ext = contentType.includes("webm") ? "webm" : contentType.includes("quicktime") ? "mov" : "mp4";
@@ -91428,6 +91454,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91428
91454
  console.log(
91429
91455
  `[ClawRouter] /imagegen command \u2192 ${imageModel} (${imageSize}): ${imagePrompt.slice(0, 80)}...`
91430
91456
  );
91457
+ const imagegenAbort = new AbortController();
91458
+ res.on("close", () => {
91459
+ if (!res.writableEnded) imagegenAbort.abort();
91460
+ });
91431
91461
  try {
91432
91462
  const imageUpstreamUrl = `${apiBase}/v1/images/generations`;
91433
91463
  const imageBody = JSON.stringify({
@@ -91436,10 +91466,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91436
91466
  size: imageSize,
91437
91467
  n: 1
91438
91468
  });
91439
- const imagegenAbort = new AbortController();
91440
- res.on("close", () => {
91441
- if (!res.writableEnded) imagegenAbort.abort();
91442
- });
91443
91469
  const imageResponse = await payFetch(imageUpstreamUrl, {
91444
91470
  method: "POST",
91445
91471
  headers: { "content-type": "application/json", "user-agent": USER_AGENT },
@@ -91581,6 +91607,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91581
91607
  );
91582
91608
  }
91583
91609
  } catch (err) {
91610
+ if (imagegenAbort.signal.aborted) return;
91584
91611
  const errMsg = err instanceof Error ? err.message : String(err);
91585
91612
  console.error(`[ClawRouter] /imagegen error: ${errMsg}`);
91586
91613
  if (!res.headersSent) {
package/dist/index.js CHANGED
@@ -39121,6 +39121,26 @@ var init_stats = __esm({
39121
39121
  }
39122
39122
  });
39123
39123
 
39124
+ // src/timestamp-strip.ts
39125
+ function stripLeadingTextBlockTimestamp(blocks) {
39126
+ let stripped = false;
39127
+ return blocks.map((block) => {
39128
+ if (!stripped && block !== null && typeof block === "object" && block.type === "text" && typeof block.text === "string") {
39129
+ stripped = true;
39130
+ const b = block;
39131
+ return { ...b, text: b.text.replace(TIMESTAMP_PATTERN, "") };
39132
+ }
39133
+ return block;
39134
+ });
39135
+ }
39136
+ var TIMESTAMP_PATTERN;
39137
+ var init_timestamp_strip = __esm({
39138
+ "src/timestamp-strip.ts"() {
39139
+ "use strict";
39140
+ TIMESTAMP_PATTERN = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39141
+ }
39142
+ });
39143
+
39124
39144
  // src/dedup.ts
39125
39145
  import { createHash } from "crypto";
39126
39146
  function canonicalize(obj) {
@@ -39147,19 +39167,21 @@ function stripTimestamps(obj) {
39147
39167
  for (const [key2, value] of Object.entries(obj)) {
39148
39168
  if (key2 === "content" && typeof value === "string") {
39149
39169
  result[key2] = value.replace(TIMESTAMP_PATTERN, "");
39170
+ } else if (key2 === "content" && Array.isArray(value)) {
39171
+ result[key2] = stripLeadingTextBlockTimestamp(value.map(stripTimestamps));
39150
39172
  } else {
39151
39173
  result[key2] = stripTimestamps(value);
39152
39174
  }
39153
39175
  }
39154
39176
  return result;
39155
39177
  }
39156
- var DEFAULT_TTL_MS2, MAX_BODY_SIZE, TIMESTAMP_PATTERN, RequestDeduplicator;
39178
+ var DEFAULT_TTL_MS2, MAX_BODY_SIZE, RequestDeduplicator;
39157
39179
  var init_dedup = __esm({
39158
39180
  "src/dedup.ts"() {
39159
39181
  "use strict";
39182
+ init_timestamp_strip();
39160
39183
  DEFAULT_TTL_MS2 = 3e4;
39161
39184
  MAX_BODY_SIZE = 1048576;
39162
- TIMESTAMP_PATTERN = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39163
39185
  RequestDeduplicator = class {
39164
39186
  inflight = /* @__PURE__ */ new Map();
39165
39187
  completed = /* @__PURE__ */ new Map();
@@ -39277,7 +39299,10 @@ function normalizeForCache(obj) {
39277
39299
  if (typeof msg === "object" && msg !== null) {
39278
39300
  const m = msg;
39279
39301
  if (typeof m.content === "string") {
39280
- return { ...m, content: m.content.replace(TIMESTAMP_PATTERN2, "") };
39302
+ return { ...m, content: m.content.replace(TIMESTAMP_PATTERN, "") };
39303
+ }
39304
+ if (Array.isArray(m.content)) {
39305
+ return { ...m, content: stripLeadingTextBlockTimestamp(m.content) };
39281
39306
  }
39282
39307
  }
39283
39308
  return msg;
@@ -39288,10 +39313,11 @@ function normalizeForCache(obj) {
39288
39313
  }
39289
39314
  return result;
39290
39315
  }
39291
- var DEFAULT_CONFIG, TIMESTAMP_PATTERN2, ResponseCache;
39316
+ var DEFAULT_CONFIG, ResponseCache;
39292
39317
  var init_response_cache = __esm({
39293
39318
  "src/response-cache.ts"() {
39294
39319
  "use strict";
39320
+ init_timestamp_strip();
39295
39321
  DEFAULT_CONFIG = {
39296
39322
  maxSize: 200,
39297
39323
  defaultTTL: 600,
@@ -39299,7 +39325,6 @@ var init_response_cache = __esm({
39299
39325
  // 1MB
39300
39326
  enabled: true
39301
39327
  };
39302
- TIMESTAMP_PATTERN2 = /^\[\w{3}\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+\w+\]\s*/;
39303
39328
  ResponseCache = class {
39304
39329
  cache = /* @__PURE__ */ new Map();
39305
39330
  expirationHeap = [];
@@ -90261,7 +90286,7 @@ async function startProxy(options) {
90261
90286
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90262
90287
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
90263
90288
  try {
90264
- const imgResp = await fetch(img.url);
90289
+ const imgResp = await fetch(img.url, { signal: clientAbort.signal });
90265
90290
  if (imgResp.ok) {
90266
90291
  const contentType = imgResp.headers.get("content-type") ?? "image/png";
90267
90292
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
@@ -90343,6 +90368,7 @@ async function startProxy(options) {
90343
90368
  img2imgCost = estimateImageCost(img2imgModel, parsed.size, parsed.n || 1);
90344
90369
  reqBody = JSON.stringify(parsed);
90345
90370
  } catch (parseErr) {
90371
+ if (clientAbort.signal.aborted) return;
90346
90372
  const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
90347
90373
  res.writeHead(400, { "Content-Type": "application/json" });
90348
90374
  res.end(JSON.stringify({ error: "Invalid request", details: msg }));
@@ -90383,7 +90409,7 @@ async function startProxy(options) {
90383
90409
  console.log(`[ClawRouter] Image saved \u2192 ${img.url}`);
90384
90410
  } else if (img.url?.startsWith("https://") || img.url?.startsWith("http://")) {
90385
90411
  try {
90386
- const imgResp = await fetch(img.url);
90412
+ const imgResp = await fetch(img.url, { signal: clientAbort.signal });
90387
90413
  if (imgResp.ok) {
90388
90414
  const contentType = imgResp.headers.get("content-type") ?? "image/png";
90389
90415
  const ext = contentType.includes("jpeg") || contentType.includes("jpg") ? "jpg" : contentType.includes("webp") ? "webp" : "png";
@@ -90629,7 +90655,7 @@ async function startProxy(options) {
90629
90655
  for (const clip of finalResult.data) {
90630
90656
  if (clip.url?.startsWith("https://") || clip.url?.startsWith("http://")) {
90631
90657
  try {
90632
- const videoResp = await fetch(clip.url);
90658
+ const videoResp = await fetch(clip.url, { signal: clientAbort.signal });
90633
90659
  if (videoResp.ok) {
90634
90660
  const contentType = videoResp.headers.get("content-type") ?? "video/mp4";
90635
90661
  const ext = contentType.includes("webm") ? "webm" : contentType.includes("quicktime") ? "mov" : "mp4";
@@ -91248,6 +91274,10 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91248
91274
  console.log(
91249
91275
  `[ClawRouter] /imagegen command \u2192 ${imageModel} (${imageSize}): ${imagePrompt.slice(0, 80)}...`
91250
91276
  );
91277
+ const imagegenAbort = new AbortController();
91278
+ res.on("close", () => {
91279
+ if (!res.writableEnded) imagegenAbort.abort();
91280
+ });
91251
91281
  try {
91252
91282
  const imageUpstreamUrl = `${apiBase}/v1/images/generations`;
91253
91283
  const imageBody = JSON.stringify({
@@ -91256,10 +91286,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91256
91286
  size: imageSize,
91257
91287
  n: 1
91258
91288
  });
91259
- const imagegenAbort = new AbortController();
91260
- res.on("close", () => {
91261
- if (!res.writableEnded) imagegenAbort.abort();
91262
- });
91263
91289
  const imageResponse = await payFetch(imageUpstreamUrl, {
91264
91290
  method: "POST",
91265
91291
  headers: { "content-type": "application/json", "user-agent": USER_AGENT },
@@ -91401,6 +91427,7 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
91401
91427
  );
91402
91428
  }
91403
91429
  } catch (err) {
91430
+ if (imagegenAbort.signal.aborted) return;
91404
91431
  const errMsg = err instanceof Error ? err.message : String(err);
91405
91432
  console.error(`[ClawRouter] /imagegen error: ${errMsg}`);
91406
91433
  if (!res.headersSent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/clawrouter",
3
- "version": "0.12.254",
3
+ "version": "0.12.256",
4
4
  "description": "Smart LLM router — save 88% on inference costs. 71 models (5 free), one wallet, x402 micropayments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",