From 302cf3bb76e497d36ea7caec9a0cef66e2a47028 Mon Sep 17 00:00:00 2001 From: tanzhenxin Date: Mon, 20 Jul 2026 01:55:35 +0000 Subject: [PATCH] fix(cli): treat whitespace-only WEB_SEARCH_API_KEY as unset Apply the function's set-but-empty-is-unset rule to the API key env var like every sibling env read, and add loadCliConfig coverage for the web search settings resolution (env precedence, empty-env fallthrough, base-URL key selection). --- packages/cli/src/config/config.test.ts | 90 ++++++++++++++++++++++++++ packages/cli/src/config/config.ts | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index cdc122205e..d24906fa47 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -1691,6 +1691,96 @@ describe('loadCliConfig', () => { expect(config.getProxy()).toBe('http://localhost:7890'); }); }); + + describe('web search settings resolution', () => { + const loadWithSettings = async (settings: Settings) => { + process.argv = ['node', 'script.js']; + const argv = await parseArguments(); + return loadCliConfig(settings, argv); + }; + + it('returns undefined when neither settings nor env configure web search', async () => { + const config = await loadWithSettings({}); + expect(config.getWebSearchSettings()).toBeUndefined(); + }); + + it('passes tools.webSearch through from settings', async () => { + const config = await loadWithSettings({ + tools: { webSearch: { enabled: true, model: 'qwen3.6-plus' } }, + }); + expect(config.getWebSearchSettings()).toEqual({ + enabled: true, + model: 'qwen3.6-plus', + }); + }); + + it('lets ENABLE_WEB_SEARCH override the settings flag', async () => { + vi.stubEnv('ENABLE_WEB_SEARCH', 'false'); + const config = await loadWithSettings({ + tools: { webSearch: { enabled: true, model: 'qwen3.6-plus' } }, + }); + expect(config.getWebSearchSettings()?.enabled).toBe(false); + }); + + it('treats a set-but-empty ENABLE_WEB_SEARCH as unset', async () => { + vi.stubEnv('ENABLE_WEB_SEARCH', ''); + const config = await loadWithSettings({ + tools: { webSearch: { enabled: true, model: 'qwen3.6-plus' } }, + }); + expect(config.getWebSearchSettings()?.enabled).toBe(true); + }); + + it('lets WEB_SEARCH_MODEL and WEB_SEARCH_EXTRACTOR override settings', async () => { + vi.stubEnv('WEB_SEARCH_MODEL', 'env-model'); + vi.stubEnv('WEB_SEARCH_EXTRACTOR', 'false'); + const config = await loadWithSettings({ + tools: { + webSearch: { enabled: true, model: 'settings-model' }, + }, + }); + expect(config.getWebSearchSettings()).toEqual({ + enabled: true, + model: 'env-model', + webExtractor: false, + }); + }); + + it('resolves WEB_SEARCH_BASE_URL with the DASHSCOPE_API_KEY fallback', async () => { + vi.stubEnv( + 'WEB_SEARCH_BASE_URL', + 'https://dashscope.aliyuncs.com/api/v2', + ); + const config = await loadWithSettings({}); + expect(config.getWebSearchSettings()).toEqual({ + baseUrl: 'https://dashscope.aliyuncs.com/api/v2', + apiKeyEnv: 'DASHSCOPE_API_KEY', + }); + }); + + it('selects WEB_SEARCH_API_KEY when it is non-empty', async () => { + vi.stubEnv( + 'WEB_SEARCH_BASE_URL', + 'https://dashscope.aliyuncs.com/api/v2', + ); + vi.stubEnv('WEB_SEARCH_API_KEY', 'sk-live'); + const config = await loadWithSettings({}); + expect(config.getWebSearchSettings()?.apiKeyEnv).toBe( + 'WEB_SEARCH_API_KEY', + ); + }); + + it('treats a whitespace-only WEB_SEARCH_API_KEY as unset', async () => { + vi.stubEnv( + 'WEB_SEARCH_BASE_URL', + 'https://dashscope.aliyuncs.com/api/v2', + ); + vi.stubEnv('WEB_SEARCH_API_KEY', ' '); + const config = await loadWithSettings({}); + expect(config.getWebSearchSettings()?.apiKeyEnv).toBe( + 'DASHSCOPE_API_KEY', + ); + }); + }); }); describe('loadCliConfig telemetry', () => { diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 0b715c8f1b..95d0adbba9 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -1257,7 +1257,7 @@ function resolveWebSearchSettings( : webSearch?.webExtractor; const baseUrl = process.env['WEB_SEARCH_BASE_URL']?.trim() || undefined; const apiKeyEnv = baseUrl - ? process.env['WEB_SEARCH_API_KEY'] + ? process.env['WEB_SEARCH_API_KEY']?.trim() ? 'WEB_SEARCH_API_KEY' : 'DASHSCOPE_API_KEY' : undefined;