blun-king-cli 9.1.581 → 9.1.583
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/CHANGELOG.md +13 -0
- package/blun.mjs +43 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## 9.1.583 - 2026-09-08
|
|
2
|
+
|
|
3
|
+
- FetchURL now passes caller cancellation through the tool and both fetch providers to the HTTP request.
|
|
4
|
+
- An aborted managed fetch no longer starts a local fallback, and a late provider result cannot become source evidence after cancellation.
|
|
5
|
+
- Normal fetch failures still allow the existing fallback. No new timeout is introduced; Telegram routing and model requests are unchanged.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# 9.1.582 - 2026-09-08
|
|
9
|
+
|
|
10
|
+
- Stop oversized local page responses while reading their body, including responses without a reliable Content-Length header. Cancel the stream when received bytes exceed the existing ten MiB limit.
|
|
11
|
+
- Apply the limit to the delivered response stream after HTTP decompression and preserve UTF-8 characters split across chunks. Transport buffers and the crossing chunk may already exist; this is not an exact process-memory ceiling.
|
|
12
|
+
- Keep the research fixes from 9.1.581. Telegram delivery, incoming addressing and model timing logic are unchanged.
|
|
13
|
+
|
|
1
14
|
## 9.1.581
|
|
2
15
|
|
|
3
16
|
- Local HTML fetching now rejects extraction results that are empty after cleanup, instead of presenting a document title alone as page content.
|
package/blun.mjs
CHANGED
|
@@ -265663,9 +265663,11 @@ var init_fetch_url = __esmMin((() => {
|
|
|
265663
265663
|
execute: (ctx) => this.execution(args, ctx)
|
|
265664
265664
|
};
|
|
265665
265665
|
}
|
|
265666
|
-
async execution(args, { toolCallId }) {
|
|
265666
|
+
async execution(args, { toolCallId, signal }) {
|
|
265667
265667
|
try {
|
|
265668
|
-
|
|
265668
|
+
signal?.throwIfAborted();
|
|
265669
|
+
const { content, kind } = await this.fetcher.fetch(args.url, { toolCallId, signal });
|
|
265670
|
+
signal?.throwIfAborted();
|
|
265669
265671
|
return formatResearchPage({ ...args, content, kind });
|
|
265670
265672
|
} catch (error) {
|
|
265671
265673
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -315114,11 +315116,13 @@ var init_local_fetch_url = __esmMin((() => {
|
|
|
315114
315116
|
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
315115
315117
|
this.allowPrivateAddresses = options.allowPrivateAddresses ?? false;
|
|
315116
315118
|
}
|
|
315117
|
-
async fetch(url,
|
|
315119
|
+
async fetch(url, options) {
|
|
315120
|
+
options?.signal?.throwIfAborted();
|
|
315118
315121
|
assertSafeFetchTarget(url, this.allowPrivateAddresses);
|
|
315119
315122
|
const response = await this.fetchImpl(url, {
|
|
315120
315123
|
method: "GET",
|
|
315121
|
-
headers: { "User-Agent": this.userAgent }
|
|
315124
|
+
headers: { "User-Agent": this.userAgent },
|
|
315125
|
+
signal: options?.signal
|
|
315122
315126
|
});
|
|
315123
315127
|
if (response.status >= 400) {
|
|
315124
315128
|
await response.body?.cancel().catch(() => {});
|
|
@@ -315127,9 +315131,32 @@ var init_local_fetch_url = __esmMin((() => {
|
|
|
315127
315131
|
const contentLengthRaw = response.headers.get("content-length");
|
|
315128
315132
|
if (contentLengthRaw !== null) {
|
|
315129
315133
|
const cl = Number(contentLengthRaw);
|
|
315130
|
-
if (Number.isFinite(cl) && cl > this.maxBytes)
|
|
315134
|
+
if (Number.isFinite(cl) && cl > this.maxBytes) {
|
|
315135
|
+
await response.body?.cancel().catch(() => {});
|
|
315136
|
+
throw new Error(`Response body too large: ${String(cl)} bytes exceeds maxBytes (${String(this.maxBytes)}).`);
|
|
315137
|
+
}
|
|
315138
|
+
}
|
|
315139
|
+
let body = "";
|
|
315140
|
+
if (response.body !== null) {
|
|
315141
|
+
const reader = response.body.getReader();
|
|
315142
|
+
const decoder = new TextDecoder();
|
|
315143
|
+
let receivedBytes = 0;
|
|
315144
|
+
try {
|
|
315145
|
+
while (true) {
|
|
315146
|
+
const { done, value } = await reader.read();
|
|
315147
|
+
if (done) break;
|
|
315148
|
+
receivedBytes += value.byteLength;
|
|
315149
|
+
if (receivedBytes > this.maxBytes) {
|
|
315150
|
+
await reader.cancel().catch(() => {});
|
|
315151
|
+
throw new Error(`Response body too large: ${String(receivedBytes)} bytes exceeds maxBytes (${String(this.maxBytes)}).`);
|
|
315152
|
+
}
|
|
315153
|
+
body += decoder.decode(value, { stream: true });
|
|
315154
|
+
}
|
|
315155
|
+
body += decoder.decode();
|
|
315156
|
+
} finally {
|
|
315157
|
+
reader.releaseLock();
|
|
315158
|
+
}
|
|
315131
315159
|
}
|
|
315132
|
-
const body = await response.text();
|
|
315133
315160
|
const actualBytes = Buffer.byteLength(body, "utf8");
|
|
315134
315161
|
if (actualBytes > this.maxBytes) throw new Error(`Response body too large: ${String(actualBytes)} bytes exceeds maxBytes (${String(this.maxBytes)}).`);
|
|
315135
315162
|
const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
|
|
@@ -315172,18 +315199,21 @@ var init_blun_fetch_url = __esmMin((() => {
|
|
|
315172
315199
|
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
315173
315200
|
}
|
|
315174
315201
|
async fetch(url, options) {
|
|
315202
|
+
const signal = options?.signal;
|
|
315203
|
+
signal?.throwIfAborted();
|
|
315175
315204
|
try {
|
|
315176
315205
|
return {
|
|
315177
|
-
content: await this.fetchViaBlun(url, options?.toolCallId),
|
|
315206
|
+
content: await this.fetchViaBlun(url, options?.toolCallId, signal),
|
|
315178
315207
|
kind: "extracted"
|
|
315179
315208
|
};
|
|
315180
315209
|
} catch {
|
|
315210
|
+
signal?.throwIfAborted();
|
|
315181
315211
|
return this.localFallback.fetch(url, options ?? {});
|
|
315182
315212
|
}
|
|
315183
315213
|
}
|
|
315184
|
-
async fetchViaBlun(url, toolCallId) {
|
|
315214
|
+
async fetchViaBlun(url, toolCallId, signal) {
|
|
315185
315215
|
const bodyJson = JSON.stringify({ url });
|
|
315186
|
-
const response = await this.post(bodyJson, toolCallId);
|
|
315216
|
+
const response = await this.post(bodyJson, toolCallId, signal);
|
|
315187
315217
|
if (response.status !== 200) {
|
|
315188
315218
|
let detail = "";
|
|
315189
315219
|
try {
|
|
@@ -315193,8 +315223,9 @@ var init_blun_fetch_url = __esmMin((() => {
|
|
|
315193
315223
|
}
|
|
315194
315224
|
return response.text();
|
|
315195
315225
|
}
|
|
315196
|
-
async post(bodyJson, toolCallId) {
|
|
315226
|
+
async post(bodyJson, toolCallId, signal) {
|
|
315197
315227
|
const accessToken = await this.resolveApiKey();
|
|
315228
|
+
signal?.throwIfAborted();
|
|
315198
315229
|
return this.fetchImpl(this.baseUrl, {
|
|
315199
315230
|
method: "POST",
|
|
315200
315231
|
headers: {
|
|
@@ -315205,7 +315236,8 @@ var init_blun_fetch_url = __esmMin((() => {
|
|
|
315205
315236
|
...toolCallId !== void 0 && toolCallId.length > 0 ? { "X-Msh-Tool-Call-Id": toolCallId } : {},
|
|
315206
315237
|
...this.customHeaders
|
|
315207
315238
|
},
|
|
315208
|
-
body: bodyJson
|
|
315239
|
+
body: bodyJson,
|
|
315240
|
+
signal
|
|
315209
315241
|
});
|
|
315210
315242
|
}
|
|
315211
315243
|
async resolveApiKey() {
|