refactor(media): centralize input file limit resolution

This commit is contained in:
Peter Steinberger
2026-02-17 00:29:22 +00:00
parent ed74f48bd5
commit 37c97964af
3 changed files with 36 additions and 38 deletions

View File

@@ -16,19 +16,14 @@ import type { GatewayHttpResponsesConfig } from "../config/types.gateway.js";
import { emitAgentEvent, onAgentEvent } from "../infra/agent-events.js";
import { logWarn } from "../logger.js";
import {
DEFAULT_INPUT_FILE_MAX_BYTES,
DEFAULT_INPUT_FILE_MAX_CHARS,
DEFAULT_INPUT_FILE_MIMES,
DEFAULT_INPUT_IMAGE_MAX_BYTES,
DEFAULT_INPUT_IMAGE_MIMES,
DEFAULT_INPUT_MAX_REDIRECTS,
DEFAULT_INPUT_PDF_MAX_PAGES,
DEFAULT_INPUT_PDF_MAX_PIXELS,
DEFAULT_INPUT_PDF_MIN_TEXT_CHARS,
DEFAULT_INPUT_TIMEOUT_MS,
extractFileContentFromSource,
extractImageContentFromSource,
normalizeMimeList,
resolveInputFileLimits,
type InputFileLimits,
type InputImageLimits,
type InputImageSource,
@@ -109,6 +104,7 @@ function resolveResponsesLimits(
): ResolvedResponsesLimits {
const files = config?.files;
const images = config?.images;
const fileLimits = resolveInputFileLimits(files);
return {
maxBodyBytes: config?.maxBodyBytes ?? DEFAULT_BODY_BYTES,
maxUrlParts:
@@ -116,18 +112,8 @@ function resolveResponsesLimits(
? Math.max(0, Math.floor(config.maxUrlParts))
: DEFAULT_MAX_URL_PARTS,
files: {
allowUrl: files?.allowUrl ?? true,
...fileLimits,
urlAllowlist: normalizeHostnameAllowlist(files?.urlAllowlist),
allowedMimes: normalizeMimeList(files?.allowedMimes, DEFAULT_INPUT_FILE_MIMES),
maxBytes: files?.maxBytes ?? DEFAULT_INPUT_FILE_MAX_BYTES,
maxChars: files?.maxChars ?? DEFAULT_INPUT_FILE_MAX_CHARS,
maxRedirects: files?.maxRedirects ?? DEFAULT_INPUT_MAX_REDIRECTS,
timeoutMs: files?.timeoutMs ?? DEFAULT_INPUT_TIMEOUT_MS,
pdf: {
maxPages: files?.pdf?.maxPages ?? DEFAULT_INPUT_PDF_MAX_PAGES,
maxPixels: files?.pdf?.maxPixels ?? DEFAULT_INPUT_PDF_MAX_PIXELS,
minTextChars: files?.pdf?.minTextChars ?? DEFAULT_INPUT_PDF_MIN_TEXT_CHARS,
},
},
images: {
allowUrl: images?.allowUrl ?? true,

View File

@@ -4,17 +4,9 @@ import type { MsgContext } from "../auto-reply/templating.js";
import type { OpenClawConfig } from "../config/config.js";
import { logVerbose, shouldLogVerbose } from "../globals.js";
import {
DEFAULT_INPUT_FILE_MAX_BYTES,
DEFAULT_INPUT_FILE_MAX_CHARS,
DEFAULT_INPUT_FILE_MIMES,
DEFAULT_INPUT_MAX_REDIRECTS,
DEFAULT_INPUT_PDF_MAX_PAGES,
DEFAULT_INPUT_PDF_MAX_PIXELS,
DEFAULT_INPUT_PDF_MIN_TEXT_CHARS,
DEFAULT_INPUT_TIMEOUT_MS,
extractFileContentFromSource,
normalizeMimeList,
normalizeMimeType,
resolveInputFileLimits,
} from "../media/input-files.js";
import { resolveAttachmentKind } from "./attachments.js";
import { runWithConcurrency } from "./concurrency.js";
@@ -107,20 +99,10 @@ function sanitizeMimeType(value?: string): string | undefined {
function resolveFileLimits(cfg: OpenClawConfig) {
const files = cfg.gateway?.http?.endpoints?.responses?.files;
const allowedMimesConfigured = Boolean(files?.allowedMimes && files.allowedMimes.length > 0);
const allowedMimesConfigured = Boolean(files?.allowedMimes?.length);
return {
allowUrl: files?.allowUrl ?? true,
allowedMimes: normalizeMimeList(files?.allowedMimes, DEFAULT_INPUT_FILE_MIMES),
...resolveInputFileLimits(files),
allowedMimesConfigured,
maxBytes: files?.maxBytes ?? DEFAULT_INPUT_FILE_MAX_BYTES,
maxChars: files?.maxChars ?? DEFAULT_INPUT_FILE_MAX_CHARS,
maxRedirects: files?.maxRedirects ?? DEFAULT_INPUT_MAX_REDIRECTS,
timeoutMs: files?.timeoutMs ?? DEFAULT_INPUT_TIMEOUT_MS,
pdf: {
maxPages: files?.pdf?.maxPages ?? DEFAULT_INPUT_PDF_MAX_PAGES,
maxPixels: files?.pdf?.maxPixels ?? DEFAULT_INPUT_PDF_MAX_PIXELS,
minTextChars: files?.pdf?.minTextChars ?? DEFAULT_INPUT_PDF_MIN_TEXT_CHARS,
},
};
}

View File

@@ -64,6 +64,20 @@ export type InputFileLimits = {
pdf: InputPdfLimits;
};
export type InputFileLimitsConfig = {
allowUrl?: boolean;
allowedMimes?: string[];
maxBytes?: number;
maxChars?: number;
maxRedirects?: number;
timeoutMs?: number;
pdf?: {
maxPages?: number;
maxPixels?: number;
minTextChars?: number;
};
};
export type InputImageLimits = {
allowUrl: boolean;
urlAllowlist?: string[];
@@ -154,6 +168,22 @@ export function normalizeMimeList(values: string[] | undefined, fallback: string
return new Set(input.map((value) => normalizeMimeType(value)).filter(Boolean) as string[]);
}
export function resolveInputFileLimits(config?: InputFileLimitsConfig): InputFileLimits {
return {
allowUrl: config?.allowUrl ?? true,
allowedMimes: normalizeMimeList(config?.allowedMimes, DEFAULT_INPUT_FILE_MIMES),
maxBytes: config?.maxBytes ?? DEFAULT_INPUT_FILE_MAX_BYTES,
maxChars: config?.maxChars ?? DEFAULT_INPUT_FILE_MAX_CHARS,
maxRedirects: config?.maxRedirects ?? DEFAULT_INPUT_MAX_REDIRECTS,
timeoutMs: config?.timeoutMs ?? DEFAULT_INPUT_TIMEOUT_MS,
pdf: {
maxPages: config?.pdf?.maxPages ?? DEFAULT_INPUT_PDF_MAX_PAGES,
maxPixels: config?.pdf?.maxPixels ?? DEFAULT_INPUT_PDF_MAX_PIXELS,
minTextChars: config?.pdf?.minTextChars ?? DEFAULT_INPUT_PDF_MIN_TEXT_CHARS,
},
};
}
export async function fetchWithGuard(params: {
url: string;
maxBytes: number;