diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b6966bfa..d5a0971e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ Docs: https://docs.clawd.bot - Gateway: strip inbound envelope headers from chat history messages to keep clients clean. - UI: prevent double-scroll in Control UI chat by locking chat layout to the viewport. (#1283) — thanks @bradleypriest. +### Fixes +- Config: allow Perplexity as a web_search provider in config validation. (#1230) + ## 2026.1.19-2 ### Changes diff --git a/src/config/config.web-search-provider.test.ts b/src/config/config.web-search-provider.test.ts new file mode 100644 index 000000000..a91c0f438 --- /dev/null +++ b/src/config/config.web-search-provider.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "vitest"; + +import { validateConfigObject } from "./config.js"; + +describe("web search provider config", () => { + it("accepts perplexity provider and config", () => { + const res = validateConfigObject({ + tools: { + web: { + search: { + enabled: true, + provider: "perplexity", + perplexity: { + apiKey: "test-key", + baseUrl: "https://api.perplexity.ai", + model: "perplexity/sonar-pro", + }, + }, + }, + }, + }); + + expect(res.ok).toBe(true); + }); +}); diff --git a/src/config/schema.ts b/src/config/schema.ts index 52d5200fb..9a3eff29e 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -349,12 +349,18 @@ const FIELD_HELP: Record = { "tools.message.crossContext.marker.suffix": 'Text suffix for cross-context markers (supports "{channel}").', "tools.message.broadcast.enabled": "Enable broadcast action (default: true).", - "tools.web.search.enabled": "Enable the web_search tool (requires Brave API key).", - "tools.web.search.provider": 'Search provider (only "brave" supported today).', + "tools.web.search.enabled": "Enable the web_search tool (requires a provider API key).", + "tools.web.search.provider": 'Search provider ("brave" or "perplexity").', "tools.web.search.apiKey": "Brave Search API key (fallback: BRAVE_API_KEY env var).", "tools.web.search.maxResults": "Default number of results to return (1-10).", "tools.web.search.timeoutSeconds": "Timeout in seconds for web_search requests.", "tools.web.search.cacheTtlMinutes": "Cache TTL in minutes for web_search results.", + "tools.web.search.perplexity.apiKey": + "Perplexity or OpenRouter API key (fallback: PERPLEXITY_API_KEY or OPENROUTER_API_KEY env var).", + "tools.web.search.perplexity.baseUrl": + "Perplexity base URL override (default: https://openrouter.ai/api/v1 or https://api.perplexity.ai).", + "tools.web.search.perplexity.model": + 'Perplexity model override (default: "perplexity/sonar-pro").', "tools.web.fetch.enabled": "Enable the web_fetch tool (lightweight HTTP fetch).", "tools.web.fetch.maxChars": "Max characters returned by web_fetch (truncated).", "tools.web.fetch.timeoutSeconds": "Timeout in seconds for web_fetch requests.", diff --git a/src/config/zod-schema.agent-runtime.ts b/src/config/zod-schema.agent-runtime.ts index 2c81510b8..537129acc 100644 --- a/src/config/zod-schema.agent-runtime.ts +++ b/src/config/zod-schema.agent-runtime.ts @@ -124,11 +124,19 @@ export const ToolPolicySchema = z export const ToolsWebSearchSchema = z .object({ enabled: z.boolean().optional(), - provider: z.union([z.literal("brave")]).optional(), + provider: z.union([z.literal("brave"), z.literal("perplexity")]).optional(), apiKey: z.string().optional(), maxResults: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), cacheTtlMinutes: z.number().nonnegative().optional(), + perplexity: z + .object({ + apiKey: z.string().optional(), + baseUrl: z.string().optional(), + model: z.string().optional(), + }) + .strict() + .optional(), }) .strict() .optional();