{"version":3,"file":"searchapi.cjs","names":["Tool"],"sources":["../../src/tools/searchapi.ts"],"sourcesContent":["import { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport { Tool } from \"@langchain/core/tools\";\n\ntype JSONPrimitive = string | number | boolean | null;\ntype JSONValue = JSONPrimitive | JSONObject | JSONArray;\ninterface JSONObject {\n  [key: string]: JSONValue;\n}\ninterface JSONArray extends Array<JSONValue> {}\n\nfunction isJSONObject(value: JSONValue): value is JSONObject {\n  return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * SearchApiParameters Type Definition.\n *\n * For more parameters and supported search engines, refer specific engine documentation:\n * Google - https://www.searchapi.io/docs/google\n * Google News - https://www.searchapi.io/docs/google-news\n * Google Scholar - https://www.searchapi.io/docs/google-scholar\n * YouTube Transcripts - https://www.searchapi.io/docs/youtube-transcripts\n * and others.\n *\n */\nexport type SearchApiParameters = {\n  [key: string]: JSONValue;\n};\n\n/**\n * SearchApi Class Definition.\n *\n * Provides a wrapper around the SearchApi.\n *\n * Ensure you've set the SEARCHAPI_API_KEY environment variable for authentication.\n * You can obtain a free API key from https://www.searchapi.io/.\n * @example\n * ```typescript\n * const searchApi = new SearchApi(\"your-api-key\", {\n *   engine: \"google_news\",\n * });\n * const agent = RunnableSequence.from([\n *   ChatPromptTemplate.fromMessages([\n *     [\"ai\", \"Answer the following questions using a bulleted list markdown format.\"\"],\n *     [\"human\", \"{input}\"],\n *   ]),\n *   new ChatOpenAI({ model: \"gpt-4o-mini\", temperature: 0 }),\n *   (input: BaseMessageChunk) => ({\n *     log: \"test\",\n *     returnValues: {\n *       output: input,\n *     },\n *   }),\n * ]);\n * const executor = AgentExecutor.fromAgentAndTools({\n *   agent,\n *   tools: [searchApi],\n * });\n * const res = await executor.invoke({\n *   input: \"What's happening in Ukraine today?\"\",\n * });\n * console.log(res);\n * ```\n */\nexport class SearchApi extends Tool {\n  static lc_name() {\n    return \"SearchApi\";\n  }\n\n  /**\n   * Converts the SearchApi instance to JSON. This method is not implemented\n   * and will throw an error if called.\n   * @returns Throws an error.\n   */\n  toJSON() {\n    return this.toJSONNotImplemented();\n  }\n\n  protected apiKey: string;\n\n  protected params: Partial<SearchApiParameters>;\n\n  constructor(\n    apiKey: string | undefined = getEnvironmentVariable(\"SEARCHAPI_API_KEY\"),\n    params: Partial<SearchApiParameters> = {}\n  ) {\n    super(...arguments);\n\n    if (!apiKey) {\n      throw new Error(\n        \"SearchApi requires an API key. Please set it as SEARCHAPI_API_KEY in your .env file, or pass it as a parameter to the SearchApi constructor.\"\n      );\n    }\n\n    this.apiKey = apiKey;\n    this.params = params;\n  }\n\n  name = \"search\";\n\n  /**\n   * Builds a URL for the SearchApi request.\n   * @param parameters The parameters for the request.\n   * @returns A string representing the built URL.\n   */\n  protected buildUrl(searchQuery: string): string {\n    const preparedParams: [string, string][] = Object.entries({\n      engine: \"google\",\n      api_key: this.apiKey,\n      ...this.params,\n      q: searchQuery,\n    })\n      .filter(\n        ([key, value]) =>\n          value !== undefined && value !== null && key !== \"apiKey\"\n      )\n      .map(([key, value]) => [key, `${value}`]);\n\n    const searchParams = new URLSearchParams(preparedParams);\n    return `https://www.searchapi.io/api/v1/search?${searchParams}`;\n  }\n\n  /** @ignore */\n  /**\n   * Calls the SearchAPI.\n   *\n   * Accepts an input query and fetches the result from SearchApi.\n   *\n   * @param {string} input - Search query.\n   * @returns {string} - Formatted search results or an error message.\n   *\n   * NOTE: This method is the core search handler and processes various types\n   * of search results including Google organic results, videos, jobs, and images.\n   */\n  async _call(input: string) {\n    const resp = await fetch(this.buildUrl(input));\n\n    const json = await resp.json();\n\n    if (json.error) {\n      throw new Error(\n        `Failed to load search results from SearchApi due to: ${json.error}`\n      );\n    }\n\n    // Google Search results\n    if (json.answer_box?.answer) {\n      return json.answer_box.answer;\n    }\n\n    if (json.answer_box?.snippet) {\n      return json.answer_box.snippet;\n    }\n\n    if (json.knowledge_graph?.description) {\n      return json.knowledge_graph.description;\n    }\n\n    // Organic results (Google, Google News)\n    if (json.organic_results) {\n      const snippets = json.organic_results\n        .filter((r: JSONObject) => r.snippet)\n        .map((r: JSONObject) => r.snippet);\n      return snippets.join(\"\\n\");\n    }\n\n    // Google Jobs results\n    if (json.jobs) {\n      const jobDescriptions = json.jobs\n        .slice(0, 1)\n        .filter((r: JSONObject) => r.description)\n        .map((r: JSONObject) => r.description);\n      return jobDescriptions.join(\"\\n\");\n    }\n\n    // Google Videos results\n    if (json.videos) {\n      const videoInfo = json.videos\n        .filter((r: JSONObject) => r.title && r.link)\n        .map((r: JSONObject) => `Title: \"${r.title}\" Link: ${r.link}`);\n      return videoInfo.join(\"\\n\");\n    }\n\n    // Google Images results\n    if (json.images) {\n      const image_results = json.images.slice(0, 15);\n      const imageInfo = image_results\n        .filter(\n          (r: JSONObject) =>\n            r.title && r.original && isJSONObject(r.original) && r.original.link\n        )\n        .map(\n          (r: JSONObject) =>\n            `Title: \"${r.title}\" Link: ${(r.original as JSONObject).link}`\n        );\n      return imageInfo.join(\"\\n\");\n    }\n\n    return \"No good search result found\";\n  }\n\n  description =\n    \"a search engine. useful for when you need to answer questions about current events. input should be a search query.\";\n}\n"],"mappings":";;;;;;AAUA,SAAS,aAAa,OAAuC;AAC3D,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqD7E,IAAa,YAAb,cAA+BA,sBAAAA,KAAK;CAClC,OAAO,UAAU;AACf,SAAO;;;;;;;CAQT,SAAS;AACP,SAAO,KAAK,sBAAsB;;CAGpC;CAEA;CAEA,YACE,UAAA,GAAA,0BAAA,wBAAoD,oBAAoB,EACxE,SAAuC,EAAE,EACzC;AACA,QAAM,GAAG,UAAU;AAEnB,MAAI,CAAC,OACH,OAAM,IAAI,MACR,+IACD;AAGH,OAAK,SAAS;AACd,OAAK,SAAS;;CAGhB,OAAO;;;;;;CAOP,SAAmB,aAA6B;EAC9C,MAAM,iBAAqC,OAAO,QAAQ;GACxD,QAAQ;GACR,SAAS,KAAK;GACd,GAAG,KAAK;GACR,GAAG;GACJ,CAAC,CACC,QACE,CAAC,KAAK,WACL,UAAU,KAAA,KAAa,UAAU,QAAQ,QAAQ,SACpD,CACA,KAAK,CAAC,KAAK,WAAW,CAAC,KAAK,GAAG,QAAQ,CAAC;AAG3C,SAAO,0CADc,IAAI,gBAAgB,eAAe;;;;;;;;;;;;;;CAgB1D,MAAM,MAAM,OAAe;EAGzB,MAAM,OAAO,OAFA,MAAM,MAAM,KAAK,SAAS,MAAM,CAAC,EAEtB,MAAM;AAE9B,MAAI,KAAK,MACP,OAAM,IAAI,MACR,wDAAwD,KAAK,QAC9D;AAIH,MAAI,KAAK,YAAY,OACnB,QAAO,KAAK,WAAW;AAGzB,MAAI,KAAK,YAAY,QACnB,QAAO,KAAK,WAAW;AAGzB,MAAI,KAAK,iBAAiB,YACxB,QAAO,KAAK,gBAAgB;AAI9B,MAAI,KAAK,gBAIP,QAHiB,KAAK,gBACnB,QAAQ,MAAkB,EAAE,QAAQ,CACpC,KAAK,MAAkB,EAAE,QAAQ,CACpB,KAAK,KAAK;AAI5B,MAAI,KAAK,KAKP,QAJwB,KAAK,KAC1B,MAAM,GAAG,EAAE,CACX,QAAQ,MAAkB,EAAE,YAAY,CACxC,KAAK,MAAkB,EAAE,YAAY,CACjB,KAAK,KAAK;AAInC,MAAI,KAAK,OAIP,QAHkB,KAAK,OACpB,QAAQ,MAAkB,EAAE,SAAS,EAAE,KAAK,CAC5C,KAAK,MAAkB,WAAW,EAAE,MAAM,UAAU,EAAE,OAAO,CAC/C,KAAK,KAAK;AAI7B,MAAI,KAAK,OAWP,QAVsB,KAAK,OAAO,MAAM,GAAG,GAAG,CAE3C,QACE,MACC,EAAE,SAAS,EAAE,YAAY,aAAa,EAAE,SAAS,IAAI,EAAE,SAAS,KACnE,CACA,KACE,MACC,WAAW,EAAE,MAAM,UAAW,EAAE,SAAwB,OAC3D,CACc,KAAK,KAAK;AAG7B,SAAO;;CAGT,cACE"}