Skip to content

Commit 7545c76

Browse files
authored
feat: add actionable config hints to all limit error messages (#112)
* feat: add actionable config hints to all limit error messages Every error message that fires when a configurable limit is breached now tells the LLM which config field to increase via manage_plugin. fs-read (4 messages): - maxFileSizeKb hint on all 'File too large' errors - maxReadChunkKb hint on per-call chunk errors fs-write (8 messages): - maxWriteChunkKb hint on per-call chunk errors (text + binary) - maxWriteSizeKb hint on cumulative write limit errors - maxEntries hint on entry creation limit errors fetch (9 messages): - maxRequestsPerMinute/maxRequestsPerHour on rate limit errors - maxDomainsPerSession on domain count errors - maxDataReceivedKb on data budget errors - maxResponseSizeKb on response too large errors - maxRequestBodySizeKb on request body errors - maxRedirects on redirect limit errors - maxJsonResponseBytes/maxTextResponseBytes on convenience method errors Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * fix: address PR #112 review feedback - writeFile chunk error now advises 'first chunk via writeFile, rest via appendFile' instead of just 'split into appendFile' which would change overwrite→append semantics - writeFileBinary same fix for non-Office fallback message - All maxReadChunkKb and maxWriteChunkKb config hints now warn to ensure the sandbox buffer is large enough to match, preventing VM faults from raising chunk size without the buffer Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> --------- Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent 5f9f20e commit 7545c76

3 files changed

Lines changed: 41 additions & 31 deletions

File tree

plugins/fetch/index.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,29 +1112,36 @@ function createRateLimiter(config: {
11121112
if (timestamps.length >= config.maxPerMinute) {
11131113
return {
11141114
allowed: false,
1115-
reason: "fetch blocked: rate limit exceeded (per-minute)",
1115+
reason:
1116+
"fetch blocked: rate limit exceeded (per-minute). To increase, reconfigure fetch with a larger maxRequestsPerMinute.",
11161117
};
11171118
}
11181119

11191120
// Per-hour total
11201121
if (totalRequests >= config.maxPerHour) {
11211122
return {
11221123
allowed: false,
1123-
reason: "fetch blocked: rate limit exceeded (per-hour)",
1124+
reason:
1125+
"fetch blocked: rate limit exceeded (per-hour). To increase, reconfigure fetch with a larger maxRequestsPerHour.",
11241126
};
11251127
}
11261128

11271129
// Domain count
11281130
if (!domains.has(hostname) && domains.size >= config.maxDomains) {
11291131
return {
11301132
allowed: false,
1131-
reason: "fetch blocked: too many unique domains",
1133+
reason:
1134+
"fetch blocked: too many unique domains. To increase, reconfigure fetch with a larger maxDomainsPerSession.",
11321135
};
11331136
}
11341137

11351138
// Data budget
11361139
if (totalBytesReceived >= config.maxDataReceivedBytes) {
1137-
return { allowed: false, reason: "fetch blocked: data budget exhausted" };
1140+
return {
1141+
allowed: false,
1142+
reason:
1143+
"fetch blocked: data budget exhausted. To increase, reconfigure fetch with a larger maxDataReceivedKb.",
1144+
};
11381145
}
11391146

11401147
return { allowed: true };
@@ -2239,7 +2246,10 @@ function secureFetchSingle(
22392246
clearTimeout(readTimer);
22402247
clearTimeout(hardTimer);
22412248
res.destroy();
2242-
return settle({ error: "fetch blocked: response too large" });
2249+
return settle({
2250+
error:
2251+
"fetch blocked: response too large. To increase, reconfigure fetch with a larger maxResponseSizeKb.",
2252+
});
22432253
}
22442254
chunks.push(chunk);
22452255
});
@@ -2547,7 +2557,7 @@ async function secureFetch(
25472557

25482558
// Exhausted redirect budget
25492559
return {
2550-
error: `fetch blocked: too many redirects (max ${opts.maxRedirects})`,
2560+
error: `fetch blocked: too many redirects (max ${opts.maxRedirects}). To increase, reconfigure fetch with a larger maxRedirects.`,
25512561
};
25522562
}
25532563

@@ -3136,7 +3146,7 @@ export function createHostFunctions(config?: FetchConfig): FetchHostFunctions {
31363146
});
31373147
await enforceMinDelay(startTime, MIN_RESPONSE_DELAY_MS);
31383148
return {
3139-
error: `fetch blocked: request body too large (max ${maxRequestBodyBytes / 1024}KB)`,
3149+
error: `fetch blocked: request body too large (max ${maxRequestBodyBytes / 1024}KB). To increase, reconfigure fetch with a larger maxRequestBodySizeKb.`,
31403150
};
31413151
}
31423152

