@blockrun/clawrouter 0.9.2 → 0.9.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.
- package/README.md +28 -17
- package/dist/cli.js +25 -49
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -8
- package/dist/index.js +25 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -509,8 +509,8 @@ type ProxyOptions = {
|
|
|
509
509
|
*/
|
|
510
510
|
sessionConfig?: Partial<SessionConfig>;
|
|
511
511
|
/**
|
|
512
|
-
* Auto-compress large requests to
|
|
513
|
-
* When enabled, requests
|
|
512
|
+
* Auto-compress large requests to reduce network usage.
|
|
513
|
+
* When enabled, requests are automatically compressed using
|
|
514
514
|
* LLM-safe context compression (15-40% reduction).
|
|
515
515
|
* Default: true
|
|
516
516
|
*/
|
|
@@ -521,11 +521,6 @@ type ProxyOptions = {
|
|
|
521
521
|
* Set to 0 to compress all requests.
|
|
522
522
|
*/
|
|
523
523
|
compressionThresholdKB?: number;
|
|
524
|
-
/**
|
|
525
|
-
* Maximum request size in KB after compression (default: 200).
|
|
526
|
-
* Hard limit enforced by BlockRun API.
|
|
527
|
-
*/
|
|
528
|
-
maxRequestSizeKB?: number;
|
|
529
524
|
onReady?: (port: number) => void;
|
|
530
525
|
onError?: (error: Error) => void;
|
|
531
526
|
onPayment?: (info: {
|
|
@@ -678,7 +673,8 @@ declare class RequestDeduplicator {
|
|
|
678
673
|
markInflight(key: string): void;
|
|
679
674
|
/** Complete an in-flight request — cache result and notify waiters. */
|
|
680
675
|
complete(key: string, result: CachedResponse): void;
|
|
681
|
-
/** Remove an in-flight entry on error (don't cache failures).
|
|
676
|
+
/** Remove an in-flight entry on error (don't cache failures).
|
|
677
|
+
* Also rejects any waiters so they can retry independently. */
|
|
682
678
|
removeInflight(key: string): void;
|
|
683
679
|
/** Prune expired completed entries. */
|
|
684
680
|
private prune;
|
package/dist/index.js
CHANGED
|
@@ -2082,26 +2082,14 @@ var RequestDeduplicator = class {
|
|
|
2082
2082
|
getInflight(key) {
|
|
2083
2083
|
const entry = this.inflight.get(key);
|
|
2084
2084
|
if (!entry) return void 0;
|
|
2085
|
-
|
|
2086
|
-
entry.
|
|
2087
|
-
new Promise((r) => {
|
|
2088
|
-
const orig = entry.resolve;
|
|
2089
|
-
entry.resolve = (result) => {
|
|
2090
|
-
orig(result);
|
|
2091
|
-
resolve(result);
|
|
2092
|
-
r(result);
|
|
2093
|
-
};
|
|
2094
|
-
})
|
|
2095
|
-
);
|
|
2085
|
+
return new Promise((resolve) => {
|
|
2086
|
+
entry.resolvers.push(resolve);
|
|
2096
2087
|
});
|
|
2097
|
-
return promise;
|
|
2098
2088
|
}
|
|
2099
2089
|
/** Mark a request as in-flight. */
|
|
2100
2090
|
markInflight(key) {
|
|
2101
2091
|
this.inflight.set(key, {
|
|
2102
|
-
|
|
2103
|
-
},
|
|
2104
|
-
waiters: []
|
|
2092
|
+
resolvers: []
|
|
2105
2093
|
});
|
|
2106
2094
|
}
|
|
2107
2095
|
/** Complete an in-flight request — cache result and notify waiters. */
|
|
@@ -2111,14 +2099,31 @@ var RequestDeduplicator = class {
|
|
|
2111
2099
|
}
|
|
2112
2100
|
const entry = this.inflight.get(key);
|
|
2113
2101
|
if (entry) {
|
|
2114
|
-
entry.
|
|
2102
|
+
for (const resolve of entry.resolvers) {
|
|
2103
|
+
resolve(result);
|
|
2104
|
+
}
|
|
2115
2105
|
this.inflight.delete(key);
|
|
2116
2106
|
}
|
|
2117
2107
|
this.prune();
|
|
2118
2108
|
}
|
|
2119
|
-
/** Remove an in-flight entry on error (don't cache failures).
|
|
2109
|
+
/** Remove an in-flight entry on error (don't cache failures).
|
|
2110
|
+
* Also rejects any waiters so they can retry independently. */
|
|
2120
2111
|
removeInflight(key) {
|
|
2121
|
-
this.inflight.
|
|
2112
|
+
const entry = this.inflight.get(key);
|
|
2113
|
+
if (entry) {
|
|
2114
|
+
const errorBody = Buffer.from(JSON.stringify({
|
|
2115
|
+
error: { message: "Original request failed, please retry", type: "dedup_origin_failed" }
|
|
2116
|
+
}));
|
|
2117
|
+
for (const resolve of entry.resolvers) {
|
|
2118
|
+
resolve({
|
|
2119
|
+
status: 503,
|
|
2120
|
+
headers: { "content-type": "application/json" },
|
|
2121
|
+
body: errorBody,
|
|
2122
|
+
completedAt: Date.now()
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
this.inflight.delete(key);
|
|
2126
|
+
}
|
|
2122
2127
|
}
|
|
2123
2128
|
/** Prune expired completed entries. */
|
|
2124
2129
|
prune() {
|
|
@@ -3391,6 +3396,8 @@ var FALLBACK_STATUS_CODES = [
|
|
|
3391
3396
|
// Payment required - but from upstream, not x402
|
|
3392
3397
|
403,
|
|
3393
3398
|
// Forbidden - provider restrictions
|
|
3399
|
+
413,
|
|
3400
|
+
// Payload too large - request exceeds model's context limit
|
|
3394
3401
|
429,
|
|
3395
3402
|
// Rate limited
|
|
3396
3403
|
500,
|
|
@@ -4024,7 +4031,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4024
4031
|
}
|
|
4025
4032
|
const autoCompress = options.autoCompressRequests ?? true;
|
|
4026
4033
|
const compressionThreshold = options.compressionThresholdKB ?? 180;
|
|
4027
|
-
const sizeLimit = options.maxRequestSizeKB ?? 200;
|
|
4028
4034
|
const requestSizeKB = Math.ceil(body.length / 1024);
|
|
4029
4035
|
if (autoCompress && requestSizeKB > compressionThreshold) {
|
|
4030
4036
|
try {
|
|
@@ -4066,21 +4072,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4066
4072
|
);
|
|
4067
4073
|
parsed.messages = compressionResult.messages;
|
|
4068
4074
|
body = Buffer.from(JSON.stringify(parsed));
|
|
4069
|
-
if (compressedSizeKB > sizeLimit) {
|
|
4070
|
-
const errorMsg = {
|
|
4071
|
-
error: {
|
|
4072
|
-
message: `Request size ${compressedSizeKB}KB still exceeds limit after compression (original: ${requestSizeKB}KB). Please reduce context size.`,
|
|
4073
|
-
type: "request_too_large",
|
|
4074
|
-
original_size_kb: requestSizeKB,
|
|
4075
|
-
compressed_size_kb: compressedSizeKB,
|
|
4076
|
-
limit_kb: sizeLimit,
|
|
4077
|
-
help: "Try: 1) Remove old messages from history, 2) Summarize large tool results, 3) Use direct API for very large contexts"
|
|
4078
|
-
}
|
|
4079
|
-
};
|
|
4080
|
-
res.writeHead(413, { "Content-Type": "application/json" });
|
|
4081
|
-
res.end(JSON.stringify(errorMsg));
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
4075
|
}
|
|
4085
4076
|
} catch (err) {
|
|
4086
4077
|
console.warn(
|
|
@@ -4088,21 +4079,6 @@ async function proxyRequest(req, res, apiBase, payFetch, options, routerOpts, de
|
|
|
4088
4079
|
);
|
|
4089
4080
|
}
|
|
4090
4081
|
}
|
|
4091
|
-
const finalSizeKB = Math.ceil(body.length / 1024);
|
|
4092
|
-
if (finalSizeKB > sizeLimit) {
|
|
4093
|
-
const errorMsg = {
|
|
4094
|
-
error: {
|
|
4095
|
-
message: `Request size ${finalSizeKB}KB exceeds limit ${sizeLimit}KB. Please reduce context size.`,
|
|
4096
|
-
type: "request_too_large",
|
|
4097
|
-
size_kb: finalSizeKB,
|
|
4098
|
-
limit_kb: sizeLimit,
|
|
4099
|
-
help: "Try: 1) Remove old messages from history, 2) Summarize large tool results, 3) Enable compression (autoCompressRequests: true)"
|
|
4100
|
-
}
|
|
4101
|
-
};
|
|
4102
|
-
res.writeHead(413, { "Content-Type": "application/json" });
|
|
4103
|
-
res.end(JSON.stringify(errorMsg));
|
|
4104
|
-
return;
|
|
4105
|
-
}
|
|
4106
4082
|
const dedupKey = RequestDeduplicator.hash(body);
|
|
4107
4083
|
const cached = deduplicator.getCached(dedupKey);
|
|
4108
4084
|
if (cached) {
|