diff --git a/packages/core/src/v1/config/config.ts b/packages/core/src/v1/config/config.ts index bd9baab123..0ef9d1ffc7 100644 --- a/packages/core/src/v1/config/config.ts +++ b/packages/core/src/v1/config/config.ts @@ -227,7 +227,8 @@ export const Info = Schema.Struct({ permission: Schema.optional(ConfigPermissionV1.Info), tools: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)), web_search: Schema.optional(Schema.Boolean).annotate({ - description: "Make web search available to models from all providers", + description: + "Make web search available to models from all providers (default: true). Set to false to limit it to managed providers.", }), // kilocode_change attachment: Schema.optional(ConfigAttachmentV1.Info).annotate({ description: "Attachment processing configuration, including image size limits and resizing behavior", diff --git a/packages/kilo-console/src/routes/config/ToolsRoute.tsx b/packages/kilo-console/src/routes/config/ToolsRoute.tsx index 9dcb20b6e0..fae54f6b8c 100644 --- a/packages/kilo-console/src/routes/config/ToolsRoute.tsx +++ b/packages/kilo-console/src/routes/config/ToolsRoute.tsx @@ -12,7 +12,7 @@ export function ToolsRoute() { const [search, setSearch] = createSignal("") const snap = () => ctx.data() const websearch = createMemo(() => snap()?.overlay.fields.web_search) - const searchEnabled = createMemo(() => websearch()?.value === true) + const searchEnabled = createMemo(() => websearch()?.value !== false) const rows = createMemo(() => { const data = snap() if (!data) return [] diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx index fabc7858b8..ca870fef21 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/BrowserTab.tsx @@ -86,7 +86,7 @@ const BrowserTab: Component = () => { description={t("settings.webTools.webSearch.description")} last > - + {t("settings.webTools.webSearch.title")} diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 4df567dd6b..4f7c275cfa 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -377,7 +377,7 @@ export const layer: Layer.Layer< const filtered = (yield* all()).filter((tool) => { if (!KiloToolRegistry.available(tool, input.agent)) return false // kilocode_change if (tool.id === WebSearchTool.id) { - if (cfg.web_search === true) return true // kilocode_change + if (cfg.web_search !== false) return true // kilocode_change return webSearchEnabled(input.providerID, { exa: flags.enableExa, parallel: flags.enableParallel }) } diff --git a/packages/opencode/test/kilocode/config/config.test.ts b/packages/opencode/test/kilocode/config/config.test.ts index 51902e1514..3938950306 100644 --- a/packages/opencode/test/kilocode/config/config.test.ts +++ b/packages/opencode/test/kilocode/config/config.test.ts @@ -152,10 +152,10 @@ describe("global config updates", () => { }) describe("kilocode web search config", () => { - test("accepts the websearch availability setting", () => { - const config = Schema.decodeUnknownSync(Config.Info)({ web_search: true }) + test("accepts explicitly limiting web search to managed providers", () => { + const config = Schema.decodeUnknownSync(Config.Info)({ web_search: false }) - expect(config.web_search).toBe(true) + expect(config.web_search).toBe(false) }) }) diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts index 97e4e6c51c..2420506b9d 100644 --- a/packages/opencode/test/tool/registry.test.ts +++ b/packages/opencode/test/tool/registry.test.ts @@ -125,7 +125,21 @@ const websearch = testEffect( config: { get: () => Effect.succeed({ - web_search: true, + provider: { openai: { options: { apiKey: "test-openai-key" } } }, + }), + }, + }), + node, + Agent.defaultLayer, + ), +) +const websearchOff = testEffect( + Layer.mergeAll( + registryLayer({ + config: { + get: () => + Effect.succeed({ + web_search: false, provider: { openai: { options: { apiKey: "test-openai-key" } } }, }), }, @@ -155,23 +169,7 @@ function sandboxProfile(): Profile { describe("tool.registry", () => { // kilocode_change start - it.instance("hides websearch for a third-party provider by default", () => - Effect.gen(function* () { - const registry = yield* ToolRegistry.Service - const agent = yield* Agent.Service - const build = yield* agent.get("build") - if (!build) return yield* Effect.die(new Error("build agent not found")) - const tools = yield* registry.tools({ - providerID: ProviderV2.ID.openai, - modelID: ModelV2.ID.make("test"), - agent: build, - }) - - expect(tools.map((tool) => tool.id)).not.toContain("websearch") - }), - ) - - websearch.instance("shows websearch for a configured third-party provider when enabled", () => + websearch.instance("shows websearch by default for a configured third-party provider", () => Effect.gen(function* () { const registry = yield* ToolRegistry.Service const agent = yield* Agent.Service @@ -187,6 +185,22 @@ describe("tool.registry", () => { }), ) + websearchOff.instance("hides websearch for a configured third-party provider when disabled", () => + Effect.gen(function* () { + const registry = yield* ToolRegistry.Service + const agent = yield* Agent.Service + const build = yield* agent.get("build") + if (!build) return yield* Effect.die(new Error("build agent not found")) + const tools = yield* registry.tools({ + providerID: ProviderV2.ID.openai, + modelID: ModelV2.ID.make("test"), + agent: build, + }) + + expect(tools.map((tool) => tool.id)).not.toContain("websearch") + }), + ) + sandboxed.instance("preserves built-in network classification through production tool definition processing", () => Effect.gen(function* () { const registry = yield* ToolRegistry.Service