@@ -3517,7 +3527,7 @@ export function createHostFunctions(config?: FetchConfig): FetchHostFunctions {
35173527
throw new Error(
35183528
`fetchJSON: response too large ` +
35193529
`(${jsonBodyBytes} bytes, max ${maxJsonResponseBytes}). ` +
3520-
`Use get() + read() loop to stream large responses instead.`,
3530+
`Use get() + read() loop to stream large responses instead, or reconfigure fetch with a larger maxJsonResponseBytes.`,
35213531
);
35223532
}
35233533

@@ -3582,7 +3592,7 @@ export function createHostFunctions(config?: FetchConfig): FetchHostFunctions {
35823592
throw new Error(
35833593
`fetchText: response too large ` +
35843594
`(${textBodyBytes} bytes, max ${maxTextResponseBytes}). ` +
3585-
`Use get() + read() loop to stream large responses instead.`,
3595+
`Use get() + read() loop to stream large responses instead, or reconfigure fetch with a larger maxTextResponseBytes.`,
35863596
);
35873597
}
35883598

plugins/fs-read/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,12 @@ export function createHostFunctions(
272272
}
273273
if (fileStat.size > maxFileBytes) {
274274
return {
275-
error: `File too large: exceeds read limit of ${maxFileBytes / 1024}KB`,
275+
error: `File too large: exceeds read limit of ${maxFileBytes / 1024}KB. To increase, reconfigure fs-read with a larger maxFileSizeKb.`,
276276
};
277277
}
278278
if (fileStat.size > maxReadChunkBytes) {
279279
return {
280-
error: `File too large for single read: ${fileStat.size} bytes exceeds per-call limit of ${maxReadChunkBytes / 1024}KB. Use readFileChunk(path, offsetBytes, lengthBytes) to read in chunks.`,
280+
error: `File too large for single read: ${fileStat.size} bytes exceeds per-call limit of ${maxReadChunkBytes / 1024}KB. Use readFileChunk(path, offsetBytes, lengthBytes) to read in chunks, or reconfigure fs-read with a larger maxReadChunkKb (ensure the sandbox input buffer is large enough to match).`,
281281
};
282282
}
283283

@@ -343,7 +343,7 @@ export function createHostFunctions(
343343
}
344344
if (fileStat.size > maxFileBytes) {
345345
return {
346-
error: `File too large: exceeds read limit of ${maxFileBytes / 1024}KB`,
346+
error: `File too large: exceeds read limit of ${maxFileBytes / 1024}KB. To increase, reconfigure fs-read with a larger maxFileSizeKb.`,
347347
};
348348
}
349349

