mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-02 18:10:23 +00:00
feat(web-search): add SearXNG as bundled web search provider plugin (#57317)
* feat(web-search): add bundled searxng plugin * test(web-search): cover searxng config wiring * test(web-search): include searxng in bundled provider inventory * test(web-search): keep searxng ordering aligned * fix(web-search): sanitize searxng result rows --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -7,13 +7,21 @@ vi.mock("../runtime.js", () => ({
|
||||
|
||||
const getScopedWebSearchCredential = (key: string) => (search?: Record<string, unknown>) =>
|
||||
(search?.[key] as { apiKey?: unknown } | undefined)?.apiKey;
|
||||
const getConfiguredPluginWebSearchCredential =
|
||||
const getConfiguredPluginWebSearchConfig =
|
||||
(pluginId: string) => (config?: Record<string, unknown>) =>
|
||||
(
|
||||
config?.plugins as
|
||||
| { entries?: Record<string, { config?: { webSearch?: { apiKey?: unknown } } }> }
|
||||
| {
|
||||
entries?: Record<
|
||||
string,
|
||||
{ config?: { webSearch?: { apiKey?: unknown; baseUrl?: unknown } } }
|
||||
>;
|
||||
}
|
||||
| undefined
|
||||
)?.entries?.[pluginId]?.config?.webSearch?.apiKey;
|
||||
)?.entries?.[pluginId]?.config?.webSearch;
|
||||
const getConfiguredPluginWebSearchCredential =
|
||||
(pluginId: string) => (config?: Record<string, unknown>) =>
|
||||
getConfiguredPluginWebSearchConfig(pluginId)(config)?.apiKey;
|
||||
|
||||
const mockWebSearchProviders = [
|
||||
{
|
||||
@@ -58,6 +66,15 @@ const mockWebSearchProviders = [
|
||||
getCredentialValue: getScopedWebSearchCredential("perplexity"),
|
||||
getConfiguredCredentialValue: getConfiguredPluginWebSearchCredential("perplexity"),
|
||||
},
|
||||
{
|
||||
id: "searxng",
|
||||
envVars: ["SEARXNG_BASE_URL"],
|
||||
credentialPath: "plugins.entries.searxng.config.webSearch.baseUrl",
|
||||
getCredentialValue: (search?: Record<string, unknown>) =>
|
||||
(search?.searxng as { baseUrl?: unknown } | undefined)?.baseUrl,
|
||||
getConfiguredCredentialValue: (config?: Record<string, unknown>) =>
|
||||
getConfiguredPluginWebSearchConfig("searxng")(config)?.baseUrl,
|
||||
},
|
||||
{
|
||||
id: "tavily",
|
||||
envVars: ["TAVILY_API_KEY"],
|
||||
@@ -179,6 +196,24 @@ describe("web search provider config", () => {
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts searxng provider config on the plugin-owned path", () => {
|
||||
const res = validateConfigObjectWithPlugins(
|
||||
buildWebSearchProviderConfig({
|
||||
enabled: true,
|
||||
provider: "searxng",
|
||||
providerConfig: {
|
||||
baseUrl: {
|
||||
source: "env",
|
||||
provider: "default",
|
||||
id: "SEARXNG_BASE_URL",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(res.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects legacy scoped Tavily config", () => {
|
||||
const res = validateConfigObjectWithPlugins({
|
||||
tools: {
|
||||
@@ -261,6 +296,7 @@ describe("web search provider auto-detection", () => {
|
||||
delete process.env.MOONSHOT_API_KEY;
|
||||
delete process.env.PERPLEXITY_API_KEY;
|
||||
delete process.env.OPENROUTER_API_KEY;
|
||||
delete process.env.SEARXNG_BASE_URL;
|
||||
delete process.env.TAVILY_API_KEY;
|
||||
delete process.env.XAI_API_KEY;
|
||||
delete process.env.KIMI_API_KEY;
|
||||
@@ -296,6 +332,11 @@ describe("web search provider auto-detection", () => {
|
||||
expect(resolveSearchProvider({})).toBe("firecrawl");
|
||||
});
|
||||
|
||||
it("auto-detects searxng when only SEARXNG_BASE_URL is set", () => {
|
||||
process.env.SEARXNG_BASE_URL = "http://localhost:8080";
|
||||
expect(resolveSearchProvider({})).toBe("searxng");
|
||||
});
|
||||
|
||||
it("auto-detects kimi when only KIMI_API_KEY is set", () => {
|
||||
process.env.KIMI_API_KEY = "test-kimi-key"; // pragma: allowlist secret
|
||||
expect(resolveSearchProvider({})).toBe("kimi");
|
||||
|
||||
@@ -11,6 +11,7 @@ const EXPECTED_BUNDLED_WEB_SEARCH_PROVIDER_KEYS = [
|
||||
"xai:grok",
|
||||
"moonshot:kimi",
|
||||
"perplexity:perplexity",
|
||||
"searxng:searxng",
|
||||
"tavily:tavily",
|
||||
] as const;
|
||||
const EXPECTED_BUNDLED_WEB_SEARCH_PROVIDER_PLUGIN_IDS = [
|
||||
@@ -22,6 +23,7 @@ const EXPECTED_BUNDLED_WEB_SEARCH_PROVIDER_PLUGIN_IDS = [
|
||||
"xai",
|
||||
"moonshot",
|
||||
"perplexity",
|
||||
"searxng",
|
||||
"tavily",
|
||||
] as const;
|
||||
const EXPECTED_BUNDLED_WEB_SEARCH_CREDENTIAL_PATHS = [
|
||||
@@ -33,6 +35,7 @@ const EXPECTED_BUNDLED_WEB_SEARCH_CREDENTIAL_PATHS = [
|
||||
"plugins.entries.xai.config.webSearch.apiKey",
|
||||
"plugins.entries.moonshot.config.webSearch.apiKey",
|
||||
"plugins.entries.perplexity.config.webSearch.apiKey",
|
||||
"plugins.entries.searxng.config.webSearch.baseUrl",
|
||||
"plugins.entries.tavily.config.webSearch.apiKey",
|
||||
] as const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user