{"version":3,"sources":["../../../src/tools/database/elasticsearch.ts"],"names":["ElasticSearchAction","ListIndices","GetIndexDetails","Search","ElasticSearchTool","Tool","name","description","inputSchema","z","object","action","nativeEnum","describe","indexName","string","optional","query","start","coerce","number","int","min","default","size","max","emitter","Emitter","root","child","namespace","creator","validateInput","schema","input","ToolInputValidationError","register","options","connection","cloud","node","nodes","ValidationError","message","propertyName","client","Client","info","error","ToolError","isRetryable","isFatal","_run","_options","run","indices","listIndices","signal","JSONToolOutput","indexDetails","getIndexDetails","response","search","aggregations","hits","map","hit","_source","cat","expand_wildcards","h","format","filter","record","index","startsWith","getMapping","parsedQuery","parseBrokenJson","searchBody","from","body"],"mappings":"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","file":"elasticsearch.cjs","sourcesContent":["/**\n * Copyright 2025 IBM Corp.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n  Tool,\n  ToolInput,\n  ToolError,\n  BaseToolOptions,\n  BaseToolRunOptions,\n  JSONToolOutput,\n  ToolInputValidationError,\n  ToolEmitter,\n} from \"@/tools/base.js\";\nimport { Cache } from \"@/cache/decoratorCache.js\";\nimport { RunContext } from \"@/context.js\";\nimport { z } from \"zod\";\nimport { ValidationError } from \"ajv\";\nimport { AnyToolSchemaLike } from \"@/internals/helpers/schema.js\";\nimport { parseBrokenJson } from \"@/internals/helpers/schema.js\";\nimport { Client, ClientOptions, estypes as ESTypes } from \"@elastic/elasticsearch\";\nimport { Emitter } from \"@/emitter/emitter.js\";\n\nexport interface ElasticSearchToolOptions extends BaseToolOptions {\n  connection: ClientOptions;\n}\n\nexport type ElasticSearchToolResult =\n  | ESTypes.CatIndicesResponse\n  | ESTypes.IndicesGetMappingResponse\n  | ESTypes.SearchResponse;\n\nexport const ElasticSearchAction = {\n  ListIndices: \"LIST_INDICES\",\n  GetIndexDetails: \"GET_INDEX_DETAILS\",\n  Search: \"SEARCH\",\n} as const;\n\nexport class ElasticSearchTool extends Tool<\n  JSONToolOutput<ElasticSearchToolResult>,\n  ElasticSearchToolOptions\n> {\n  name = \"ElasticSearchTool\";\n\n  description = `Can query data from an ElasticSearch database. IMPORTANT: strictly follow this order of actions:\n   1. ${ElasticSearchAction.ListIndices} - retrieve a list of available indices\n   2. ${ElasticSearchAction.GetIndexDetails} - get details of index fields\n   3. ${ElasticSearchAction.Search} - perform search or aggregation query on a specific index or pass the original user query without modifications if it's a valid JSON ElasticSearch query after identifying the index`;\n\n  inputSchema() {\n    return z.object({\n      action: z\n        .nativeEnum(ElasticSearchAction)\n        .describe(\n          `The action to perform. ${ElasticSearchAction.ListIndices} lists all indices, ${ElasticSearchAction.GetIndexDetails} fetches details for a specified index, and ${ElasticSearchAction.Search} executes a search or aggregation query`,\n        ),\n      indexName: z\n        .string()\n        .optional()\n        .describe(\n          `The name of the index to query, required for ${ElasticSearchAction.GetIndexDetails} and ${ElasticSearchAction.Search}`,\n        ),\n      query: z\n        .string()\n        .optional()\n        .describe(\n          `Valid ElasticSearch JSON search or aggregation query for ${ElasticSearchAction.Search} action`,\n        ),\n      start: z.coerce\n        .number()\n        .int()\n        .min(0)\n        .default(0)\n        .optional()\n        .describe(\n          \"The record index from which the query will start. Increase by the size of the query to get the next page of results\",\n        ),\n      size: z.coerce\n        .number()\n        .int()\n        .min(0)\n        .max(10)\n        .default(10)\n        .optional()\n        .describe(\"How many records will be retrieved from the ElasticSearch query. Maximum is 10\"),\n    });\n  }\n\n  public readonly emitter: ToolEmitter<ToolInput<this>, JSONToolOutput<ElasticSearchToolResult>> =\n    Emitter.root.child({\n      namespace: [\"tool\", \"database\", \"elasticsearch\"],\n      creator: this,\n    });\n\n  protected validateInput(\n    schema: AnyToolSchemaLike,\n    input: unknown,\n  ): asserts input is ToolInput<this> {\n    super.validateInput(schema, input);\n    if (input.action === ElasticSearchAction.GetIndexDetails && !input.indexName) {\n      throw new ToolInputValidationError(\n        `Index name is required for ${ElasticSearchAction.GetIndexDetails} action.`,\n      );\n    }\n    if (input.action === ElasticSearchAction.Search && (!input.indexName || !input.query)) {\n      throw new ToolInputValidationError(\n        `Both index name and query are required for ${ElasticSearchAction.Search} action.`,\n      );\n    }\n  }\n\n  static {\n    this.register();\n  }\n\n  public constructor(options: ElasticSearchToolOptions) {\n    super(options);\n    if (!options.connection.cloud && !options.connection.node && !options.connection.nodes) {\n      throw new ValidationError([\n        {\n          message: \"At least one of the properties must be provided\",\n          propertyName: \"connection.cloud, connection.node, connection.nodes\",\n        },\n      ]);\n    }\n  }\n\n  @Cache()\n  protected async client(): Promise<Client> {\n    try {\n      const client = new Client(this.options.connection);\n      await client.info();\n      return client;\n    } catch (error) {\n      throw new ToolError(`Unable to connect to ElasticSearch.`, [error], {\n        isRetryable: false,\n        isFatal: true,\n      });\n    }\n  }\n\n  protected async _run(\n    input: ToolInput<this>,\n    _options: Partial<BaseToolRunOptions>,\n    run: RunContext<this>,\n  ): Promise<JSONToolOutput<any>> {\n    if (input.action === ElasticSearchAction.ListIndices) {\n      const indices = await this.listIndices(run.signal);\n      return new JSONToolOutput(indices);\n    } else if (input.action === ElasticSearchAction.GetIndexDetails) {\n      const indexDetails = await this.getIndexDetails(input, run.signal);\n      return new JSONToolOutput(indexDetails);\n    } else if (input.action === ElasticSearchAction.Search) {\n      const response = await this.search(input, run.signal);\n      if (response.aggregations) {\n        return new JSONToolOutput(response.aggregations);\n      } else {\n        return new JSONToolOutput(response.hits.hits.map((hit: ESTypes.SearchHit) => hit._source));\n      }\n    } else {\n      throw new ToolError(`Invalid action specified: ${input.action}`);\n    }\n  }\n\n  protected async listIndices(signal?: AbortSignal): Promise<ESTypes.CatIndicesResponse> {\n    const client = await this.client();\n    const response = await client.cat.indices(\n      {\n        expand_wildcards: \"open\",\n        h: \"index\",\n        format: \"json\",\n      },\n      { signal: signal },\n    );\n    return response\n      .filter((record) => record.index && !record.index.startsWith(\".\")) // Exclude system indices\n      .map((record) => ({ index: record.index }));\n  }\n\n  protected async getIndexDetails(\n    input: ToolInput<this>,\n    signal: AbortSignal,\n  ): Promise<ESTypes.IndicesGetMappingResponse> {\n    const client = await this.client();\n    return await client.indices.getMapping(\n      {\n        index: input.indexName,\n      },\n      { signal: signal },\n    );\n  }\n\n  protected async search(\n    input: ToolInput<this>,\n    signal: AbortSignal,\n  ): Promise<ESTypes.SearchResponse> {\n    const parsedQuery = parseBrokenJson(input.query);\n    const searchBody: ESTypes.SearchRequest = {\n      ...parsedQuery,\n      from: parsedQuery.from || input.start,\n      size: parsedQuery.size || input.size,\n    };\n    const client = await this.client();\n    return await client.search(\n      {\n        index: input.indexName,\n        body: searchBody,\n      },\n      { signal: signal },\n    );\n  }\n}\n"]}