From b6f631e0457ddde3e91e4d562c83c1dacdc2ff9d Mon Sep 17 00:00:00 2001 From: Erhhung Yuan Date: Wed, 25 Mar 2026 16:40:00 -0700 Subject: [PATCH] fix(schema): tools.web.fetch.maxResponseBytes #53397 (#53401) Merged via squash. Prepared head SHA: 5d10a98bdb1f7fc3065adf438c4d572c3d61f8ce Co-authored-by: erhhung <5808864+erhhung@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Reviewed-by: @altaywtf --- CHANGELOG.md | 1 + docs/.generated/config-baseline.json | 15 +++++++++++++++ docs/.generated/config-baseline.jsonl | 3 ++- src/config/schema.base.generated.ts | 10 ++++++++++ src/config/schema.help.ts | 1 + src/config/schema.labels.ts | 1 + src/config/schema.test.ts | 12 ++++++++++++ src/config/types.tools.ts | 2 ++ src/config/zod-schema.agent-runtime.ts | 1 + 9 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbbe1c3a627..77e4661c151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -149,6 +149,7 @@ Docs: https://docs.openclaw.ai - Docs/IRC: fix five `json55` code-fence typos in the IRC channel examples so Mintlify applies JSON5 syntax highlighting correctly. (#50842) Thanks @Hollychou924. - Discord/commands: trim overlong slash-command descriptions to Discord's 100-character limit and map rejected deploy indexes from Discord validation payloads back to command names/descriptions, so deploys stop failing on long descriptions and startup logs identify the rejected commands. (#54118) thanks @huntharo - Agents/cooldowns: scope rate-limit cooldowns per model so one 429 no longer blocks every model on the same auth profile, replace the exponential 1 min → 1 h escalation with a stepped 30 s / 1 min / 5 min ladder, and surface a user-facing countdown message when all models are rate-limited. (#49834) Thanks @kiranvk-2011. +- Config/web fetch: allow the documented `tools.web.fetch.maxResponseBytes` setting in runtime schema validation so valid configs no longer fail with unrecognized-key errors. (#53401) Thanks @erhhung. ## 2026.3.23 diff --git a/docs/.generated/config-baseline.json b/docs/.generated/config-baseline.json index b2e5c385ca4..194bf68c565 100644 --- a/docs/.generated/config-baseline.json +++ b/docs/.generated/config-baseline.json @@ -64610,6 +64610,21 @@ "help": "Maximum redirects allowed for web_fetch (default: 3).", "hasChildren": false }, + { + "path": "tools.web.fetch.maxResponseBytes", + "kind": "core", + "type": "integer", + "required": false, + "deprecated": false, + "sensitive": false, + "tags": [ + "performance", + "tools" + ], + "label": "Web Fetch Max Download Size (bytes)", + "help": "Max download size before truncation.", + "hasChildren": false + }, { "path": "tools.web.fetch.readability", "kind": "core", diff --git a/docs/.generated/config-baseline.jsonl b/docs/.generated/config-baseline.jsonl index 0abd6a8bbdd..374b61f4bfe 100644 --- a/docs/.generated/config-baseline.jsonl +++ b/docs/.generated/config-baseline.jsonl @@ -1,4 +1,4 @@ -{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5631} +{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5632} {"recordType":"path","path":"acp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACP","help":"ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.","hasChildren":true} {"recordType":"path","path":"acp.allowedAgents","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"ACP Allowed Agents","help":"Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.","hasChildren":true} {"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false} @@ -5545,6 +5545,7 @@ {"recordType":"path","path":"tools.web.fetch.maxChars","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Max Chars","help":"Max characters returned by web_fetch (truncated).","hasChildren":false} {"recordType":"path","path":"tools.web.fetch.maxCharsCap","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Hard Max Chars","help":"Hard cap for web_fetch maxChars (applies to config and tool calls).","hasChildren":false} {"recordType":"path","path":"tools.web.fetch.maxRedirects","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","storage","tools"],"label":"Web Fetch Max Redirects","help":"Maximum redirects allowed for web_fetch (default: 3).","hasChildren":false} +{"recordType":"path","path":"tools.web.fetch.maxResponseBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Max Download Size (bytes)","help":"Max download size before truncation.","hasChildren":false} {"recordType":"path","path":"tools.web.fetch.readability","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Fetch Readability Extraction","help":"Use Readability to extract main content from HTML (fallbacks to basic HTML cleanup).","hasChildren":false} {"recordType":"path","path":"tools.web.fetch.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Timeout (sec)","help":"Timeout in seconds for web_fetch requests.","hasChildren":false} {"recordType":"path","path":"tools.web.fetch.userAgent","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Fetch User-Agent","help":"Override User-Agent header for web_fetch requests.","hasChildren":false} diff --git a/src/config/schema.base.generated.ts b/src/config/schema.base.generated.ts index 340b19adca0..3e1d80acabb 100644 --- a/src/config/schema.base.generated.ts +++ b/src/config/schema.base.generated.ts @@ -5620,6 +5620,11 @@ export const GENERATED_BASE_CONFIG_SCHEMA = { exclusiveMinimum: 0, maximum: 9007199254740991, }, + maxResponseBytes: { + type: "integer", + exclusiveMinimum: 0, + maximum: 9007199254740991, + }, timeoutSeconds: { type: "integer", exclusiveMinimum: 0, @@ -12947,6 +12952,11 @@ export const GENERATED_BASE_CONFIG_SCHEMA = { help: "Hard cap for web_fetch maxChars (applies to config and tool calls).", tags: ["performance", "tools"], }, + "tools.web.fetch.maxResponseBytes": { + label: "Web Fetch Max Download Size (bytes)", + help: "Max download size before truncation.", + tags: ["performance", "tools"], + }, "tools.web.fetch.timeoutSeconds": { label: "Web Fetch Timeout (sec)", help: "Timeout in seconds for web_fetch requests.", diff --git a/src/config/schema.help.ts b/src/config/schema.help.ts index 78ba36c5925..c97e9ac60ad 100644 --- a/src/config/schema.help.ts +++ b/src/config/schema.help.ts @@ -683,6 +683,7 @@ export const FIELD_HELP: Record = { "tools.web.fetch.maxChars": "Max characters returned by web_fetch (truncated).", "tools.web.fetch.maxCharsCap": "Hard cap for web_fetch maxChars (applies to config and tool calls).", + "tools.web.fetch.maxResponseBytes": "Max download size before truncation.", "tools.web.fetch.timeoutSeconds": "Timeout in seconds for web_fetch requests.", "tools.web.fetch.cacheTtlMinutes": "Cache TTL in minutes for web_fetch results.", "tools.web.fetch.maxRedirects": "Maximum redirects allowed for web_fetch (default: 3).", diff --git a/src/config/schema.labels.ts b/src/config/schema.labels.ts index 15736dad2f0..0b430c1a77d 100644 --- a/src/config/schema.labels.ts +++ b/src/config/schema.labels.ts @@ -226,6 +226,7 @@ export const FIELD_LABELS: Record = { "tools.web.fetch.enabled": "Enable Web Fetch Tool", "tools.web.fetch.maxChars": "Web Fetch Max Chars", "tools.web.fetch.maxCharsCap": "Web Fetch Hard Max Chars", + "tools.web.fetch.maxResponseBytes": "Web Fetch Max Download Size (bytes)", "tools.web.fetch.timeoutSeconds": "Web Fetch Timeout (sec)", "tools.web.fetch.cacheTtlMinutes": "Web Fetch Cache TTL (min)", "tools.web.fetch.maxRedirects": "Web Fetch Max Redirects", diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index 3d6ecced2ca..532eb89a8d9 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -231,6 +231,18 @@ describe("config schema", () => { }); }); + it("accepts web fetch maxResponseBytes in the runtime zod schema", () => { + const parsed = ToolsSchema.parse({ + web: { + fetch: { + maxResponseBytes: 2_000_000, + }, + }, + }); + + expect(parsed?.web?.fetch?.maxResponseBytes).toBe(2_000_000); + }); + it("rejects unknown keys inside web fetch firecrawl config", () => { expect(() => ToolsSchema.parse({ diff --git a/src/config/types.tools.ts b/src/config/types.tools.ts index 4549bd80c54..f66d6773045 100644 --- a/src/config/types.tools.ts +++ b/src/config/types.tools.ts @@ -502,6 +502,8 @@ export type ToolsConfig = { maxChars?: number; /** Hard cap for maxChars (tool or config), defaults to 50000. */ maxCharsCap?: number; + /** Max download size before truncation, defaults to 2000000. */ + maxResponseBytes?: number; /** Timeout in seconds for fetch requests. */ timeoutSeconds?: number; /** Cache TTL in minutes for fetched content. */ diff --git a/src/config/zod-schema.agent-runtime.ts b/src/config/zod-schema.agent-runtime.ts index 722c5ec9baf..737b824694f 100644 --- a/src/config/zod-schema.agent-runtime.ts +++ b/src/config/zod-schema.agent-runtime.ts @@ -327,6 +327,7 @@ export const ToolsWebFetchSchema = z enabled: z.boolean().optional(), maxChars: z.number().int().positive().optional(), maxCharsCap: z.number().int().positive().optional(), + maxResponseBytes: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), cacheTtlMinutes: z.number().nonnegative().optional(), maxRedirects: z.number().int().nonnegative().optional(),