{"version":3,"file":"searchapi.cjs","names":["value: JSONValue","Tool","apiKey: string | undefined","params: Partial<SearchApiParameters>","searchQuery: string","preparedParams: [string, string][]","input: string","r: JSONObject"],"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,aAAaA,OAAuC;AAC3D,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;AAC5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDD,IAAa,YAAb,cAA+BC,4BAAK;CAClC,OAAO,UAAU;AACf,SAAO;CACR;;;;;;CAOD,SAAS;AACP,SAAO,KAAK,sBAAsB;CACnC;CAED,AAAU;CAEV,AAAU;CAEV,YACEC,gEAAoD,oBAAoB,EACxEC,SAAuC,CAAE,GACzC;EACA,MAAM,GAAG,UAAU;AAEnB,MAAI,CAAC,OACH,OAAM,IAAI,MACR;EAIJ,KAAK,SAAS;EACd,KAAK,SAAS;CACf;CAED,OAAO;;;;;;CAOP,AAAU,SAASC,aAA6B;EAC9C,MAAMC,iBAAqC,OAAO,QAAQ;GACxD,QAAQ;GACR,SAAS,KAAK;GACd,GAAG,KAAK;GACR,GAAG;EACJ,EAAC,CACC,OACC,CAAC,CAAC,KAAK,MAAM,KACX,UAAU,UAAa,UAAU,QAAQ,QAAQ,SACpD,CACA,IAAI,CAAC,CAAC,KAAK,MAAM,KAAK,CAAC,KAAK,GAAG,OAAO,AAAC,EAAC;EAE3C,MAAM,eAAe,IAAI,gBAAgB;AACzC,SAAO,CAAC,uCAAuC,EAAE,cAAc;CAChE;;;;;;;;;;;;;CAcD,MAAM,MAAMC,OAAe;EACzB,MAAM,OAAO,MAAM,MAAM,KAAK,SAAS,MAAM,CAAC;EAE9C,MAAM,OAAO,MAAM,KAAK,MAAM;AAE9B,MAAI,KAAK,MACP,OAAM,IAAI,MACR,CAAC,qDAAqD,EAAE,KAAK,OAAO;AAKxE,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,iBAAiB;GACxB,MAAM,WAAW,KAAK,gBACnB,OAAO,CAACC,MAAkB,EAAE,QAAQ,CACpC,IAAI,CAACA,MAAkB,EAAE,QAAQ;AACpC,UAAO,SAAS,KAAK,KAAK;EAC3B;AAGD,MAAI,KAAK,MAAM;GACb,MAAM,kBAAkB,KAAK,KAC1B,MAAM,GAAG,EAAE,CACX,OAAO,CAACA,MAAkB,EAAE,YAAY,CACxC,IAAI,CAACA,MAAkB,EAAE,YAAY;AACxC,UAAO,gBAAgB,KAAK,KAAK;EAClC;AAGD,MAAI,KAAK,QAAQ;GACf,MAAM,YAAY,KAAK,OACpB,OAAO,CAACA,MAAkB,EAAE,SAAS,EAAE,KAAK,CAC5C,IAAI,CAACA,MAAkB,CAAC,QAAQ,EAAE,EAAE,MAAM,QAAQ,EAAE,EAAE,MAAM,CAAC;AAChE,UAAO,UAAU,KAAK,KAAK;EAC5B;AAGD,MAAI,KAAK,QAAQ;GACf,MAAM,gBAAgB,KAAK,OAAO,MAAM,GAAG,GAAG;GAC9C,MAAM,YAAY,cACf,OACC,CAACA,MACC,EAAE,SAAS,EAAE,YAAY,aAAa,EAAE,SAAS,IAAI,EAAE,SAAS,KACnE,CACA,IACC,CAACA,MACC,CAAC,QAAQ,EAAE,EAAE,MAAM,QAAQ,EAAG,EAAE,SAAwB,MAAM,CACjE;AACH,UAAO,UAAU,KAAK,KAAK;EAC5B;AAED,SAAO;CACR;CAED,cACE;AACH"}