{"version":3,"file":"chroma.cjs","names":["VectorStore","Document"],"sources":["../../src/vectorstores/chroma.ts"],"sourcesContent":["import * as uuid from \"uuid\";\nimport type {\n  ChromaClient as ChromaClientT,\n  ChromaClientArgs,\n  Collection,\n  CollectionConfiguration,\n  CollectionMetadata,\n  Where,\n} from \"chromadb\";\n\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\n\ntype SharedChromaLibArgs = {\n  numDimensions?: number;\n  collectionName?: string;\n  filter?: object;\n  collectionMetadata?: CollectionMetadata;\n  collectionConfiguration?: CollectionConfiguration;\n  chromaCloudAPIKey?: string;\n  clientParams?: Omit<ChromaClientArgs, \"path\">;\n};\n\n/**\n * Defines the arguments that can be passed to the `Chroma` class\n * constructor. It can either contain a `url` for the Chroma database, the\n * number of dimensions for the vectors (`numDimensions`), a\n * `collectionName` for the collection to be used in the database, and a\n * `filter` object; or it can contain an `index` which is an instance of\n * `ChromaClientT`, along with the `numDimensions`, `collectionName`, and\n * `filter`.\n */\nexport type ChromaLibArgs =\n  | ({\n      url?: string;\n    } & SharedChromaLibArgs)\n  | ({\n      index?: ChromaClientT;\n    } & SharedChromaLibArgs);\n\n/**\n * Defines the parameters for the `delete` method in the `Chroma` class.\n * It can either contain an array of `ids` of the documents to be deleted\n * or a `filter` object to specify the documents to be deleted.\n */\nexport interface ChromaDeleteParams<T> {\n  ids?: string[];\n  filter?: T;\n}\n\n/**\n * Chroma vector store integration.\n *\n * Setup:\n * Install `@langchain/community` and `chromadb`.\n *\n * ```bash\n * npm install @langchain/community chromadb\n * ```\n *\n * ## [Constructor args](https://api.js.langchain.com/classes/langchain_community_vectorstores_chroma.Chroma.html#constructor)\n *\n * <details open>\n * <summary><strong>Instantiate</strong></summary>\n *\n * ```typescript\n * import { Chroma } from '@langchain/community/vectorstores/chroma';\n * // Or other embeddings\n * import { OpenAIEmbeddings } from '@langchain/openai';\n *\n * const embeddings = new OpenAIEmbeddings({\n *   model: \"text-embedding-3-small\",\n * })\n *\n * const vectorStore = new Chroma(\n *   embeddings,\n *   {\n *     collectionName: \"foo\",\n *     host: \"localhost\",\n *   }\n * );\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Add documents</strong></summary>\n *\n * ```typescript\n * import type { Document } from '@langchain/core/documents';\n *\n * const document1 = { pageContent: \"foo\", metadata: { baz: \"bar\" } };\n * const document2 = { pageContent: \"thud\", metadata: { bar: \"baz\" } };\n * const document3 = { pageContent: \"I will be deleted :(\", metadata: {} };\n *\n * const documents: Document[] = [document1, document2, document3];\n * const ids = [\"1\", \"2\", \"3\"];\n * await vectorStore.addDocuments(documents, { ids });\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Delete documents</strong></summary>\n *\n * ```typescript\n * await vectorStore.delete({ ids: [\"3\"] });\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>Similarity search</strong></summary>\n *\n * ```typescript\n * const results = await vectorStore.similaritySearch(\"thud\", 1);\n * for (const doc of results) {\n *   console.log(`* ${doc.pageContent} [${JSON.stringify(doc.metadata, null)}]`);\n * }\n * // Output: * thud [{\"baz\":\"bar\"}]\n * ```\n * </details>\n *\n * <br />\n *\n *\n * <details>\n * <summary><strong>Similarity search with filter</strong></summary>\n *\n * ```typescript\n * const resultsWithFilter = await vectorStore.similaritySearch(\"thud\", 1, { baz: \"bar\" });\n *\n * for (const doc of resultsWithFilter) {\n *   console.log(`* ${doc.pageContent} [${JSON.stringify(doc.metadata, null)}]`);\n * }\n * // Output: * foo [{\"baz\":\"bar\"}]\n * ```\n * </details>\n *\n * <br />\n *\n *\n * <details>\n * <summary><strong>Similarity search with score</strong></summary>\n *\n * ```typescript\n * const resultsWithScore = await vectorStore.similaritySearchWithScore(\"qux\", 1);\n * for (const [doc, score] of resultsWithScore) {\n *   console.log(`* [SIM=${score.toFixed(6)}] ${doc.pageContent} [${JSON.stringify(doc.metadata, null)}]`);\n * }\n * // Output: * [SIM=0.000000] qux [{\"bar\":\"baz\",\"baz\":\"bar\"}]\n * ```\n * </details>\n *\n * <br />\n *\n * <details>\n * <summary><strong>As a retriever</strong></summary>\n *\n * ```typescript\n * const retriever = vectorStore.asRetriever({\n *   searchType: \"mmr\", // Leave blank for standard similarity search\n *   k: 1,\n * });\n * const resultAsRetriever = await retriever.invoke(\"thud\");\n * console.log(resultAsRetriever);\n *\n * // Output: [Document({ metadata: { \"baz\":\"bar\" }, pageContent: \"thud\" })]\n * ```\n * </details>\n *\n * <br />\n */\nexport class Chroma extends VectorStore {\n  declare FilterType: Where;\n\n  index?: ChromaClientT;\n\n  collection?: Collection;\n\n  collectionName: string;\n\n  collectionMetadata?: CollectionMetadata;\n\n  numDimensions?: number;\n\n  clientParams?: Omit<ChromaClientArgs, \"path\">;\n\n  url: string;\n\n  filter?: object;\n\n  _vectorstoreType(): string {\n    return \"chroma\";\n  }\n\n  constructor(embeddings: EmbeddingsInterface, args: ChromaLibArgs) {\n    super(embeddings, args);\n    this.numDimensions = args.numDimensions;\n    this.embeddings = embeddings;\n    this.collectionName = ensureCollectionName(args.collectionName);\n    this.collectionMetadata = args.collectionMetadata;\n    this.clientParams = args.clientParams || {};\n    if (\"index\" in args) {\n      this.index = args.index;\n    } else if (\"url\" in args) {\n      this.url = args.url || \"http://localhost:8000\";\n    }\n\n    if (args.chromaCloudAPIKey) {\n      this.clientParams.headers = {\n        ...(this.clientParams?.headers || {}),\n        \"x-chroma-token\": args.chromaCloudAPIKey,\n      };\n    }\n\n    this.filter = args.filter;\n  }\n\n  /**\n   * Adds documents to the Chroma database. The documents are first\n   * converted to vectors using the `embeddings` instance, and then added to\n   * the database.\n   * @param documents An array of `Document` instances to be added to the database.\n   * @param options Optional. An object containing an array of `ids` for the documents.\n   * @returns A promise that resolves when the documents have been added to the database.\n   */\n  async addDocuments(documents: Document[], options?: { ids?: string[] }) {\n    const texts = documents.map(({ pageContent }) => pageContent);\n    return this.addVectors(\n      await this.embeddings.embedDocuments(texts),\n      documents,\n      options\n    );\n  }\n\n  /**\n   * Ensures that a collection exists in the Chroma database. If the\n   * collection does not exist, it is created.\n   * @returns A promise that resolves with the `Collection` instance.\n   */\n  async ensureCollection(): Promise<Collection> {\n    if (!this.collection) {\n      if (!this.index) {\n        this.index = new (await Chroma.imports()).ChromaClient({\n          path: this.url,\n          ...(this.clientParams ?? {}),\n        });\n      }\n      try {\n        this.collection = await this.index.getOrCreateCollection({\n          name: this.collectionName,\n          embeddingFunction: null,\n          ...(this.collectionMetadata && { metadata: this.collectionMetadata }),\n        });\n      } catch (err) {\n        throw new Error(`Chroma getOrCreateCollection error: ${err}`);\n      }\n    }\n\n    return this.collection;\n  }\n\n  /**\n   * Adds vectors to the Chroma database. The vectors are associated with\n   * the provided documents.\n   * @param vectors An array of vectors to be added to the database.\n   * @param documents An array of `Document` instances associated with the vectors.\n   * @param options Optional. An object containing an array of `ids` for the vectors.\n   * @returns A promise that resolves with an array of document IDs when the vectors have been added to the database.\n   */\n  async addVectors(\n    vectors: number[][],\n    documents: Document[],\n    options?: { ids?: string[] }\n  ) {\n    if (vectors.length === 0) {\n      return [];\n    }\n    if (this.numDimensions === undefined) {\n      this.numDimensions = vectors[0].length;\n    }\n    if (vectors.length !== documents.length) {\n      throw new Error(`Vectors and metadatas must have the same length`);\n    }\n    if (vectors[0].length !== this.numDimensions) {\n      throw new Error(\n        `Vectors must have the same length as the number of dimensions (${this.numDimensions})`\n      );\n    }\n\n    const documentIds =\n      options?.ids ?? Array.from({ length: vectors.length }, () => uuid.v1());\n    const collection = await this.ensureCollection();\n\n    const mappedMetadatas = documents.map(({ metadata }) => {\n      let locFrom;\n      let locTo;\n\n      if (metadata?.loc) {\n        if (metadata.loc.lines?.from !== undefined)\n          locFrom = metadata.loc.lines.from;\n        if (metadata.loc.lines?.to !== undefined) locTo = metadata.loc.lines.to;\n      }\n\n      const newMetadata: Document[\"metadata\"] = {\n        ...metadata,\n        ...(locFrom !== undefined && { locFrom }),\n        ...(locTo !== undefined && { locTo }),\n      };\n\n      if (newMetadata.loc) delete newMetadata.loc;\n\n      return newMetadata;\n    });\n\n    await collection.upsert({\n      ids: documentIds,\n      embeddings: vectors,\n      metadatas: mappedMetadatas,\n      documents: documents.map(({ pageContent }) => pageContent),\n    });\n    return documentIds;\n  }\n\n  /**\n   * Deletes documents from the Chroma database. The documents to be deleted\n   * can be specified by providing an array of `ids` or a `filter` object.\n   * @param params An object containing either an array of `ids` of the documents to be deleted or a `filter` object to specify the documents to be deleted.\n   * @returns A promise that resolves when the specified documents have been deleted from the database.\n   */\n  async delete(params: ChromaDeleteParams<this[\"FilterType\"]>): Promise<void> {\n    const collection = await this.ensureCollection();\n    if (Array.isArray(params.ids)) {\n      await collection.delete({ ids: params.ids });\n    } else if (params.filter) {\n      await collection.delete({\n        where: { ...params.filter },\n      });\n    } else {\n      throw new Error(`You must provide one of \"ids or \"filter\".`);\n    }\n  }\n\n  /**\n   * Searches for vectors in the Chroma database that are similar to the\n   * provided query vector. The search can be filtered using the provided\n   * `filter` object or the `filter` property of the `Chroma` instance.\n   * @param query The query vector.\n   * @param k The number of similar vectors to return.\n   * @param filter Optional. A `filter` object to filter the search results.\n   * @returns A promise that resolves with an array of tuples, each containing a `Document` instance and a similarity score.\n   */\n  async similaritySearchVectorWithScore(\n    query: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ) {\n    if (filter && this.filter) {\n      throw new Error(\"cannot provide both `filter` and `this.filter`\");\n    }\n    const _filter = filter ?? this.filter;\n    const where = _filter === undefined ? undefined : { ..._filter };\n\n    const collection = await this.ensureCollection();\n\n    // similaritySearchVectorWithScore supports one query vector at a time\n    // chroma supports multiple query vectors at a time\n    const result = await collection.query({\n      queryEmbeddings: [query],\n      nResults: k,\n      where,\n    });\n\n    const { ids, distances, documents, metadatas } = result;\n    if (!ids || !distances || !documents || !metadatas) {\n      return [];\n    }\n    // get the result data from the first and only query vector\n    const [firstIds] = ids;\n    const [firstDistances] = distances;\n    const [firstDocuments] = documents;\n    const [firstMetadatas] = metadatas;\n\n    if (firstDistances.some((item) => item === null)) {\n      return [];\n    }\n\n    const cleanDistances = firstDistances.filter((item) => item !== null);\n\n    const results: [Document, number][] = [];\n    for (let i = 0; i < firstIds.length; i += 1) {\n      let metadata: Document[\"metadata\"] = firstMetadatas?.[i] ?? {};\n\n      if (metadata.locFrom && metadata.locTo) {\n        metadata = {\n          ...metadata,\n          loc: {\n            lines: {\n              from: metadata.locFrom,\n              to: metadata.locTo,\n            },\n          },\n        };\n\n        delete metadata.locFrom;\n        delete metadata.locTo;\n      }\n\n      results.push([\n        new Document({\n          pageContent: firstDocuments?.[i] ?? \"\",\n          metadata,\n          id: firstIds[i],\n        }),\n        cleanDistances[i],\n      ]);\n    }\n    return results;\n  }\n\n  /**\n   * Creates a new `Chroma` instance from an array of text strings. The text\n   * strings are converted to `Document` instances and added to the Chroma\n   * database.\n   * @param texts An array of text strings.\n   * @param metadatas An array of metadata objects or a single metadata object. If an array is provided, it must have the same length as the `texts` array.\n   * @param embeddings An `Embeddings` instance used to generate embeddings for the documents.\n   * @param dbConfig A `ChromaLibArgs` object containing the configuration for the Chroma database.\n   * @returns A promise that resolves with a new `Chroma` instance.\n   */\n  static async fromTexts(\n    texts: string[],\n    metadatas: object[] | object,\n    embeddings: EmbeddingsInterface,\n    dbConfig: ChromaLibArgs\n  ): Promise<Chroma> {\n    const docs: Document[] = [];\n    for (let i = 0; i < texts.length; i += 1) {\n      const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n      const newDoc = new Document({\n        pageContent: texts[i],\n        metadata,\n      });\n      docs.push(newDoc);\n    }\n    return this.fromDocuments(docs, embeddings, dbConfig);\n  }\n\n  /**\n   * Creates a new `Chroma` instance from an array of `Document` instances.\n   * The documents are added to the Chroma database.\n   * @param docs An array of `Document` instances.\n   * @param embeddings An `Embeddings` instance used to generate embeddings for the documents.\n   * @param dbConfig A `ChromaLibArgs` object containing the configuration for the Chroma database.\n   * @returns A promise that resolves with a new `Chroma` instance.\n   */\n  static async fromDocuments(\n    docs: Document[],\n    embeddings: EmbeddingsInterface,\n    dbConfig: ChromaLibArgs\n  ): Promise<Chroma> {\n    const instance = new this(embeddings, dbConfig);\n    await instance.addDocuments(docs);\n    return instance;\n  }\n\n  /**\n   * Creates a new `Chroma` instance from an existing collection in the\n   * Chroma database.\n   * @param embeddings An `Embeddings` instance used to generate embeddings for the documents.\n   * @param dbConfig A `ChromaLibArgs` object containing the configuration for the Chroma database.\n   * @returns A promise that resolves with a new `Chroma` instance.\n   */\n  static async fromExistingCollection(\n    embeddings: EmbeddingsInterface,\n    dbConfig: ChromaLibArgs\n  ): Promise<Chroma> {\n    const instance = new this(embeddings, dbConfig);\n    await instance.ensureCollection();\n    return instance;\n  }\n\n  /** @ignore */\n  static async imports(): Promise<{\n    ChromaClient: typeof ChromaClientT;\n  }> {\n    try {\n      const { ChromaClient } = await import(\"chromadb\");\n      return { ChromaClient };\n    } catch {\n      throw new Error(\n        \"Please install chromadb as a dependency with, e.g. `npm install -S chromadb`\"\n      );\n    }\n  }\n}\n\n/**\n * Generates a unique collection name if none is provided.\n */\nfunction ensureCollectionName(collectionName?: string) {\n  if (!collectionName) {\n    return `langchain-${uuid.v4()}`;\n  }\n  return collectionName;\n}\n"],"mappings":"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"}