fix(body-size): raise LLM API payload limit for responses routes (#5652)

Integrated into release/v3.8.43. Thanks @JxnLexn!
This commit is contained in:
Jan Leon
2026-06-30 19:50:48 +02:00
committed by GitHub
parent 58b5ba01ca
commit 8ec85993d2
3 changed files with 42 additions and 2 deletions

View File

@@ -28,6 +28,9 @@ export const MAX_BODY_BYTES_AUDIO = 100 * 1024 * 1024;
/** Larger limit for file uploads: 500 MB */
export const MAX_BODY_BYTES_FILE = 500 * 1024 * 1024;
/** Larger limit for LLM request payloads: 50 MB */
export const MAX_BODY_BYTES_LLM_API = 50 * 1024 * 1024;
/** Configured limit — reads from env or falls back to 10 MB */
export const MAX_BODY_BYTES = parseRequestBodyLimitBytes(process.env.MAX_BODY_SIZE_BYTES);
@@ -35,6 +38,8 @@ type BodySizeRule = { prefix: string; limit: number };
const ROUTE_LIMITS: BodySizeRule[] = [
{ prefix: "/api/db-backups/import", limit: MAX_BODY_BYTES_IMPORT },
{ prefix: "/api/v1/chat/completions", limit: MAX_BODY_BYTES_LLM_API },
{ prefix: "/api/v1/responses", limit: MAX_BODY_BYTES_LLM_API },
{ prefix: "/api/v1/audio/transcriptions", limit: MAX_BODY_BYTES_AUDIO },
{ prefix: "/api/v1/files", limit: MAX_BODY_BYTES_FILE },
];

View File

@@ -62,8 +62,8 @@ const INJECTION_PATTERNS = [
* latency/GC source. Injection directives sit near the top of a prompt, so
* scanning hundreds of KB of pasted code / RAG context buys only CPU. We bound
* the scan to the first 16 KB (generous: real directives are far shorter) before
* the regex loop. The 10 MB body-size cap that protects ingestion lives
* elsewhere; this constant only bounds the regex scan. Refs #3932 / #4041.
* the regex loop. The body-size caps that protect ingestion live elsewhere;
* this constant only bounds the regex scan. Refs #3932 / #4041.
*/
export const MAX_INJECTION_SCAN_BYTES = 16 * 1024;

View File

@@ -4,6 +4,7 @@ import * as bodySizeGuard from "../../src/shared/middleware/bodySizeGuard.ts";
import {
MAX_BODY_BYTES_AUDIO,
MAX_BODY_BYTES_FILE,
MAX_BODY_BYTES_LLM_API,
getBodySizeLimit,
checkBodySize,
} from "../../src/shared/middleware/bodySizeGuard.ts";
@@ -23,6 +24,14 @@ test("body size guard uses maxBodySizeMb from settings for regular API routes",
});
test("body size guard keeps dedicated upload limits as lower bounds", () => {
assert.equal(
getBodySizeLimit("/api/v1/responses", { maxBodySizeMb: 10 }),
MAX_BODY_BYTES_LLM_API
);
assert.equal(
getBodySizeLimit("/api/v1/chat/completions", { maxBodySizeMb: 10 }),
MAX_BODY_BYTES_LLM_API
);
assert.equal(
getBodySizeLimit("/api/v1/audio/transcriptions", { maxBodySizeMb: 1 }),
MAX_BODY_BYTES_AUDIO
@@ -49,6 +58,32 @@ test("checkBodySize reports the configured request limit in 413 responses", asyn
assert.match(body.error.message, /100 MB/);
});
test("/api/v1/responses route guard allows 15 MB agent payloads by default", () => {
const fifteenMb = 15 * 1024 * 1024;
const request = new Request("http://localhost/api/v1/responses", {
method: "POST",
headers: { "content-length": String(fifteenMb) },
});
assert.equal(checkBodySize(request, getBodySizeLimit("/api/v1/responses")), null);
});
test("/api/v1/responses route guard rejects payloads above the LLM API floor", async () => {
const tooBig = MAX_BODY_BYTES_LLM_API + 1;
const request = new Request("http://localhost/api/v1/responses", {
method: "POST",
headers: { "content-length": String(tooBig) },
});
const response = checkBodySize(request, getBodySizeLimit("/api/v1/responses"));
assert.ok(response);
assert.equal(response.status, 413);
const body = await response.json();
assert.equal(body.error.code, "PAYLOAD_TOO_LARGE");
assert.match(body.error.message, /50 MB/);
});
test("/api/v1/files route has 512 MB dedicated limit floor", () => {
const limit = getBodySizeLimit("/api/v1/files", { maxBodySizeMb: 1 });
assert.equal(limit, MAX_BODY_BYTES_FILE);