diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 00ef0768e..718bd5355 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -90,6 +90,11 @@ - Normalized resolved file paths in `read` summary recovery selectors, PDF image handles, and notebook errors so suffix-matched input does not teach agents malformed follow-up paths ([#7788](https://github.com/can1357/oh-my-pi/issues/7788)). +### Changed + +- Consolidated Exa web-search enablement on `exa.enabled`; legacy `exa.enableSearch` values migrate automatically, and the obsolete Researcher and Websets settings have been removed. +- Removed stale `computer.backend` values during config migration. + ## [17.2.9] - 2026-08-05 ### Breaking Changes diff --git a/packages/coding-agent/src/config/settings-schema.ts b/packages/coding-agent/src/config/settings-schema.ts index 0477a8b8f..3083aabd1 100644 --- a/packages/coding-agent/src/config/settings-schema.ts +++ b/packages/coding-agent/src/config/settings-schema.ts @@ -5406,19 +5406,13 @@ export const SETTINGS_SCHEMA = { // Exa "exa.enabled": { - type: "boolean", - default: true, - ui: { tab: "providers", group: "Services", label: "Exa", description: "Master toggle for all Exa search tools" }, - }, - - "exa.enableSearch": { type: "boolean", default: true, ui: { tab: "providers", group: "Services", - label: "Exa Search", - description: "Enable Exa basic search, deep search, code search, and crawl tools", + label: "Exa", + description: "Enable the Exa web search provider", }, }, @@ -5433,28 +5427,6 @@ export const SETTINGS_SCHEMA = { }, }, - "exa.enableResearcher": { - type: "boolean", - default: false, - ui: { - tab: "providers", - group: "Services", - label: "Exa Researcher", - description: "Enable the Exa researcher tool for AI-powered deep research", - }, - }, - - "exa.enableWebsets": { - type: "boolean", - default: false, - ui: { - tab: "providers", - group: "Services", - label: "Exa Websets", - description: "Enable Exa webset management and enrichment tools", - }, - }, - // SearXNG "searxng.endpoint": { type: "string", @@ -5794,10 +5766,7 @@ export interface TtsrSettings { export interface ExaSettings { enabled: boolean; - enableSearch: boolean; searchDelayMs: number; - enableResearcher: boolean; - enableWebsets: boolean; } export interface StatusLineSettings { diff --git a/packages/coding-agent/src/config/settings.ts b/packages/coding-agent/src/config/settings.ts index 5a8ec994b..a7b0553e4 100644 --- a/packages/coding-agent/src/config/settings.ts +++ b/packages/coding-agent/src/config/settings.ts @@ -1860,6 +1860,52 @@ export class Settings { : undefined, ); + // Consolidate the retired Exa suite toggles onto the sole remaining + // provider switch. The old runtime required both `enabled` and + // `enableSearch`, so preserve that AND semantics when both are present. + // Researcher and Websets were removed with the standalone Exa tools. + const exaObj = isRecord(raw.exa) ? raw.exa : undefined; + const exaEnabledValues = [ + exaObj?.enabled, + raw["exa.enabled"], + exaObj?.enableSearch, + raw["exa.enableSearch"], + ].filter((value): value is boolean => typeof value === "boolean"); + const hasFlatExaSetting = + "exa.enabled" in raw || + "exa.enableSearch" in raw || + "exa.enableResearcher" in raw || + "exa.enableWebsets" in raw; + if (exaObj || hasFlatExaSetting) { + const exaRoot = exaObj ?? {}; + if (exaEnabledValues.length > 0) { + exaRoot.enabled = exaEnabledValues.every(Boolean); + } + delete exaRoot.enableSearch; + delete exaRoot.enableResearcher; + delete exaRoot.enableWebsets; + if (Object.keys(exaRoot).length > 0) { + raw.exa = exaRoot; + } else { + delete raw.exa; + } + delete raw["exa.enabled"]; + delete raw["exa.enableSearch"]; + delete raw["exa.enableResearcher"]; + delete raw["exa.enableWebsets"]; + } + + // computer.backend and model-specific controller routing were removed + // when the computer tool moved to one native desktop implementation. + const computerObj = isRecord(raw.computer) ? raw.computer : undefined; + if (computerObj && "backend" in computerObj) { + delete computerObj.backend; + if (Object.keys(computerObj).length === 0) { + delete raw.computer; + } + } + delete raw["computer.backend"]; + return raw; } diff --git a/packages/coding-agent/src/web/search/providers/exa.ts b/packages/coding-agent/src/web/search/providers/exa.ts index 9c81d5317..37d628e32 100644 --- a/packages/coding-agent/src/web/search/providers/exa.ts +++ b/packages/coding-agent/src/web/search/providers/exa.ts @@ -464,7 +464,7 @@ export class ExaProvider extends SearchProvider { #settingsAllowSearch(): boolean { try { - if (settings.get("exa.enabled") === false || settings.get("exa.enableSearch") === false) { + if (settings.get("exa.enabled") === false) { return false; } } catch { diff --git a/packages/coding-agent/test/settings-manager.test.ts b/packages/coding-agent/test/settings-manager.test.ts index c9f6dfd83..2e15e69c8 100644 --- a/packages/coding-agent/test/settings-manager.test.ts +++ b/packages/coding-agent/test/settings-manager.test.ts @@ -919,6 +919,60 @@ describe("Settings", () => { }); describe("migrations", () => { + it("consolidates legacy Exa suite toggles onto exa.enabled", async () => { + await writeSettings({ + exa: { + enabled: true, + enableSearch: false, + enableResearcher: true, + enableWebsets: true, + }, + }); + + const settings = await Settings.init({ cwd: projectDir, agentDir }); + + expect(settings.get("exa.enabled")).toBe(false); + settings.set("display.showTokenUsage", true); + await settings.flush(); + expect((await readSettings()).exa).toEqual({ enabled: false }); + }); + + it("migrates quoted dotted Exa toggles and removes obsolete suite settings", async () => { + await Bun.write( + getConfigPath(), + `"exa.enabled": true\n"exa.enableSearch": false\n"exa.enableResearcher": true\n"exa.enableWebsets": true\n`, + ); + + const settings = await Settings.init({ cwd: projectDir, agentDir }); + + expect(settings.get("exa.enabled")).toBe(false); + settings.set("display.showTokenUsage", true); + await settings.flush(); + expect((await readSettings()).exa).toEqual({ enabled: false }); + }); + + it("removes the legacy Exa block when it contains only retired suite toggles", async () => { + await writeSettings({ exa: { enableResearcher: true, enableWebsets: true } }); + + const settings = await Settings.init({ cwd: projectDir, agentDir }); + + expect(settings.get("exa.enabled")).toBe(true); + settings.set("display.showTokenUsage", true); + await settings.flush(); + expect((await readSettings()).exa).toBeUndefined(); + }); + + it("removes the retired computer backend setting", async () => { + await writeSettings({ computer: { backend: "auto", enabled: true }, "computer.backend": "native" }); + + const settings = await Settings.init({ cwd: projectDir, agentDir }); + + expect(settings.get("computer.enabled")).toBe(true); + settings.set("display.showTokenUsage", true); + await settings.flush(); + expect((await readSettings()).computer).toEqual({ enabled: true }); + }); + it("maps removed atom edit mode settings to hashline", async () => { await writeSettings({ edit: {