@@ -484,14 +484,14 @@ export function createHostFunctions(
484484
}
485485
if (fileStat.size > maxFileBytes) {
486486
throw new Error(
487-
`File too large: exceeds read limit of ${maxFileBytes / 1024}KB`,
487+
`File too large: exceeds read limit of ${maxFileBytes / 1024}KB. To increase, reconfigure fs-read with a larger maxFileSizeKb.`,
488488
);
489489
}
490490
if (fileStat.size > maxReadChunkBytes) {
491491
throw new Error(
492492
`File too large for single read: ${fileStat.size} bytes exceeds ` +
493493
`per-call limit of ${maxReadChunkBytes / 1024}KB. ` +
494-
`Use readFileChunkBinary(path, offsetBytes, lengthBytes) to read in chunks.`,
494+
`Use readFileChunkBinary(path, offsetBytes, lengthBytes) to read in chunks, or reconfigure fs-read with a larger maxReadChunkKb (ensure the sandbox input buffer is large enough to match).`,
495495
);
496496
}
497497

@@ -547,7 +547,7 @@ export function createHostFunctions(
547547
}
548548
if (fileStat.size > maxFileBytes) {
549549
throw new Error(
550-
`File too large: exceeds read limit of ${maxFileBytes / 1024}KB`,
550+
`File too large: exceeds read limit of ${maxFileBytes / 1024}KB. To increase, reconfigure fs-read with a larger maxFileSizeKb.`,
551551
);
552552
}
553553

