{"version":3,"file":"supabase.cjs","names":["VectorStore","embeddings: EmbeddingsInterface","args: SupabaseLibArgs","documents: Document[]","options?: { ids?: string[] | number[] }","vectors: number[][]","returnedIds: string[]","params: { ids: string[] | number[] }","query: number[]","k: number","filter?: this[\"FilterType\"]","matchDocumentsParams: Partial<SearchEmbeddingsParams>","filterFunction: SupabaseFilterRPCCall","rpcCall","result: [Document, number][]","Document","query: string","options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>","texts: string[]","metadatas: object[] | object","dbConfig: SupabaseLibArgs","docs: Document[]"],"sources":["../../src/vectorstores/supabase.ts"],"sourcesContent":["import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { PostgrestFilterBuilder } from \"@supabase/postgrest-js\";\nimport {\n  MaxMarginalRelevanceSearchOptions,\n  VectorStore,\n} from \"@langchain/core/vectorstores\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { Document } from \"@langchain/core/documents\";\nimport { maximalMarginalRelevance } from \"@langchain/core/utils/math\";\n\n/**\n * Interface for the parameters required for searching embeddings.\n */\ninterface SearchEmbeddingsParams {\n  query_embedding: number[];\n  match_count: number; // int\n  filter?: SupabaseMetadata | SupabaseFilterRPCCall;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SupabaseMetadata = Record<string, any>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SupabaseFilter = PostgrestFilterBuilder<any, any, any>;\nexport type SupabaseFilterRPCCall = (rpcCall: SupabaseFilter) => SupabaseFilter;\n\n/**\n * Interface for the response returned when searching embeddings.\n */\ninterface SearchEmbeddingsResponse {\n  id: number;\n  content: string;\n  metadata: object;\n  embedding: number[];\n  similarity: number;\n}\n\n/**\n * Interface for the arguments required to initialize a Supabase library.\n */\nexport interface SupabaseLibArgs {\n  client: SupabaseClient;\n  tableName?: string;\n  queryName?: string;\n  filter?: SupabaseMetadata | SupabaseFilterRPCCall;\n  upsertBatchSize?: number;\n}\n\n/**\n * Supabase vector store integration.\n *\n * Setup:\n * Install `@langchain/community` and `@supabase/supabase-js`.\n *\n * ```bash\n * npm install @langchain/community @supabase/supabase-js\n * ```\n *\n * See https://js.langchain.com/docs/integrations/vectorstores/supabase for\n * instructions on how to set up your Supabase instance.\n *\n * ## [Constructor args](https://api.js.langchain.com/classes/_langchain_community.vectorstores_supabase.SupabaseVectorStore.html#constructor)\n *\n * <details open>\n * <summary><strong>Instantiate</strong></summary>\n *\n * ```typescript\n * import { SupabaseVectorStore } from \"@langchain/community/vectorstores/supabase\";\n * import { OpenAIEmbeddings } from \"@langchain/openai\";\n *\n * import { createClient } from \"@supabase/supabase-js\";\n *\n * const embeddings = new OpenAIEmbeddings({\n *   model: \"text-embedding-3-small\",\n * });\n *\n * const supabaseClient = createClient(\n *   process.env.SUPABASE_URL,\n *   process.env.SUPABASE_PRIVATE_KEY\n * );\n *\n * const vectorStore = new SupabaseVectorStore(embeddings, {\n *   client: supabaseClient,\n *   tableName: \"documents\",\n *   queryName: \"match_documents\",\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 SupabaseVectorStore extends VectorStore {\n  declare FilterType: SupabaseMetadata | SupabaseFilterRPCCall;\n\n  client: SupabaseClient;\n\n  tableName: string;\n\n  queryName: string;\n\n  filter?: SupabaseMetadata | SupabaseFilterRPCCall;\n\n  upsertBatchSize = 500;\n\n  _vectorstoreType(): string {\n    return \"supabase\";\n  }\n\n  constructor(embeddings: EmbeddingsInterface, args: SupabaseLibArgs) {\n    super(embeddings, args);\n\n    this.client = args.client;\n    this.tableName = args.tableName || \"documents\";\n    this.queryName = args.queryName || \"match_documents\";\n    this.filter = args.filter;\n    this.upsertBatchSize = args.upsertBatchSize ?? this.upsertBatchSize;\n  }\n\n  /**\n   * Adds documents to the vector store.\n   * @param documents The documents to add.\n   * @param options Optional parameters for adding the documents.\n   * @returns A promise that resolves when the documents have been added.\n   */\n  async addDocuments(\n    documents: Document[],\n    options?: { ids?: string[] | number[] }\n  ) {\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   * Adds vectors to the vector store.\n   * @param vectors The vectors to add.\n   * @param documents The documents associated with the vectors.\n   * @param options Optional parameters for adding the vectors.\n   * @returns A promise that resolves with the IDs of the added vectors when the vectors have been added.\n   */\n  async addVectors(\n    vectors: number[][],\n    documents: Document[],\n    options?: { ids?: string[] | number[] }\n  ) {\n    const rows = vectors.map((embedding, idx) => ({\n      content: documents[idx].pageContent,\n      embedding,\n      metadata: documents[idx].metadata,\n    }));\n\n    // upsert returns 500/502/504 (yes really any of them) if given too many rows/characters\n    // ~2000 trips it, but my data is probably smaller than average pageContent and metadata\n    let returnedIds: string[] = [];\n    for (let i = 0; i < rows.length; i += this.upsertBatchSize) {\n      const chunk = rows.slice(i, i + this.upsertBatchSize).map((row, j) => {\n        if (options?.ids) {\n          return { id: options.ids[i + j], ...row };\n        }\n        return row;\n      });\n\n      const res = await this.client.from(this.tableName).upsert(chunk).select();\n      if (res.error) {\n        throw new Error(\n          `Error inserting: ${res.error.message} ${res.status} ${res.statusText}`\n        );\n      }\n      if (res.data) {\n        returnedIds = returnedIds.concat(res.data.map((row) => row.id));\n      }\n    }\n    return returnedIds;\n  }\n\n  /**\n   * Deletes vectors from the vector store.\n   * @param params The parameters for deleting vectors.\n   * @returns A promise that resolves when the vectors have been deleted.\n   */\n  async delete(params: { ids: string[] | number[] }): Promise<void> {\n    const { ids } = params;\n    for (const id of ids) {\n      await this.client.from(this.tableName).delete().eq(\"id\", id);\n    }\n  }\n\n  protected async _searchSupabase(\n    query: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<SearchEmbeddingsResponse[]> {\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 matchDocumentsParams: Partial<SearchEmbeddingsParams> = {\n      query_embedding: query,\n    };\n\n    let filterFunction: SupabaseFilterRPCCall;\n\n    if (typeof _filter === \"function\") {\n      filterFunction = (rpcCall) => _filter(rpcCall).limit(k);\n    } else if (typeof _filter === \"object\") {\n      matchDocumentsParams.filter = _filter;\n      matchDocumentsParams.match_count = k;\n      filterFunction = (rpcCall) => rpcCall;\n    } else {\n      throw new Error(\"invalid filter type\");\n    }\n\n    const rpcCall = this.client.rpc(this.queryName, matchDocumentsParams);\n\n    const { data: searches, error } = await filterFunction(rpcCall);\n\n    if (error) {\n      throw new Error(\n        `Error searching for documents: ${error.code} ${error.message} ${error.details}`\n      );\n    }\n\n    return searches;\n  }\n\n  /**\n   * Performs a similarity search on the vector store.\n   * @param query The query vector.\n   * @param k The number of results to return.\n   * @param filter Optional filter to apply to the search.\n   * @returns A promise that resolves with the search results when the search is complete.\n   */\n  async similaritySearchVectorWithScore(\n    query: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<[Document, number][]> {\n    const searches = await this._searchSupabase(query, k, filter);\n    const result: [Document, number][] = searches.map((resp) => [\n      new Document({\n        metadata: resp.metadata,\n        pageContent: resp.content,\n      }),\n      resp.similarity,\n    ]);\n\n    return result;\n  }\n\n  /**\n   * Return documents selected using the maximal marginal relevance.\n   * Maximal marginal relevance optimizes for similarity to the query AND diversity\n   * among selected documents.\n   *\n   * @param {string} query - Text to look up documents similar to.\n   * @param {number} options.k - Number of documents to return.\n   * @param {number} options.fetchK=20- Number of documents to fetch before passing to the MMR algorithm.\n   * @param {number} options.lambda=0.5 - Number between 0 and 1 that determines the degree of diversity among the results,\n   *                 where 0 corresponds to maximum diversity and 1 to minimum diversity.\n   * @param {SupabaseLibArgs} options.filter - Optional filter to apply to the search.\n   *\n   * @returns {Promise<Document[]>} - List of documents selected by maximal marginal relevance.\n   */\n  async maxMarginalRelevanceSearch(\n    query: string,\n    options: MaxMarginalRelevanceSearchOptions<this[\"FilterType\"]>\n  ): Promise<Document[]> {\n    const queryEmbedding = await this.embeddings.embedQuery(query);\n\n    const searches = await this._searchSupabase(\n      queryEmbedding,\n      options.fetchK ?? 20,\n      options.filter\n    );\n\n    const embeddingList = searches.map((searchResp) => searchResp.embedding);\n\n    const mmrIndexes = maximalMarginalRelevance(\n      queryEmbedding,\n      embeddingList,\n      options.lambda,\n      options.k\n    );\n\n    return mmrIndexes.map(\n      (idx) =>\n        new Document({\n          metadata: searches[idx].metadata,\n          pageContent: searches[idx].content,\n        })\n    );\n  }\n\n  /**\n   * Creates a new SupabaseVectorStore instance from an array of texts.\n   * @param texts The texts to create documents from.\n   * @param metadatas The metadata for the documents.\n   * @param embeddings The embeddings to use.\n   * @param dbConfig The configuration for the Supabase database.\n   * @returns A promise that resolves with a new SupabaseVectorStore instance when the instance has been created.\n   */\n  static async fromTexts(\n    texts: string[],\n    metadatas: object[] | object,\n    embeddings: EmbeddingsInterface,\n    dbConfig: SupabaseLibArgs\n  ): Promise<SupabaseVectorStore> {\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 SupabaseVectorStore.fromDocuments(docs, embeddings, dbConfig);\n  }\n\n  /**\n   * Creates a new SupabaseVectorStore instance from an array of documents.\n   * @param docs The documents to create the instance from.\n   * @param embeddings The embeddings to use.\n   * @param dbConfig The configuration for the Supabase database.\n   * @returns A promise that resolves with a new SupabaseVectorStore instance when the instance has been created.\n   */\n  static async fromDocuments(\n    docs: Document[],\n    embeddings: EmbeddingsInterface,\n    dbConfig: SupabaseLibArgs\n  ): Promise<SupabaseVectorStore> {\n    const instance = new this(embeddings, dbConfig);\n    await instance.addDocuments(docs);\n    return instance;\n  }\n\n  /**\n   * Creates a new SupabaseVectorStore instance from an existing index.\n   * @param embeddings The embeddings to use.\n   * @param dbConfig The configuration for the Supabase database.\n   * @returns A promise that resolves with a new SupabaseVectorStore instance when the instance has been created.\n   */\n  static async fromExistingIndex(\n    embeddings: EmbeddingsInterface,\n    dbConfig: SupabaseLibArgs\n  ): Promise<SupabaseVectorStore> {\n    const instance = new this(embeddings, dbConfig);\n    return instance;\n  }\n}\n"],"mappings":"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"}