{"version":3,"file":"serpapi.cjs","names":["Tool"],"sources":["../../src/tools/serpapi.ts"],"sourcesContent":["import { getEnvironmentVariable } from \"@langchain/core/utils/env\";\nimport { Tool } from \"@langchain/core/tools\";\n\n/**\n * This does not use the `serpapi` package because it appears to cause issues\n * when used in `jest` tests. Part of the issue seems to be that the `serpapi`\n * package imports a wasm module to use instead of native `fetch`, which we\n * don't want anyway.\n *\n * NOTE: you must provide location, gl and hl or your region and language will\n * may not match your location, and will not be deterministic.\n */\n\n// Copied over from `serpapi` package\ninterface BaseParameters {\n  /**\n   * Parameter defines the device to use to get the results. It can be set to\n   * `desktop` (default) to use a regular browser, `tablet` to use a tablet browser\n   * (currently using iPads), or `mobile` to use a mobile browser (currently\n   * using iPhones).\n   */\n  device?: \"desktop\" | \"tablet\" | \"mobile\";\n  /**\n   * Parameter will force SerpApi to fetch the Google results even if a cached\n   * version is already present. A cache is served only if the query and all\n   * parameters are exactly the same. Cache expires after 1h. Cached searches\n   * are free, and are not counted towards your searches per month. It can be set\n   * to `false` (default) to allow results from the cache, or `true` to disallow\n   * results from the cache. `no_cache` and `async` parameters should not be used together.\n   */\n  no_cache?: boolean;\n  /**\n   * Specify the client-side timeout of the request. In milliseconds.\n   */\n  timeout?: number;\n}\n\nexport interface SerpAPIParameters extends BaseParameters {\n  /**\n   * Search Query\n   * Parameter defines the query you want to search. You can use anything that you\n   * would use in a regular Google search. e.g. `inurl:`, `site:`, `intitle:`. We\n   * also support advanced search query parameters such as as_dt and as_eq. See the\n   * [full list](https://serpapi.com/advanced-google-query-parameters) of supported\n   * advanced search query parameters.\n   */\n  q: string;\n  /**\n   * Location\n   * Parameter defines from where you want the search to originate. If several\n   * locations match the location requested, we'll pick the most popular one. Head to\n   * [/locations.json API](https://serpapi.com/locations-api) if you need more\n   * precise control. location and uule parameters can't be used together. Avoid\n   * utilizing location when setting the location outside the U.S. when using Google\n   * Shopping and/or Google Product API.\n   */\n  location?: string;\n  /**\n   * Encoded Location\n   * Parameter is the Google encoded location you want to use for the search. uule\n   * and location parameters can't be used together.\n   */\n  uule?: string;\n  /**\n   * Google Place ID\n   * Parameter defines the id (`CID`) of the Google My Business listing you want to\n   * scrape. Also known as Google Place ID.\n   */\n  ludocid?: string;\n  /**\n   * Additional Google Place ID\n   * Parameter that you might have to use to force the knowledge graph map view to\n   * show up. You can find the lsig ID by using our [Local Pack\n   * API](https://serpapi.com/local-pack) or [Local Places Results\n   * API](https://serpapi.com/local-results).\n   * lsig ID is also available via a redirect Google uses within [Google My\n   * Business](https://www.google.com/business/).\n   */\n  lsig?: string;\n  /**\n   * Google Knowledge Graph ID\n   * Parameter defines the id (`KGMID`) of the Google Knowledge Graph listing you\n   * want to scrape. Also known as Google Knowledge Graph ID. Searches with kgmid\n   * parameter will return results for the originally encrypted search parameters.\n   * For some searches, kgmid may override all other parameters except start, and num\n   * parameters.\n   */\n  kgmid?: string;\n  /**\n   * Google Cached Search Parameters ID\n   * Parameter defines the cached search parameters of the Google Search you want to\n   * scrape. Searches with si parameter will return results for the originally\n   * encrypted search parameters. For some searches, si may override all other\n   * parameters except start, and num parameters. si can be used to scrape Google\n   * Knowledge Graph Tabs.\n   */\n  si?: string;\n  /**\n   * Domain\n   * Parameter defines the Google domain to use. It defaults to `google.com`. Head to\n   * the [Google domains page](https://serpapi.com/google-domains) for a full list of\n   * supported Google domains.\n   */\n  google_domain?: string;\n  /**\n   * Country\n   * Parameter defines the country to use for the Google search. It's a two-letter\n   * country code. (e.g., `us` for the United States, `uk` for United Kingdom, or\n   * `fr` for France). Head to the [Google countries\n   * page](https://serpapi.com/google-countries) for a full list of supported Google\n   * countries.\n   */\n  gl?: string;\n  /**\n   * Language\n   * Parameter defines the language to use for the Google search. It's a two-letter\n   * language code. (e.g., `en` for English, `es` for Spanish, or `fr` for French).\n   * Head to the [Google languages page](https://serpapi.com/google-languages) for a\n   * full list of supported Google languages.\n   */\n  hl?: string;\n  /**\n   * Set Multiple Languages\n   * Parameter defines one or multiple languages to limit the search to. It uses\n   * `lang_{two-letter language code}` to specify languages and `|` as a delimiter.\n   * (e.g., `lang_fr|lang_de` will only search French and German pages). Head to the\n   * [Google lr languages page](https://serpapi.com/google-lr-languages) for a full\n   * list of supported languages.\n   */\n  lr?: string;\n  /**\n   * as_dt\n   * Parameter controls whether to include or exclude results from the site named in\n   * the as_sitesearch parameter.\n   */\n  as_dt?: string;\n  /**\n   * as_epq\n   * Parameter identifies a phrase that all documents in the search results must\n   * contain. You can also use the [phrase\n   * search](https://developers.google.com/custom-search/docs/xml_results#PhraseSearchqt)\n   * query term to search for a phrase.\n   */\n  as_epq?: string;\n  /**\n   * as_eq\n   * Parameter identifies a word or phrase that should not appear in any documents in\n   * the search results. You can also use the [exclude\n   * query](https://developers.google.com/custom-search/docs/xml_results#Excludeqt)\n   * term to ensure that a particular word or phrase will not appear in the documents\n   * in a set of search results.\n   */\n  as_eq?: string;\n  /**\n   * as_lq\n   * Parameter specifies that all search results should contain a link to a\n   * particular URL. You can also use the\n   * [link:](https://developers.google.com/custom-search/docs/xml_results#BackLinksqt)\n   * query term for this type of query.\n   */\n  as_lq?: string;\n  /**\n   * as_nlo\n   * Parameter specifies the starting value for a search range. Use as_nlo and as_nhi\n   * to append an inclusive search range.\n   */\n  as_nlo?: string;\n  /**\n   * as_nhi\n   * Parameter specifies the ending value for a search range. Use as_nlo and as_nhi\n   * to append an inclusive search range.\n   */\n  as_nhi?: string;\n  /**\n   * as_oq\n   * Parameter provides additional search terms to check for in a document, where\n   * each document in the search results must contain at least one of the additional\n   * search terms. You can also use the [Boolean\n   * OR](https://developers.google.com/custom-search/docs/xml_results#BooleanOrqt)\n   * query term for this type of query.\n   */\n  as_oq?: string;\n  /**\n   * as_q\n   * Parameter provides search terms to check for in a document. This parameter is\n   * also commonly used to allow users to specify additional terms to search for\n   * within a set of search results.\n   */\n  as_q?: string;\n  /**\n   * as_qdr\n   * Parameter requests search results from a specified time period (quick date\n   * range). The following values are supported:\n   * `d[number]`: requests results from the specified number of past days. Example\n   * for the past 10 days: `as_qdr=d10`\n   * `w[number]`: requests results from the specified number of past weeks.\n   * `m[number]`: requests results from the specified number of past months.\n   * `y[number]`: requests results from the specified number of past years. Example\n   * for the past year: `as_qdr=y`\n   */\n  as_qdr?: string;\n  /**\n   * as_rq\n   * Parameter specifies that all search results should be pages that are related to\n   * the specified URL. The parameter value should be a URL. You can also use the\n   * [related:](https://developers.google.com/custom-search/docs/xml_results#RelatedLinksqt)\n   * query term for this type of query.\n   */\n  as_rq?: string;\n  /**\n   * as_sitesearch\n   * Parameter allows you to specify that all search results should be pages from a\n   * given site. By setting the as_dt parameter, you can also use it to exclude pages\n   * from a given site from your search resutls.\n   */\n  as_sitesearch?: string;\n  /**\n   * Advanced Search Parameters\n   * (to be searched) parameter defines advanced search parameters that aren't\n   * possible in the regular query field. (e.g., advanced search for patents, dates,\n   * news, videos, images, apps, or text contents).\n   */\n  tbs?: string;\n  /**\n   * Adult Content Filtering\n   * Parameter defines the level of filtering for adult content. It can be set to\n   * `active`, or `off` (default).\n   */\n  safe?: string;\n  /**\n   * Exclude Auto-corrected Results\n   * Parameter defines the exclusion of results from an auto-corrected query that is\n   * spelled wrong. It can be set to `1` to exclude these results, or `0` to include\n   * them (default).\n   */\n  nfpr?: string;\n  /**\n   * Results Filtering\n   * Parameter defines if the filters for 'Similar Results' and 'Omitted Results' are\n   * on or off. It can be set to `1` (default) to enable these filters, or `0` to\n   * disable these filters.\n   */\n  filter?: string;\n  /**\n   * Search Type\n   * (to be matched) parameter defines the type of search you want to do.\n   * It can be set to:\n   * `(no tbm parameter)`: regular Google Search,\n   * `isch`: [Google Images API](https://serpapi.com/images-results),\n   * `lcl` - [Google Local API](https://serpapi.com/local-results)\n   * `vid`: [Google Videos API](https://serpapi.com/videos-results),\n   * `nws`: [Google News API](https://serpapi.com/news-results),\n   * `shop`: [Google Shopping API](https://serpapi.com/shopping-results),\n   * or any other Google service.\n   */\n  tbm?: string;\n  /**\n   * Result Offset\n   * Parameter defines the result offset. It skips the given number of results. It's\n   * used for pagination. (e.g., `0` (default) is the first page of results, `10` is\n   * the 2nd page of results, `20` is the 3rd page of results, etc.).\n   * Google Local Results only accepts multiples of `20`(e.g. `20` for the second\n   * page results, `40` for the third page results, etc.) as the start value.\n   */\n  start?: number;\n  /**\n   * Number of Results\n   * Parameter defines the maximum number of results to return. (e.g., `10` (default)\n   * returns 10 results, `40` returns 40 results, and `100` returns 100 results).\n   */\n  num?: string;\n  /**\n   * Page Number (images)\n   * Parameter defines the page number for [Google\n   * Images](https://serpapi.com/images-results). There are 100 images per page. This\n   * parameter is equivalent to start (offset) = ijn * 100. This parameter works only\n   * for [Google Images](https://serpapi.com/images-results) (set tbm to `isch`).\n   */\n  ijn?: string;\n}\n\ntype UrlParameters = Record<\n  string,\n  string | number | boolean | undefined | null\n>;\n\n/**\n * Wrapper around SerpAPI.\n *\n * To use, you should have the `serpapi` package installed and the SERPAPI_API_KEY environment variable set.\n */\nexport class SerpAPI extends Tool {\n  static lc_name() {\n    return \"SerpAPI\";\n  }\n\n  toJSON() {\n    return this.toJSONNotImplemented();\n  }\n\n  protected key: string;\n\n  protected params: Partial<SerpAPIParameters>;\n\n  protected baseUrl: string;\n\n  constructor(\n    apiKey: string | undefined = getEnvironmentVariable(\"SERPAPI_API_KEY\"),\n    params: Partial<SerpAPIParameters> = {},\n    baseUrl = \"https://serpapi.com\"\n  ) {\n    super(...arguments);\n\n    if (!apiKey) {\n      throw new Error(\n        \"SerpAPI API key not set. You can set it as SERPAPI_API_KEY in your .env file, or pass it to SerpAPI.\"\n      );\n    }\n\n    this.key = apiKey;\n    this.params = params;\n    this.baseUrl = baseUrl;\n  }\n\n  name = \"search\";\n\n  /**\n   * Builds a URL for the SerpAPI request.\n   * @param path The path for the request.\n   * @param parameters The parameters for the request.\n   * @param baseUrl The base URL for the request.\n   * @returns A string representing the built URL.\n   */\n  protected buildUrl<P extends UrlParameters>(\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}`]);\n    const searchParams = new URLSearchParams(nonUndefinedParams);\n    return `${baseUrl}/${path}?${searchParams}`;\n  }\n\n  /** @ignore */\n  async _call(input: string) {\n    const { timeout, ...params } = this.params;\n    const resp = await fetch(\n      this.buildUrl(\n        \"search\",\n        {\n          ...params,\n          api_key: this.key,\n          q: input,\n        },\n        this.baseUrl\n      ),\n      {\n        signal: timeout ? AbortSignal.timeout(timeout) : undefined,\n      }\n    );\n\n    const res = await resp.json();\n\n    if (res.error) {\n      throw new Error(`Got error from serpAPI: ${res.error}`);\n    }\n\n    const answer_box = res.answer_box_list\n      ? res.answer_box_list[0]\n      : res.answer_box;\n    if (answer_box) {\n      if (answer_box.result) {\n        return answer_box.result;\n      } else if (answer_box.answer) {\n        return answer_box.answer;\n      } else if (answer_box.snippet) {\n        return answer_box.snippet;\n      } else if (answer_box.snippet_highlighted_words) {\n        return answer_box.snippet_highlighted_words.toString();\n      } else {\n        const answer: { [key: string]: string } = {};\n        Object.keys(answer_box)\n          .filter(\n            (k) =>\n              !Array.isArray(answer_box[k]) &&\n              typeof answer_box[k] !== \"object\" &&\n              !(\n                typeof answer_box[k] === \"string\" &&\n                answer_box[k].startsWith(\"http\")\n              )\n          )\n          .forEach((k) => {\n            answer[k] = answer_box[k];\n          });\n        return JSON.stringify(answer);\n      }\n    }\n\n    if (res.events_results) {\n      return JSON.stringify(res.events_results);\n    }\n\n    if (res.sports_results) {\n      return JSON.stringify(res.sports_results);\n    }\n\n    if (res.top_stories) {\n      return JSON.stringify(res.top_stories);\n    }\n\n    if (res.news_results) {\n      return JSON.stringify(res.news_results);\n    }\n\n    if (res.jobs_results?.jobs) {\n      return JSON.stringify(res.jobs_results.jobs);\n    }\n\n    if (res.questions_and_answers) {\n      return JSON.stringify(res.questions_and_answers);\n    }\n\n    if (res.popular_destinations?.destinations) {\n      return JSON.stringify(res.popular_destinations.destinations);\n    }\n\n    if (res.top_sights?.sights) {\n      const sights: Array<{ [key: string]: string }> = res.top_sights.sights\n        .map((s: { [key: string]: string }) => ({\n          title: s.title,\n          description: s.description,\n          price: s.price,\n        }))\n        .slice(0, 8);\n      return JSON.stringify(sights);\n    }\n\n    if (res.shopping_results && res.shopping_results[0]?.title) {\n      return JSON.stringify(res.shopping_results.slice(0, 3));\n    }\n\n    if (res.images_results && res.images_results[0]?.thumbnail) {\n      return res.images_results\n        .map((ir: { thumbnail: string }) => ir.thumbnail)\n        .slice(0, 10)\n        .toString();\n    }\n\n    const snippets = [];\n    if (res.knowledge_graph) {\n      if (res.knowledge_graph.description) {\n        snippets.push(res.knowledge_graph.description);\n      }\n\n      const title = res.knowledge_graph.title || \"\";\n      Object.keys(res.knowledge_graph)\n        .filter(\n          (k) =>\n            typeof res.knowledge_graph[k] === \"string\" &&\n            k !== \"title\" &&\n            k !== \"description\" &&\n            !k.endsWith(\"_stick\") &&\n            !k.endsWith(\"_link\") &&\n            !k.startsWith(\"http\")\n        )\n        .forEach((k) =>\n          snippets.push(`${title} ${k}: ${res.knowledge_graph[k]}`)\n        );\n    }\n\n    const first_organic_result = res.organic_results?.[0];\n    if (first_organic_result) {\n      if (first_organic_result.snippet) {\n        snippets.push(first_organic_result.snippet);\n      } else if (first_organic_result.snippet_highlighted_words) {\n        snippets.push(first_organic_result.snippet_highlighted_words);\n      } else if (first_organic_result.rich_snippet) {\n        snippets.push(first_organic_result.rich_snippet);\n      } else if (first_organic_result.rich_snippet_table) {\n        snippets.push(first_organic_result.rich_snippet_table);\n      } else if (first_organic_result.link) {\n        snippets.push(first_organic_result.link);\n      }\n    }\n\n    if (res.buying_guide) {\n      snippets.push(res.buying_guide);\n    }\n\n    if (res.local_results?.places) {\n      snippets.push(res.local_results.places);\n    }\n\n    if (snippets.length > 0) {\n      return JSON.stringify(snippets);\n    } else {\n      return \"No good search result found\";\n    }\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":"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"}