From 491979cab229e1305d03618947cfaf955aad1b61 Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:28:47 -0500 Subject: [PATCH 1/3] fix(kiloclaw): preserve Brave config on upgrade when provider is unset --- .../controller/src/config-writer.test.ts | 27 +++++++++++++++++++ .../kiloclaw/controller/src/config-writer.ts | 5 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/services/kiloclaw/controller/src/config-writer.test.ts b/services/kiloclaw/controller/src/config-writer.test.ts index c371d9ddc..99f5b9bf0 100644 --- a/services/kiloclaw/controller/src/config-writer.test.ts +++ b/services/kiloclaw/controller/src/config-writer.test.ts @@ -169,6 +169,19 @@ describe('generateBaseConfig', () => { expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(true); }); + it('does not auto-assign kilo-exa 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).toBeUndefined(); + expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBeUndefined(); + }); + it('auto-assigns kilo-exa even when web search was explicitly disabled but provider is missing', () => { const existing = JSON.stringify({ tools: { @@ -1375,6 +1388,20 @@ describe('writeBaseConfig', () => { expect(config.tools?.web?.search?.enabled).toBe(true); }); + it('does not auto-assign Exa on restore path when 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).toBeUndefined(); + }); + 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..07c2458b4 100644 --- a/services/kiloclaw/controller/src/config-writer.ts +++ b/services/kiloclaw/controller/src/config-writer.ts @@ -343,10 +343,12 @@ 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); const shouldForceExa = kiloExaSearchMode === 'kilo-proxy'; - const shouldAutoAssignExa = kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider; + const shouldAutoAssignExa = + kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && !braveConfigured; if (shouldForceExa || shouldAutoAssignExa) { customizerWebSearchConfig.enabled = true; config.tools = config.tools ?? {}; @@ -360,7 +362,6 @@ export function generateBaseConfig( } 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) From 727609e81350297d209d0461c7fb246f1aa748bf Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:51:45 -0500 Subject: [PATCH 2/3] fix(kiloclaw): prefer Brave when provider is unset --- .../kiloclaw/controller/src/config-writer.test.ts | 12 +++++++----- services/kiloclaw/controller/src/config-writer.ts | 9 +++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/services/kiloclaw/controller/src/config-writer.test.ts b/services/kiloclaw/controller/src/config-writer.test.ts index 99f5b9bf0..d4fc7df64 100644 --- a/services/kiloclaw/controller/src/config-writer.test.ts +++ b/services/kiloclaw/controller/src/config-writer.test.ts @@ -169,7 +169,7 @@ describe('generateBaseConfig', () => { expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBe(true); }); - it('does not auto-assign kilo-exa when provider is missing and Brave is configured', () => { + it('prefers brave when provider is missing and Brave is configured', () => { const existing = JSON.stringify({ tools: { web: { search: {} } } }); const { deps } = fakeDeps(existing); const env = { @@ -178,8 +178,9 @@ describe('generateBaseConfig', () => { }; const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); - expect(config.tools.web.search.provider).toBeUndefined(); - expect(config.plugins.entries['kiloclaw-customizer'].config.webSearch.enabled).toBeUndefined(); + 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', () => { @@ -1388,7 +1389,7 @@ describe('writeBaseConfig', () => { expect(config.tools?.web?.search?.enabled).toBe(true); }); - it('does not auto-assign Exa on restore path when Brave is configured', () => { + it('prefers Brave on restore path when provider is missing and Brave is configured', () => { const { deps, written } = fakeDeps(); const env: Record = { ...minimalEnv(), @@ -1399,7 +1400,8 @@ describe('writeBaseConfig', () => { writeBaseConfig(env, '/tmp/openclaw.json', deps); const config = JSON.parse(written[0].data); - expect(config.tools?.web?.search?.provider).toBeUndefined(); + 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', () => { diff --git a/services/kiloclaw/controller/src/config-writer.ts b/services/kiloclaw/controller/src/config-writer.ts index 07c2458b4..671d0ab21 100644 --- a/services/kiloclaw/controller/src/config-writer.ts +++ b/services/kiloclaw/controller/src/config-writer.ts @@ -347,6 +347,8 @@ export function generateBaseConfig( const kiloExaSearchMode = resolveKiloExaSearchMode(env.KILO_EXA_SEARCH_MODE); const shouldForceExa = kiloExaSearchMode === 'kilo-proxy'; + const shouldPreferBrave = + kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && braveConfigured; const shouldAutoAssignExa = kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && !braveConfigured; if (shouldForceExa || shouldAutoAssignExa) { @@ -359,6 +361,13 @@ 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; From a6cf6887a24c8a2cef9727d789d2f0e0355f7c4d Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:15:31 -0500 Subject: [PATCH 3/3] test(kiloclaw): preserve explicit custom search providers --- .../controller/src/config-writer.test.ts | 21 +++++++++++++++++++ .../kiloclaw/controller/src/config-writer.ts | 2 ++ 2 files changed, 23 insertions(+) diff --git a/services/kiloclaw/controller/src/config-writer.test.ts b/services/kiloclaw/controller/src/config-writer.test.ts index d4fc7df64..f75dcb9d7 100644 --- a/services/kiloclaw/controller/src/config-writer.test.ts +++ b/services/kiloclaw/controller/src/config-writer.test.ts @@ -218,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' }; diff --git a/services/kiloclaw/controller/src/config-writer.ts b/services/kiloclaw/controller/src/config-writer.ts index 671d0ab21..687173273 100644 --- a/services/kiloclaw/controller/src/config-writer.ts +++ b/services/kiloclaw/controller/src/config-writer.ts @@ -346,6 +346,8 @@ export function generateBaseConfig( 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 shouldPreferBrave = kiloExaSearchMode === 'unset' && !hasExplicitSearchProvider && braveConfigured;