plugins/fs-write/index.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -243,12 +243,12 @@ export function createHostFunctions(
243243

244244
if (contentBytes > maxWriteChunkBytes) {
245245
return {
246-
error: `Content too large for single write: ${contentBytes} bytes exceeds per-call limit of ${maxWriteChunkBytes / 1024}KB. Split into multiple appendFile calls.`,
246+
error: `Content too large for single write: ${contentBytes} bytes exceeds per-call limit of ${maxWriteChunkBytes / 1024}KB. Write the first chunk with writeFile, then append remaining chunks with appendFile. Or reconfigure fs-write with a larger maxWriteChunkKb (ensure the sandbox output buffer is large enough to match).`,
247247
};
248248
}
249249
if (contentBytes > maxWriteBytes) {
250250
return {
251-
error: `Content too large: exceeds cumulative file write limit of ${maxWriteBytes / 1024}KB`,
251+
error: `Content too large: exceeds cumulative file write limit of ${maxWriteBytes / 1024}KB. To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
252252
};
253253
}
254254

@@ -263,7 +263,7 @@ export function createHostFunctions(
263263
if (isNew) {
264264
if (entriesCreated >= maxEntries) {
265265
return {
266-
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories`,
266+
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories. To increase, reconfigure fs-write with a larger maxEntries.`,
267267
};
268268
}
269269
entriesCreated++;
@@ -333,12 +333,12 @@ export function createHostFunctions(
333333

334334
if (contentBytes > maxWriteChunkBytes) {
335335
return {
336-
error: `Append content too large for single call: ${contentBytes} bytes exceeds per-call limit of ${maxWriteChunkBytes / 1024}KB. Split into smaller appendFile calls.`,
336+
error: `Append content too large for single call: ${contentBytes} bytes exceeds per-call limit of ${maxWriteChunkBytes / 1024}KB. Split into smaller appendFile calls, or reconfigure fs-write with a larger maxWriteChunkKb.`,
337337
};
338338
}
339339
if (contentBytes > maxWriteBytes) {
340340
return {
341-
error: `Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB`,
341+
error: `Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB. To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
342342
};
343343
}
344344

@@ -353,7 +353,7 @@ export function createHostFunctions(
353353
if (isNew) {
354354
if (entriesCreated >= maxEntries) {
355355
return {
356-
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories`,
356+
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories. To increase, reconfigure fs-write with a larger maxEntries.`,
357357
};
358358
}
359359
entriesCreated++;
@@ -372,7 +372,7 @@ export function createHostFunctions(
372372
}
373373
if (fdStat.size + contentBytes > maxWriteBytes) {
374374
return {
375-
error: `Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB (current: ${fdStat.size} bytes + new: ${contentBytes} bytes)`,
375+
error: `Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB (current: ${fdStat.size} bytes + new: ${contentBytes} bytes). To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
376376
};
377377
}
378378

@@ -432,15 +432,15 @@ export function createHostFunctions(
432432
filePath.toLowerCase().endsWith(".docx");
433433
const hint = isOffice
434434
? ` For ${isPptx ? "PPTX" : "Office"} files, use exportToFile(pres, filename, fsWrite) from ha:pptx which handles chunking automatically.`
435-
: " Split into multiple appendFileBinary calls.";
435+
: " Write the first chunk with writeFileBinary, then append remaining chunks with appendFileBinary.";
436436
throw new Error(
437437
`Content too large for single write: ${contentBytes} bytes exceeds ` +
438-
`per-call limit of ${maxWriteChunkBytes / 1024}KB.${hint}`,
438+
`per-call limit of ${maxWriteChunkBytes / 1024}KB.${hint} Or reconfigure fs-write with a larger maxWriteChunkKb (ensure the sandbox output buffer is large enough to match).`,
439439
);
440440
}
441441
if (contentBytes > maxWriteBytes) {
442442
throw new Error(
443-
`Content too large: exceeds cumulative file write limit of ${maxWriteBytes / 1024}KB`,
443+
`Content too large: exceeds cumulative file write limit of ${maxWriteBytes / 1024}KB. To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
444444
);
445445
}
446446

@@ -455,7 +455,7 @@ export function createHostFunctions(
455455
if (isNew) {
456456
if (entriesCreated >= maxEntries) {
457457
throw new Error(
458-
`Entry limit reached: cannot create more than ${maxEntries} files/directories`,
458+
`Entry limit reached: cannot create more than ${maxEntries} files/directories. To increase, reconfigure fs-write with a larger maxEntries.`,
459459
);
460460
}
461461
entriesCreated++;
@@ -520,12 +520,12 @@ export function createHostFunctions(
520520
throw new Error(
521521
`Append content too large for single call: ${contentBytes} bytes exceeds ` +
522522
`per-call limit of ${maxWriteChunkBytes / 1024}KB. ` +
523-
`Split into smaller appendFileBinary calls.`,
523+
`Split into smaller appendFileBinary calls, or reconfigure fs-write with a larger maxWriteChunkKb.`,
524524
);
525525
}
526526
if (contentBytes > maxWriteBytes) {
527527
throw new Error(
528-
`Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB`,
528+
`Append would exceed cumulative file write limit of ${maxWriteBytes / 1024}KB. To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
529529
);
530530
}
531531

@@ -540,7 +540,7 @@ export function createHostFunctions(
540540
if (isNew) {
541541
if (entriesCreated >= maxEntries) {
542542
throw new Error(
543-
`Entry limit reached: cannot create more than ${maxEntries} files/directories`,
543+
`Entry limit reached: cannot create more than ${maxEntries} files/directories. To increase, reconfigure fs-write with a larger maxEntries.`,
544544
);
545545
}
546546
entriesCreated++;
@@ -560,7 +560,7 @@ export function createHostFunctions(
560560
if (fdStat.size + contentBytes > maxWriteBytes) {
561561
throw new Error(
562562
`Append would exceed cumulative file write limit of ` +
563-
`${maxWriteBytes / 1024}KB (current: ${fdStat.size} bytes + new: ${contentBytes} bytes)`,
563+
`${maxWriteBytes / 1024}KB (current: ${fdStat.size} bytes + new: ${contentBytes} bytes). To increase, reconfigure fs-write with a larger maxWriteSizeKb.`,
564564
);
565565
}
566566

@@ -595,7 +595,7 @@ export function createHostFunctions(
595595
}
596596
if (entriesCreated >= maxEntries) {
597597
return {
598-
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories`,
598+
error: `Entry limit reached: cannot create more than ${maxEntries} files/directories. To increase, reconfigure fs-write with a larger maxEntries.`,
599599
};
600600
}
601601
entriesCreated++;

0 commit comments

Comments
 (0)