Commit ecb56bc9afe2

Vincent Demeester <vincent@sbr.pm>
2026-03-23 23:10:41
feat(pi-search): add engines parameter for SearXNG
Added optional engines param to web_search tool to target specific SearXNG backends (e.g. engines='google,wikipedia').
1 parent f4e26be
Changed files (2)
dots
pi
agent
extensions
dots/pi/agent/extensions/search/backends.ts
@@ -13,7 +13,7 @@ export interface SearchResult {
 
 export interface SearchBackend {
   name: string;
-  search(query: string, maxResults: number, signal?: AbortSignal): Promise<SearchResult[]>;
+  search(query: string, maxResults: number, signal?: AbortSignal, engines?: string): Promise<SearchResult[]>;
   isAvailable(): Promise<boolean>;
 }
 
@@ -40,8 +40,11 @@ export class SearXNGBackend implements SearchBackend {
     }
   }
 
-  async search(query: string, maxResults: number, signal?: AbortSignal): Promise<SearchResult[]> {
-    const url = `${this.baseUrl}/search?q=${encodeURIComponent(query)}&format=json`;
+  async search(query: string, maxResults: number, signal?: AbortSignal, engines?: string): Promise<SearchResult[]> {
+    let url = `${this.baseUrl}/search?q=${encodeURIComponent(query)}&format=json`;
+    if (engines) {
+      url += `&engines=${encodeURIComponent(engines)}`;
+    }
     const response = await fetch(url, { signal });
 
     if (!response.ok) {
@@ -158,12 +161,13 @@ export async function searchWithFallback(
   query: string,
   maxResults: number,
   signal?: AbortSignal,
+  engines?: string,
 ): Promise<{ results: SearchResult[]; backend: string; errors: string[] }> {
   const errors: string[] = [];
 
   for (const backend of backends) {
     try {
-      const results = await backend.search(query, maxResults, signal);
+      const results = await backend.search(query, maxResults, signal, engines);
       return { results, backend: backend.name, errors };
     } catch (e: any) {
       errors.push(`${backend.name}: ${e.message}`);
dots/pi/agent/extensions/search/index.ts
@@ -101,6 +101,7 @@ export default function (pi: ExtensionAPI) {
     parameters: Type.Object({
       query: Type.String({ description: "The search query." }),
       limit: Type.Optional(Type.Number({ description: "Maximum number of results (default 10)" })),
+      engines: Type.Optional(Type.String({ description: "Comma-separated list of SearXNG engines to use (e.g. 'google,wikipedia'). Only applies to SearXNG backend." })),
     }),
     renderCall(args, theme) {
       let text = theme.fg("toolTitle", theme.bold("web_search "));
@@ -131,6 +132,7 @@ export default function (pi: ExtensionAPI) {
           params.query,
           maxResults,
           signal,
+          params.engines,
         );
 
         if (results.length === 0) {