@langchain/community
Version:
Third-party integrations for LangChain.js
1 lines • 9.33 kB
Source Map (JSON)
{"version":3,"file":"searxng_search.cjs","names":["Tool"],"sources":["../../src/tools/searxng_search.ts"],"sourcesContent":["import { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport { Tool } from \"@langchain/core/tools\";\n\n/**\n * Interface for the results returned by the Searxng search.\n */\ninterface SearxngResults {\n query: string;\n number_of_results: number;\n results: Array<{\n url: string;\n title: string;\n content: string;\n img_src: string;\n engine: string;\n parsed_url: Array<string>;\n template: string;\n engines: Array<string>;\n positions: Array<number>;\n score: number;\n category: string;\n pretty_url: string;\n open_group?: boolean;\n close_group?: boolean;\n }>;\n answers: Array<string>;\n corrections: Array<string>;\n infoboxes: Array<{\n infobox: string;\n content: string;\n engine: string;\n engines: Array<string>;\n }>;\n suggestions: Array<string>;\n unresponsive_engines: Array<string>;\n}\n\n/**\n * Interface for custom headers used in the Searxng search.\n */\ninterface SearxngCustomHeaders {\n [key: string]: string;\n}\n\ninterface SearxngSearchParams {\n /**\n * @default 10\n * Number of results included in results\n */\n numResults?: number;\n /** Comma separated list, specifies the active search categories\n * https://docs.searxng.org/user/configured_engines.html#configured-engines\n */\n categories?: string;\n\n /** Comma separated list, specifies the active search engines\n * https://docs.searxng.org/user/configured_engines.html#configured-engines\n */\n engines?: string;\n\n /** Code of the language. */\n language?: string;\n /** Search page number. */\n pageNumber?: number;\n /**\n * day / month / year\n *\n * Time range of search for engines which support it. See if an engine supports time range search in the preferences page of an instance.\n */\n timeRange?: number;\n\n /**\n * Throws Error if format is set anything other than \"json\"\n * Output format of results. Format needs to be activated in search:\n */\n format?: \"json\";\n /** Open search results on new tab. */\n resultsOnNewTab?: 0 | 1;\n /** Proxy image results through SearXNG. */\n imageProxy?: boolean;\n autocomplete?: string;\n /**\n * Filter search results of engines which support safe search. See if an engine supports safe search in the preferences page of an instance.\n */\n safesearch?: 0 | 1 | 2;\n}\n\n/**\n * SearxngSearch class represents a meta search engine tool.\n * Use this class when you need to answer questions about current events.\n * The input should be a search query, and the output is a JSON array of the query results.\n *\n * note: works best with *agentType*: `structured-chat-zero-shot-react-description`\n * https://github.com/searxng/searxng\n * @example\n * ```typescript\n * const executor = AgentExecutor.fromAgentAndTools({\n * agent,\n * tools: [\n * new SearxngSearch({\n * params: {\n * format: \"json\",\n * engines: \"google\",\n * },\n * headers: {},\n * }),\n * ],\n * });\n * const result = await executor.invoke({\n * input: `What is Langchain? Describe in 50 words`,\n * });\n * ```\n */\nexport class SearxngSearch extends Tool {\n static lc_name() {\n return \"SearxngSearch\";\n }\n\n name = \"searxng-search\";\n\n description =\n \"A meta search engine. Useful for when you need to answer questions about current events. Input should be a search query. Output is a JSON array of the query results\";\n\n protected apiBase?: string;\n\n protected params?: SearxngSearchParams = {\n numResults: 10,\n pageNumber: 1,\n format: \"json\",\n imageProxy: true,\n safesearch: 0,\n };\n\n protected headers?: SearxngCustomHeaders;\n\n get lc_secrets(): { [key: string]: string } | undefined {\n return {\n apiBase: \"SEARXNG_API_BASE\",\n };\n }\n\n /**\n * Constructor for the SearxngSearch class\n * @param apiBase Base URL of the Searxng instance\n * @param params SearxNG parameters\n * @param headers Custom headers\n */\n constructor({\n apiBase,\n params,\n headers,\n }: {\n /** Base URL of Searxng instance */\n apiBase?: string;\n\n /** SearxNG Paramerters\n *\n * https://docs.searxng.org/dev/search_api.html check here for more details\n */\n params?: SearxngSearchParams;\n\n /**\n * Custom headers\n * Set custom headers if you're using a api from RapidAPI (https://rapidapi.com/iamrony777/api/searxng)\n * No headers needed for a locally self-hosted instance\n */\n headers?: SearxngCustomHeaders;\n }) {\n super(...arguments);\n\n this.apiBase = getEnvironmentVariable(\"SEARXNG_API_BASE\") || apiBase;\n this.headers = { \"content-type\": \"application/json\", ...headers };\n\n if (!this.apiBase) {\n throw new Error(\n `SEARXNG_API_BASE not set. You can set it as \"SEARXNG_API_BASE\" in your environment variables.`\n );\n }\n\n if (params) {\n this.params = { ...this.params, ...params };\n }\n }\n\n /**\n * Builds the URL for the Searxng search.\n * @param path The path for the URL.\n * @param parameters The parameters for the URL.\n * @param baseUrl The base URL.\n * @returns The complete URL as a string.\n */\n protected buildUrl<P extends SearxngSearchParams>(\n path: string,\n parameters: P,\n baseUrl: string\n ): string {\n const nonUndefinedParams: [string, string][] = Object.entries(parameters)\n .filter(([_, value]) => value !== undefined)\n .map(([key, value]) => [key, value.toString()]); // Avoid string conversion\n const searchParams = new URLSearchParams(nonUndefinedParams);\n return `${baseUrl}/${path}?${searchParams}`;\n }\n\n async _call(input: string): Promise<string> {\n const queryParams = {\n q: input,\n ...this.params,\n };\n const url = this.buildUrl(\"search\", queryParams, this.apiBase as string);\n\n const resp = await fetch(url, {\n method: \"POST\",\n headers: this.headers,\n signal: AbortSignal.timeout(5 * 1000), // 5 seconds\n });\n\n if (!resp.ok) {\n throw new Error(resp.statusText);\n }\n\n const res: SearxngResults = await resp.json();\n\n if (\n !res.results.length &&\n !res.answers.length &&\n !res.infoboxes.length &&\n !res.suggestions.length\n ) {\n return \"No good results found.\";\n } else if (res.results.length) {\n const response: string[] = [];\n\n res.results.forEach((r) => {\n response.push(\n JSON.stringify({\n title: r.title || \"\",\n link: r.url || \"\",\n snippet: r.content || \"\",\n })\n );\n });\n\n return response.slice(0, this.params?.numResults).toString();\n } else if (res.answers.length) {\n return res.answers[0];\n } else if (res.infoboxes.length) {\n // Apply HTML tag stripping repeatedly until no more replacements occur\n // to prevent incomplete sanitization from crafted inputs like \"<scr<script>ipt>\"\n let content = res.infoboxes[0]?.content ?? \"\";\n let previous: string;\n do {\n previous = content;\n content = content.replace(/<[^>]+>/gi, \"\");\n } while (content !== previous);\n return content;\n } else if (res.suggestions.length) {\n let suggestions = \"Suggestions: \";\n res.suggestions.forEach((s) => {\n suggestions += `${s}, `;\n });\n return suggestions;\n } else {\n return \"No good results found.\";\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiHA,IAAa,gBAAb,cAAmCA,sBAAAA,KAAK;CACtC,OAAO,UAAU;AACf,SAAO;;CAGT,OAAO;CAEP,cACE;CAEF;CAEA,SAAyC;EACvC,YAAY;EACZ,YAAY;EACZ,QAAQ;EACR,YAAY;EACZ,YAAY;EACb;CAED;CAEA,IAAI,aAAoD;AACtD,SAAO,EACL,SAAS,oBACV;;;;;;;;CASH,YAAY,EACV,SACA,QACA,WAiBC;AACD,QAAM,GAAG,UAAU;AAEnB,OAAK,WAAA,GAAA,0BAAA,wBAAiC,mBAAmB,IAAI;AAC7D,OAAK,UAAU;GAAE,gBAAgB;GAAoB,GAAG;GAAS;AAEjE,MAAI,CAAC,KAAK,QACR,OAAM,IAAI,MACR,gGACD;AAGH,MAAI,OACF,MAAK,SAAS;GAAE,GAAG,KAAK;GAAQ,GAAG;GAAQ;;;;;;;;;CAW/C,SACE,MACA,YACA,SACQ;EACR,MAAM,qBAAyC,OAAO,QAAQ,WAAW,CACtE,QAAQ,CAAC,GAAG,WAAW,UAAU,KAAA,EAAU,CAC3C,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,UAAU,CAAC,CAAC;AAEjD,SAAO,GAAG,QAAQ,GAAG,KAAK,GADL,IAAI,gBAAgB,mBAAmB;;CAI9D,MAAM,MAAM,OAAgC;EAC1C,MAAM,cAAc;GAClB,GAAG;GACH,GAAG,KAAK;GACT;EACD,MAAM,MAAM,KAAK,SAAS,UAAU,aAAa,KAAK,QAAkB;EAExE,MAAM,OAAO,MAAM,MAAM,KAAK;GAC5B,QAAQ;GACR,SAAS,KAAK;GACd,QAAQ,YAAY,QAAQ,IAAI,IAAK;GACtC,CAAC;AAEF,MAAI,CAAC,KAAK,GACR,OAAM,IAAI,MAAM,KAAK,WAAW;EAGlC,MAAM,MAAsB,MAAM,KAAK,MAAM;AAE7C,MACE,CAAC,IAAI,QAAQ,UACb,CAAC,IAAI,QAAQ,UACb,CAAC,IAAI,UAAU,UACf,CAAC,IAAI,YAAY,OAEjB,QAAO;WACE,IAAI,QAAQ,QAAQ;GAC7B,MAAM,WAAqB,EAAE;AAE7B,OAAI,QAAQ,SAAS,MAAM;AACzB,aAAS,KACP,KAAK,UAAU;KACb,OAAO,EAAE,SAAS;KAClB,MAAM,EAAE,OAAO;KACf,SAAS,EAAE,WAAW;KACvB,CAAC,CACH;KACD;AAEF,UAAO,SAAS,MAAM,GAAG,KAAK,QAAQ,WAAW,CAAC,UAAU;aACnD,IAAI,QAAQ,OACrB,QAAO,IAAI,QAAQ;WACV,IAAI,UAAU,QAAQ;GAG/B,IAAI,UAAU,IAAI,UAAU,IAAI,WAAW;GAC3C,IAAI;AACJ,MAAG;AACD,eAAW;AACX,cAAU,QAAQ,QAAQ,aAAa,GAAG;YACnC,YAAY;AACrB,UAAO;aACE,IAAI,YAAY,QAAQ;GACjC,IAAI,cAAc;AAClB,OAAI,YAAY,SAAS,MAAM;AAC7B,mBAAe,GAAG,EAAE;KACpB;AACF,UAAO;QAEP,QAAO"}