diff --git a/services/kiloclaw/controller/src/config-writer.test.ts b/services/kiloclaw/controller/src/config-writer.test.ts index c371d9ddc..f75dcb9d7 100644 --- a/services/kiloclaw/controller/src/config-writer.test.ts +++ b/services/kiloclaw/controller/src/config-writer.test.ts @@ -169,6 +169,20 @@ describe('generateBaseConfig', () => { expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(true); }); + it('prefers brave when provider is missing and Brave is configured', () => { + const existing = JSON.stringify({ tools: { web: { search: {} } } }); + const { deps } = fakeDeps(existing); + const env = { + ...minimalEnv(), + BRAVE_API_KEY: 'BSA' + 'A'.repeat(20), + }; + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); + + expect(config.tools.web.search.provider).toBe('brave'); + expect(config.tools.web.search.enabled).toBe(true); + expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(false); + }); + it('auto-assigns kilo-exa even when web search was explicitly disabled but provider is missing', () => { const existing = JSON.stringify({ tools: { @@ -204,6 +218,27 @@ describe('generateBaseConfig', () => { expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(true); }); + it('preserves explicit custom provider when mode is unset and Brave is configured', () => { + const existing = JSON.stringify({ + tools: { + web: { + search: { + provider: 'custom-provider', + }, + }, + }, + }); + const { deps } = fakeDeps(existing); + const env = { + ...minimalEnv(), + BRAVE_API_KEY: 'BSA' + 'A'.repeat(20), + }; + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); + + expect(config.tools.web.search.provider).toBe('custom-provider'); + expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(false); + }); + it('selects kilo-exa provider when KILO_EXA_SEARCH_MODE=kilo-proxy', () => { const { deps } = fakeDeps(); const env = { ...minimalEnv(), KILO_EXA_SEARCH_MODE: 'kilo-proxy' }; @@ -1375,6 +1410,21 @@ describe('writeBaseConfig', () => { expect(config.tools?.web?.search?.enabled).toBe(true); }); + it('prefers Brave on restore path when provider is missing and Brave is configured', () => { + const { deps, written } = fakeDeps(); + const env: Record = { + ...minimalEnv(), + BRAVE_API_KEY: 'BSA' + 'A'.repeat(20), + }; + delete env.KILOCLAW_FRESH_INSTALL; + + writeBaseConfig(env, '/tmp/openclaw.json', deps); + + const config = JSON.parse(written[0].data); + expect(config.tools?.web?.search?.provider).toBe('brave'); + expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(false); + }); + it('throws if KILOCODE_API_KEY is missing', () => { const { deps } = fakeDeps(); const env = { ...minimalEnv() }; diff --git a/services/kiloclaw/controller/src/config-writer.ts b/services/kiloclaw/controller/src/config-writer.ts index 211ccd3b7..687173273 100644 --- a/services/kiloclaw/controller/src/config-writer.ts +++ b/services/kiloclaw/controller/src/config-writer.ts @@ -343,10 +343,16 @@ export function generateBaseConfig( const searchProvider = config.tools?.web?.search?.provider; const hasExplicitSearchProvider = typeof searchProvider === 'string' && searchProvider.trim().length > 0; + const braveConfigured = Boolean(env.BRAVE_API_KEY?.trim()); const kiloExaSearchMode = resolveKiloExaSearchMode(env.KILO_EXA_SEARCH_MODE); + // Only assign dashboard-managed defaults when provider is unset. + // Preserve any explicit provider value, including user-defined custom providers. const shouldForceExa = kiloExaSearchMode === 'kilo-proxy'; - const shouldAutoAssignExa = kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider; + const shouldPreferBrave = + kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && braveConfigured; + const shouldAutoAssignExa = + kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && !braveConfigured; if (shouldForceExa || shouldAutoAssignExa) { customizerWebSearchConfig.enabled = true; config.tools = config.tools ?? {}; @@ -357,10 +363,16 @@ export function generateBaseConfig( if (shouldAutoAssignExa) { console.log('[config-writer] Auto-assigned web search provider to kilo-exa (mode=unset)'); } + } else if (shouldPreferBrave) { + customizerWebSearchConfig.enabled = false; + config.tools = config.tools ?? {}; + config.tools.web = config.tools.web ?? {}; + config.tools.web.search = config.tools.web.search ?? {}; + config.tools.web.search.enabled = true; + config.tools.web.search.provider = 'brave'; } else if (kiloExaSearchMode === 'disabled') { customizerWebSearchConfig.enabled = false; - const braveConfigured = Boolean(env.BRAVE_API_KEY?.trim()); if ( braveConfigured && (!hasExplicitSearchProvider || config.tools?.web?.search?.provider === KILO_EXA_PROVIDER_ID)