{"version":3,"file":"stackexchange.cjs","names":["Tool"],"sources":["../../src/tools/stackexchange.ts"],"sourcesContent":["import { Tool } from \"@langchain/core/tools\";\n\nexport interface StackExchangeAnswer {\n  items: StackExchangeItem[];\n  has_more: boolean;\n  quota_max: number;\n  quota_remaining: number;\n}\n\nexport interface StackExchangeItem {\n  tags: string[];\n  question_score: number;\n  is_accepted: boolean;\n  has_accepted_answer?: boolean;\n  answer_count?: number;\n  is_answered: boolean;\n  question_id: number;\n  item_type: string;\n  score: number;\n  last_activity_date: number;\n  creation_date: number;\n  body: string;\n  excerpt: string;\n  title: string;\n  answer_id?: number;\n}\n\ntype StackExchangeOptions = Record<string, string | number | boolean>;\n\nexport interface StackExchangeAPIParams {\n  /**\n   * The maximum number of results to return from the search.\n   * Limiting to 10 to avoid context overload.\n   * @default 3\n   */\n  maxResult?: number;\n  /**\n   * Which part of StackOverflows items to match against. One of 'all', 'title',\n   * 'body'.\n   * @default \"all\"\n   */\n  queryType?: \"all\" | \"title\" | \"body\";\n  /**\n   * Additional params to pass to the StackExchange API\n   */\n  options?: StackExchangeOptions;\n  /**\n   * Separator between question,answer pairs.\n   * @default \"\\n\\n\"\n   */\n  resultSeparator?: string;\n}\n\n/**\n * Class for interacting with the StackExchange API\n * It extends the base Tool class to perform retrieval.\n */\nexport class StackExchangeAPI extends Tool {\n  name = \"stackexchange\";\n\n  description = \"Stack Exchange API Implementation\";\n\n  private pageSize: number;\n\n  private maxResult = 3;\n\n  private key: string | null;\n\n  private accessToken: string | null;\n\n  private site = \"stackoverflow\";\n\n  private version = \"2.3\";\n\n  private baseUrl = \"https://api.stackexchange.com\";\n\n  private queryType = \"all\";\n\n  private options?: StackExchangeOptions = {};\n\n  private resultSeparator?: string = \"\\n\\n\";\n\n  constructor(params: StackExchangeAPIParams = {}) {\n    const { maxResult, queryType = \"all\", options, resultSeparator } = params;\n    super();\n    this.maxResult = maxResult || this.maxResult;\n    this.pageSize = 100;\n    this.baseUrl = `${this.baseUrl}/${this.version}/`;\n    this.queryType = queryType === \"all\" ? \"q\" : queryType;\n    this.options = options || this.options;\n    this.resultSeparator = resultSeparator || this.resultSeparator;\n  }\n\n  async _call(query: string): Promise<string> {\n    const params = {\n      [this.queryType]: query,\n      site: this.site,\n      ...this.options,\n    };\n    const output = await this._fetch<StackExchangeAnswer>(\n      \"search/excerpts\",\n      params\n    );\n    if (output.items.length < 1) {\n      return `No relevant results found for '${query}' on Stack Overflow.`;\n    }\n    const questions = output.items\n      .filter((item) => item.item_type === \"question\")\n      .slice(0, this.maxResult);\n    const answers = output.items.filter((item) => item.item_type === \"answer\");\n\n    const results: string[] = [];\n\n    for (const question of questions) {\n      let res_text = `Question: ${question.title}\\n${question.excerpt}`;\n\n      const relevant_answers = answers.filter(\n        (answer) => answer.question_id === question.question_id\n      );\n      const accepted_answers = relevant_answers.filter(\n        (answer) => answer.is_accepted\n      );\n\n      if (relevant_answers.length > 0) {\n        const top_answer =\n          accepted_answers.length > 0\n            ? accepted_answers[0]\n            : relevant_answers[0];\n        const { excerpt } = top_answer;\n        res_text += `\\nAnswer: ${excerpt}`;\n      }\n\n      results.push(res_text);\n    }\n\n    return results.join(this.resultSeparator);\n  }\n\n  /**\n   * Call the StackExchange API\n   * @param endpoint Name of the endpoint from StackExchange API\n   * @param params Additional parameters passed to the endpoint\n   * @param page Number of the page to retrieve\n   * @param filter Filtering properties\n   */\n  private async _fetch<T>(\n    endpoint: string,\n    params: StackExchangeOptions = {},\n    page = 1,\n    filter = \"default\"\n  ): Promise<T> {\n    try {\n      if (!endpoint) {\n        throw new Error(\"No end point provided.\");\n      }\n      const queryParams = new URLSearchParams({\n        pagesize: this.pageSize.toString(),\n        page: page.toString(),\n        filter,\n        ...params,\n      });\n\n      if (this.key) {\n        queryParams.append(\"key\", this.key);\n      }\n      if (this.accessToken) {\n        queryParams.append(\"access_token\", this.accessToken);\n      }\n\n      const queryParamsString = queryParams.toString();\n\n      const endpointUrl = `${this.baseUrl}${endpoint}?${queryParamsString}`;\n      return await this._makeRequest(endpointUrl);\n    } catch {\n      throw new Error(\"Error while calling Stack Exchange API\");\n    }\n  }\n\n  /**\n   * Fetch the result of a specific endpoint\n   * @param endpointUrl Endpoint to call\n   */\n  private async _makeRequest<T>(endpointUrl: string): Promise<T> {\n    try {\n      const response = await fetch(endpointUrl);\n      if (response.status !== 200) {\n        throw new Error(`HTTP Error: ${response.statusText}`);\n      }\n      return await response.json();\n    } catch {\n      throw new Error(`Error while calling Stack Exchange API: ${endpointUrl}`);\n    }\n  }\n}\n"],"mappings":";;;;;;;;;AAyDA,IAAa,mBAAb,cAAsCA,sBAAAA,KAAK;CACzC,OAAO;CAEP,cAAc;CAEd;CAEA,YAAoB;CAEpB;CAEA;CAEA,OAAe;CAEf,UAAkB;CAElB,UAAkB;CAElB,YAAoB;CAEpB,UAAyC,EAAE;CAE3C,kBAAmC;CAEnC,YAAY,SAAiC,EAAE,EAAE;EAC/C,MAAM,EAAE,WAAW,YAAY,OAAO,SAAS,oBAAoB;AACnE,SAAO;AACP,OAAK,YAAY,aAAa,KAAK;AACnC,OAAK,WAAW;AAChB,OAAK,UAAU,GAAG,KAAK,QAAQ,GAAG,KAAK,QAAQ;AAC/C,OAAK,YAAY,cAAc,QAAQ,MAAM;AAC7C,OAAK,UAAU,WAAW,KAAK;AAC/B,OAAK,kBAAkB,mBAAmB,KAAK;;CAGjD,MAAM,MAAM,OAAgC;EAC1C,MAAM,SAAS;IACZ,KAAK,YAAY;GAClB,MAAM,KAAK;GACX,GAAG,KAAK;GACT;EACD,MAAM,SAAS,MAAM,KAAK,OACxB,mBACA,OACD;AACD,MAAI,OAAO,MAAM,SAAS,EACxB,QAAO,kCAAkC,MAAM;EAEjD,MAAM,YAAY,OAAO,MACtB,QAAQ,SAAS,KAAK,cAAc,WAAW,CAC/C,MAAM,GAAG,KAAK,UAAU;EAC3B,MAAM,UAAU,OAAO,MAAM,QAAQ,SAAS,KAAK,cAAc,SAAS;EAE1E,MAAM,UAAoB,EAAE;AAE5B,OAAK,MAAM,YAAY,WAAW;GAChC,IAAI,WAAW,aAAa,SAAS,MAAM,IAAI,SAAS;GAExD,MAAM,mBAAmB,QAAQ,QAC9B,WAAW,OAAO,gBAAgB,SAAS,YAC7C;GACD,MAAM,mBAAmB,iBAAiB,QACvC,WAAW,OAAO,YACpB;AAED,OAAI,iBAAiB,SAAS,GAAG;IAK/B,MAAM,EAAE,YAHN,iBAAiB,SAAS,IACtB,iBAAiB,KACjB,iBAAiB;AAEvB,gBAAY,aAAa;;AAG3B,WAAQ,KAAK,SAAS;;AAGxB,SAAO,QAAQ,KAAK,KAAK,gBAAgB;;;;;;;;;CAU3C,MAAc,OACZ,UACA,SAA+B,EAAE,EACjC,OAAO,GACP,SAAS,WACG;AACZ,MAAI;AACF,OAAI,CAAC,SACH,OAAM,IAAI,MAAM,yBAAyB;GAE3C,MAAM,cAAc,IAAI,gBAAgB;IACtC,UAAU,KAAK,SAAS,UAAU;IAClC,MAAM,KAAK,UAAU;IACrB;IACA,GAAG;IACJ,CAAC;AAEF,OAAI,KAAK,IACP,aAAY,OAAO,OAAO,KAAK,IAAI;AAErC,OAAI,KAAK,YACP,aAAY,OAAO,gBAAgB,KAAK,YAAY;GAGtD,MAAM,oBAAoB,YAAY,UAAU;GAEhD,MAAM,cAAc,GAAG,KAAK,UAAU,SAAS,GAAG;AAClD,UAAO,MAAM,KAAK,aAAa,YAAY;UACrC;AACN,SAAM,IAAI,MAAM,yCAAyC;;;;;;;CAQ7D,MAAc,aAAgB,aAAiC;AAC7D,MAAI;GACF,MAAM,WAAW,MAAM,MAAM,YAAY;AACzC,OAAI,SAAS,WAAW,IACtB,OAAM,IAAI,MAAM,eAAe,SAAS,aAAa;AAEvD,UAAO,MAAM,SAAS,MAAM;UACtB;AACN,SAAM,IAAI,MAAM,2CAA2C,cAAc"}