From 5cc751386d217ff5767ecf6c0938d2aaf93fec4b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 19:13:54 +0000 Subject: [PATCH] refactor: share web secret unresolved helpers --- src/secrets/runtime-web-tools.test.ts | 42 ++++++++++++------------- src/secrets/runtime-web-tools.ts | 45 +++++++++++---------------- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/secrets/runtime-web-tools.test.ts b/src/secrets/runtime-web-tools.test.ts index b4484095188..57e3e955066 100644 --- a/src/secrets/runtime-web-tools.test.ts +++ b/src/secrets/runtime-web-tools.test.ts @@ -65,6 +65,24 @@ function readProviderKey(config: OpenClawConfig, provider: ProviderUnderTest): u return config.tools?.web?.search?.perplexity?.apiKey; } +function expectInactiveFirecrawlSecretRef(params: { + resolveSpy: ReturnType; + metadata: Awaited>["metadata"]; + context: Awaited>["context"]; +}) { + expect(params.resolveSpy).not.toHaveBeenCalled(); + expect(params.metadata.fetch.firecrawl.active).toBe(false); + expect(params.metadata.fetch.firecrawl.apiKeySource).toBe("secretRef"); + expect(params.context.warnings).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + code: "SECRETS_REF_IGNORED_INACTIVE_SURFACE", + path: "tools.web.fetch.firecrawl.apiKey", + }), + ]), + ); +} + describe("runtime web tools resolution", () => { afterEach(() => { vi.restoreAllMocks(); @@ -339,17 +357,7 @@ describe("runtime web tools resolution", () => { }), }); - expect(resolveSpy).not.toHaveBeenCalled(); - expect(metadata.fetch.firecrawl.active).toBe(false); - expect(metadata.fetch.firecrawl.apiKeySource).toBe("secretRef"); - expect(context.warnings).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - code: "SECRETS_REF_IGNORED_INACTIVE_SURFACE", - path: "tools.web.fetch.firecrawl.apiKey", - }), - ]), - ); + expectInactiveFirecrawlSecretRef({ resolveSpy, metadata, context }); }); it("does not resolve Firecrawl SecretRef when Firecrawl is disabled", async () => { @@ -370,17 +378,7 @@ describe("runtime web tools resolution", () => { }), }); - expect(resolveSpy).not.toHaveBeenCalled(); - expect(metadata.fetch.firecrawl.active).toBe(false); - expect(metadata.fetch.firecrawl.apiKeySource).toBe("secretRef"); - expect(context.warnings).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - code: "SECRETS_REF_IGNORED_INACTIVE_SURFACE", - path: "tools.web.fetch.firecrawl.apiKey", - }), - ]), - ); + expectInactiveFirecrawlSecretRef({ resolveSpy, metadata, context }); }); it("uses env fallback for unresolved Firecrawl SecretRef when active", async () => { diff --git a/src/secrets/runtime-web-tools.ts b/src/secrets/runtime-web-tools.ts index d888b36e8ab..883aac6bd02 100644 --- a/src/secrets/runtime-web-tools.ts +++ b/src/secrets/runtime-web-tools.ts @@ -471,39 +471,30 @@ export async function resolveRuntimeWebTools(params: { } } + const failUnresolvedSearchNoFallback = (unresolved: { path: string; reason: string }) => { + const diagnostic: RuntimeWebDiagnostic = { + code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", + message: unresolved.reason, + path: unresolved.path, + }; + diagnostics.push(diagnostic); + searchMetadata.diagnostics.push(diagnostic); + pushWarning(params.context, { + code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", + path: unresolved.path, + message: unresolved.reason, + }); + throw new Error(`[WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK] ${unresolved.reason}`); + }; + if (configuredProvider) { const unresolved = unresolvedWithoutFallback[0]; if (unresolved) { - const diagnostic: RuntimeWebDiagnostic = { - code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", - message: unresolved.reason, - path: unresolved.path, - }; - diagnostics.push(diagnostic); - searchMetadata.diagnostics.push(diagnostic); - pushWarning(params.context, { - code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", - path: unresolved.path, - message: unresolved.reason, - }); - throw new Error(`[WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK] ${unresolved.reason}`); + failUnresolvedSearchNoFallback(unresolved); } } else { if (!selectedProvider && unresolvedWithoutFallback.length > 0) { - const unresolved = unresolvedWithoutFallback[0]; - const diagnostic: RuntimeWebDiagnostic = { - code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", - message: unresolved.reason, - path: unresolved.path, - }; - diagnostics.push(diagnostic); - searchMetadata.diagnostics.push(diagnostic); - pushWarning(params.context, { - code: "WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK", - path: unresolved.path, - message: unresolved.reason, - }); - throw new Error(`[WEB_SEARCH_KEY_UNRESOLVED_NO_FALLBACK] ${unresolved.reason}`); + failUnresolvedSearchNoFallback(unresolvedWithoutFallback[0]); } if (selectedProvider) {