diff --git a/CHANGELOG.md b/CHANGELOG.md index d3eb7679f5b..6c189efda09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai - Agents/Azure OpenAI startup prompts: rephrase the built-in `/new`, `/reset`, and post-compaction startup instruction so Azure OpenAI deployments no longer hit HTTP 400 false positives from the content filter. (#43403) Thanks @xingsy97. - Config/validation: accept documented `agents.list[].params` per-agent overrides in strict config validation so `openclaw config validate` no longer rejects runtime-supported `cacheRetention`, `temperature`, and `maxTokens` settings. (#41171) Thanks @atian8179. - Android/onboarding QR scan: switch setup QR scanning to Google Code Scanner so onboarding uses a more reliable scanner instead of the legacy embedded ZXing flow. (#45021) Thanks @obviyus. +- Config/web fetch: restore runtime validation for documented `tools.web.fetch.readability` and `tools.web.fetch.firecrawl` settings so valid web fetch configs no longer fail with unrecognized-key errors. (#42583) Thanks @stim64045-spec. ## 2026.3.12 diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index 54aaa79c846..3d6ecced2ca 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -1,6 +1,7 @@ import { beforeAll, describe, expect, it } from "vitest"; import { buildConfigSchema, lookupConfigSchema } from "./schema.js"; import { applyDerivedTags, CONFIG_TAGS, deriveTagsForPath } from "./schema.tags.js"; +import { ToolsSchema } from "./zod-schema.agent-runtime.js"; describe("config schema", () => { type SchemaInput = NonNullable[0]>; @@ -200,6 +201,51 @@ describe("config schema", () => { expect(tags).toContain("performance"); }); + it("accepts web fetch readability and firecrawl config in the runtime zod schema", () => { + const parsed = ToolsSchema.parse({ + web: { + fetch: { + readability: true, + firecrawl: { + enabled: true, + apiKey: "firecrawl-test-key", + baseUrl: "https://api.firecrawl.dev", + onlyMainContent: true, + maxAgeMs: 60_000, + timeoutSeconds: 15, + }, + }, + }, + }); + + expect(parsed?.web?.fetch?.readability).toBe(true); + expect(parsed?.web?.fetch).toMatchObject({ + firecrawl: { + enabled: true, + apiKey: "firecrawl-test-key", + baseUrl: "https://api.firecrawl.dev", + onlyMainContent: true, + maxAgeMs: 60_000, + timeoutSeconds: 15, + }, + }); + }); + + it("rejects unknown keys inside web fetch firecrawl config", () => { + expect(() => + ToolsSchema.parse({ + web: { + fetch: { + firecrawl: { + enabled: true, + nope: true, + }, + }, + }, + }), + ).toThrow(); + }); + it("keeps tags in the allowed taxonomy", () => { const withTags = applyDerivedTags({ "gateway.auth.token": {}, diff --git a/src/config/zod-schema.agent-runtime.ts b/src/config/zod-schema.agent-runtime.ts index 680b79cdc16..7a87440a768 100644 --- a/src/config/zod-schema.agent-runtime.ts +++ b/src/config/zod-schema.agent-runtime.ts @@ -327,6 +327,18 @@ export const ToolsWebFetchSchema = z cacheTtlMinutes: z.number().nonnegative().optional(), maxRedirects: z.number().int().nonnegative().optional(), userAgent: z.string().optional(), + readability: z.boolean().optional(), + firecrawl: z + .object({ + enabled: z.boolean().optional(), + apiKey: SecretInputSchema.optional().register(sensitive), + baseUrl: z.string().optional(), + onlyMainContent: z.boolean().optional(), + maxAgeMs: z.number().int().nonnegative().optional(), + timeoutSeconds: z.number().int().positive().optional(), + }) + .strict() + .optional(), }) .strict() .optional();