Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions services/kiloclaw/controller/src/config-writer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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' };
Expand Down Expand Up @@ -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<string, string | undefined> = {
...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() };
Expand Down
16 changes: 14 additions & 2 deletions services/kiloclaw/controller/src/config-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Leaving the provider unset still allows Kilo Exa to win auto-detection

createKiloExaWebSearchProvider() is always registered and advertises envVars: ['KILOCODE_API_KEY'] with autoDetectOrder, and every KiloClaw machine has KILOCODE_API_KEY. In the Brave-configured case this branch now stops writing tools.web.search.provider, but it never explicitly selects brave or disables the customizer provider, so the runtime can still auto-select kilo-exa when the provider is missing. That means the restore/doctor path here does not reliably preserve Brave search despite the new regression tests passing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, this was valid.

I changed the unset-mode + Brave-configured path to explicitly prefer Brave (instead of leaving provider unset):

  • tools.web.search.provider = 'brave'
  • plugins.entries.kiloclaw-customizer.config.webSearch.enabled = false

Also updated regression tests for both normal and restore paths and re-ran:

  • pnpm -C services/kiloclaw test -- controller/src/config-writer.test.ts
  • pnpm typecheck
  • pnpm format

if (shouldForceExa || shouldAutoAssignExa) {
customizerWebSearchConfig.enabled = true;
config.tools = config.tools ?? {};
Expand All @@ -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)
Expand Down
Loading