{"version":3,"file":"convex.cjs","names":["VectorStore","Document"],"sources":["../../src/vectorstores/convex.ts"],"sourcesContent":["import {\n  DocumentByInfo,\n  FieldPaths,\n  FilterExpression,\n  FunctionReference,\n  GenericActionCtx,\n  GenericDataModel,\n  GenericTableInfo,\n  NamedTableInfo,\n  NamedVectorIndex,\n  TableNamesInDataModel,\n  VectorFilterBuilder,\n  VectorIndexNames,\n  makeFunctionReference,\n} from \"convex/server\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport { Document } from \"@langchain/core/documents\";\n\n/**\n * Type that defines the config required to initialize the\n * ConvexVectorStore class. It includes the table name,\n * index name, text field name, and embedding field name.\n */\nexport type ConvexVectorStoreConfig<\n  DataModel extends GenericDataModel,\n  TableName extends TableNamesInDataModel<DataModel>,\n  IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>>,\n  TextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  EmbeddingFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  MetadataFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  InsertMutation extends FunctionReference<\n    \"mutation\",\n    \"internal\",\n    { table: string; document: object }\n  >,\n  GetQuery extends FunctionReference<\n    \"query\",\n    \"internal\",\n    { id: string },\n    object | null\n  >,\n> = {\n  readonly ctx: GenericActionCtx<DataModel>;\n  /**\n   * Defaults to \"documents\"\n   */\n  readonly table?: TableName;\n  /**\n   * Defaults to \"byEmbedding\"\n   */\n  readonly index?: IndexName;\n  /**\n   * Defaults to \"text\"\n   */\n  readonly textField?: TextFieldName;\n  /**\n   * Defaults to \"embedding\"\n   */\n  readonly embeddingField?: EmbeddingFieldName;\n  /**\n   * Defaults to \"metadata\"\n   */\n  readonly metadataField?: MetadataFieldName;\n  /**\n   * Defaults to `internal.langchain.db.insert`\n   */\n  readonly insert?: InsertMutation;\n  /**\n   * Defaults to `internal.langchain.db.get`\n   */\n  readonly get?: GetQuery;\n};\n\n/**\n * Class that is a wrapper around Convex storage and vector search. It is used\n * to insert embeddings in Convex documents with a vector search index,\n * and perform a vector search on them.\n *\n * ConvexVectorStore does NOT implement maxMarginalRelevanceSearch.\n */\nexport class ConvexVectorStore<\n  DataModel extends GenericDataModel,\n  TableName extends TableNamesInDataModel<DataModel>,\n  IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>>,\n  TextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  EmbeddingFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  MetadataFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n  InsertMutation extends FunctionReference<\n    \"mutation\",\n    \"internal\",\n    { table: string; document: object }\n  >,\n  GetQuery extends FunctionReference<\n    \"query\",\n    \"internal\",\n    { id: string },\n    object | null\n  >,\n> extends VectorStore {\n  /**\n   * Type that defines the filter used in the\n   * similaritySearchVectorWithScore and maxMarginalRelevanceSearch methods.\n   * It includes limit, filter and a flag to include embeddings.\n   */\n  declare FilterType: {\n    filter?: (\n      q: VectorFilterBuilder<\n        DocumentByInfo<GenericTableInfo>,\n        NamedVectorIndex<NamedTableInfo<DataModel, TableName>, IndexName>\n      >\n    ) => FilterExpression<boolean>;\n    includeEmbeddings?: boolean;\n  };\n\n  private readonly ctx: GenericActionCtx<DataModel>;\n\n  private readonly table: TableName;\n\n  private readonly index: IndexName;\n\n  private readonly textField: TextFieldName;\n\n  private readonly embeddingField: EmbeddingFieldName;\n\n  private readonly metadataField: MetadataFieldName;\n\n  private readonly insert: InsertMutation;\n\n  private readonly get: GetQuery;\n\n  _vectorstoreType(): string {\n    return \"convex\";\n  }\n\n  constructor(\n    embeddings: EmbeddingsInterface,\n    config: ConvexVectorStoreConfig<\n      DataModel,\n      TableName,\n      IndexName,\n      TextFieldName,\n      EmbeddingFieldName,\n      MetadataFieldName,\n      InsertMutation,\n      GetQuery\n    >\n  ) {\n    super(embeddings, config);\n    this.ctx = config.ctx;\n    this.table = config.table ?? (\"documents\" as TableName);\n    this.index = config.index ?? (\"byEmbedding\" as IndexName);\n    this.textField = config.textField ?? (\"text\" as TextFieldName);\n    this.embeddingField =\n      config.embeddingField ?? (\"embedding\" as EmbeddingFieldName);\n    this.metadataField =\n      config.metadataField ?? (\"metadata\" as MetadataFieldName);\n    this.insert =\n      // oxlint-disable-next-line typescript/no-explicit-any\n      config.insert ?? (makeFunctionReference(\"langchain/db:insert\") as any);\n    // oxlint-disable-next-line typescript/no-explicit-any\n    this.get = config.get ?? (makeFunctionReference(\"langchain/db:get\") as any);\n  }\n\n  /**\n   * Add vectors and their corresponding documents to the Convex table.\n   * @param vectors Vectors to be added.\n   * @param documents Corresponding documents to be added.\n   * @returns Promise that resolves when the vectors and documents have been added.\n   */\n  async addVectors(vectors: number[][], documents: Document[]): Promise<void> {\n    const convexDocuments = vectors.map((embedding, idx) => ({\n      [this.textField]: documents[idx].pageContent,\n      [this.embeddingField]: embedding,\n      [this.metadataField]: documents[idx].metadata,\n    }));\n    // TODO: Remove chunking when Convex handles the concurrent requests correctly\n    const PAGE_SIZE = 16;\n    for (let i = 0; i < convexDocuments.length; i += PAGE_SIZE) {\n      await Promise.all(\n        convexDocuments.slice(i, i + PAGE_SIZE).map((document) =>\n          this.ctx.runMutation(this.insert, {\n            table: this.table,\n            document,\n            // oxlint-disable-next-line typescript/no-explicit-any\n          } as any)\n        )\n      );\n    }\n  }\n\n  /**\n   * Add documents to the Convex table. It first converts\n   * the documents to vectors using the embeddings and then calls the\n   * addVectors method.\n   * @param documents Documents to be added.\n   * @returns Promise that resolves when the documents have been added.\n   */\n  async addDocuments(documents: Document[]): Promise<void> {\n    const texts = documents.map(({ pageContent }) => pageContent);\n    return this.addVectors(\n      await this.embeddings.embedDocuments(texts),\n      documents\n    );\n  }\n\n  /**\n   * Similarity search on the vectors stored in the\n   * Convex table. It returns a list of documents and their\n   * corresponding similarity scores.\n   * @param query Query vector for the similarity search.\n   * @param k Number of nearest neighbors to return.\n   * @param filter Optional filter to be applied.\n   * @returns Promise that resolves to a list of documents and their corresponding similarity scores.\n   */\n  async similaritySearchVectorWithScore(\n    query: number[],\n    k: number,\n    filter?: this[\"FilterType\"]\n  ): Promise<[Document, number][]> {\n    const idsAndScores = await this.ctx.vectorSearch(this.table, this.index, {\n      vector: query,\n      limit: k,\n      filter: filter?.filter,\n    });\n\n    const documents = await Promise.all(\n      idsAndScores.map(({ _id }) =>\n        // oxlint-disable-next-line typescript/no-explicit-any\n        this.ctx.runQuery(this.get, { id: _id } as any)\n      )\n    );\n\n    return documents.map(\n      (\n        {\n          [this.textField]: text,\n          [this.embeddingField]: embedding,\n          [this.metadataField]: metadata,\n        },\n        idx\n      ) => [\n        new Document({\n          pageContent: text as string,\n          metadata: {\n            ...metadata,\n            ...(filter?.includeEmbeddings ? { embedding } : null),\n          },\n        }),\n        idsAndScores[idx]._score,\n      ]\n    );\n  }\n\n  /**\n   * Static method to create an instance of ConvexVectorStore from a\n   * list of texts. It first converts the texts to vectors and then adds\n   * them to the Convex table.\n   * @param texts List of texts to be converted to vectors.\n   * @param metadatas Metadata for the texts.\n   * @param embeddings Embeddings to be used for conversion.\n   * @param dbConfig Database configuration for Convex.\n   * @returns Promise that resolves to a new instance of ConvexVectorStore.\n   */\n  static async fromTexts<\n    DataModel extends GenericDataModel,\n    TableName extends TableNamesInDataModel<DataModel>,\n    IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>>,\n    TextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    EmbeddingFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    MetadataFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    InsertMutation extends FunctionReference<\n      \"mutation\",\n      \"internal\",\n      { table: string; document: object }\n    >,\n    GetQuery extends FunctionReference<\n      \"query\",\n      \"internal\",\n      { id: string },\n      object | null\n    >,\n  >(\n    texts: string[],\n    metadatas: object[] | object,\n    embeddings: EmbeddingsInterface,\n    dbConfig: ConvexVectorStoreConfig<\n      DataModel,\n      TableName,\n      IndexName,\n      TextFieldName,\n      EmbeddingFieldName,\n      MetadataFieldName,\n      InsertMutation,\n      GetQuery\n    >\n  ): Promise<\n    ConvexVectorStore<\n      DataModel,\n      TableName,\n      IndexName,\n      TextFieldName,\n      EmbeddingFieldName,\n      MetadataFieldName,\n      InsertMutation,\n      GetQuery\n    >\n  > {\n    const docs = texts.map(\n      (text, i) =>\n        new Document({\n          pageContent: text,\n          metadata: Array.isArray(metadatas) ? metadatas[i] : metadatas,\n        })\n    );\n    return ConvexVectorStore.fromDocuments(docs, embeddings, dbConfig);\n  }\n\n  /**\n   * Static method to create an instance of ConvexVectorStore from a\n   * list of documents. It first converts the documents to vectors and then\n   * adds them to the Convex table.\n   * @param docs List of documents to be converted to vectors.\n   * @param embeddings Embeddings to be used for conversion.\n   * @param dbConfig Database configuration for Convex.\n   * @returns Promise that resolves to a new instance of ConvexVectorStore.\n   */\n  static async fromDocuments<\n    DataModel extends GenericDataModel,\n    TableName extends TableNamesInDataModel<DataModel>,\n    IndexName extends VectorIndexNames<NamedTableInfo<DataModel, TableName>>,\n    TextFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    EmbeddingFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    MetadataFieldName extends FieldPaths<NamedTableInfo<DataModel, TableName>>,\n    InsertMutation extends FunctionReference<\n      \"mutation\",\n      \"internal\",\n      { table: string; document: object }\n    >,\n    GetQuery extends FunctionReference<\n      \"query\",\n      \"internal\",\n      { id: string },\n      object | null\n    >,\n  >(\n    docs: Document[],\n    embeddings: EmbeddingsInterface,\n    dbConfig: ConvexVectorStoreConfig<\n      DataModel,\n      TableName,\n      IndexName,\n      TextFieldName,\n      EmbeddingFieldName,\n      MetadataFieldName,\n      InsertMutation,\n      GetQuery\n    >\n  ): Promise<\n    ConvexVectorStore<\n      DataModel,\n      TableName,\n      IndexName,\n      TextFieldName,\n      EmbeddingFieldName,\n      MetadataFieldName,\n      InsertMutation,\n      GetQuery\n    >\n  > {\n    const instance = new this(embeddings, dbConfig);\n    await instance.addDocuments(docs);\n    return instance;\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;AAiFA,IAAa,oBAAb,MAAa,0BAkBHA,6BAAAA,YAAY;CAgBpB;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA,mBAA2B;AACzB,SAAO;;CAGT,YACE,YACA,QAUA;AACA,QAAM,YAAY,OAAO;AACzB,OAAK,MAAM,OAAO;AAClB,OAAK,QAAQ,OAAO,SAAU;AAC9B,OAAK,QAAQ,OAAO,SAAU;AAC9B,OAAK,YAAY,OAAO,aAAc;AACtC,OAAK,iBACH,OAAO,kBAAmB;AAC5B,OAAK,gBACH,OAAO,iBAAkB;AAC3B,OAAK,SAEH,OAAO,WAAA,GAAA,cAAA,uBAAiC,sBAAsB;AAEhE,OAAK,MAAM,OAAO,QAAA,GAAA,cAAA,uBAA8B,mBAAmB;;;;;;;;CASrE,MAAM,WAAW,SAAqB,WAAsC;EAC1E,MAAM,kBAAkB,QAAQ,KAAK,WAAW,SAAS;IACtD,KAAK,YAAY,UAAU,KAAK;IAChC,KAAK,iBAAiB;IACtB,KAAK,gBAAgB,UAAU,KAAK;GACtC,EAAE;EAEH,MAAM,YAAY;AAClB,OAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK,UAC/C,OAAM,QAAQ,IACZ,gBAAgB,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,aAC3C,KAAK,IAAI,YAAY,KAAK,QAAQ;GAChC,OAAO,KAAK;GACZ;GAED,CAAQ,CACV,CACF;;;;;;;;;CAWL,MAAM,aAAa,WAAsC;EACvD,MAAM,QAAQ,UAAU,KAAK,EAAE,kBAAkB,YAAY;AAC7D,SAAO,KAAK,WACV,MAAM,KAAK,WAAW,eAAe,MAAM,EAC3C,UACD;;;;;;;;;;;CAYH,MAAM,gCACJ,OACA,GACA,QAC+B;EAC/B,MAAM,eAAe,MAAM,KAAK,IAAI,aAAa,KAAK,OAAO,KAAK,OAAO;GACvE,QAAQ;GACR,OAAO;GACP,QAAQ,QAAQ;GACjB,CAAC;AASF,UAPkB,MAAM,QAAQ,IAC9B,aAAa,KAAK,EAAE,UAElB,KAAK,IAAI,SAAS,KAAK,KAAK,EAAE,IAAI,KAAK,CAAQ,CAChD,CACF,EAEgB,KAEb,GACG,KAAK,YAAY,OACjB,KAAK,iBAAiB,YACtB,KAAK,gBAAgB,YAExB,QACG,CACH,IAAIC,0BAAAA,SAAS;GACX,aAAa;GACb,UAAU;IACR,GAAG;IACH,GAAI,QAAQ,oBAAoB,EAAE,WAAW,GAAG;IACjD;GACF,CAAC,EACF,aAAa,KAAK,OACnB,CACF;;;;;;;;;;;;CAaH,aAAa,UAmBX,OACA,WACA,YACA,UAqBA;EACA,MAAM,OAAO,MAAM,KAChB,MAAM,MACL,IAAIA,0BAAAA,SAAS;GACX,aAAa;GACb,UAAU,MAAM,QAAQ,UAAU,GAAG,UAAU,KAAK;GACrD,CAAC,CACL;AACD,SAAO,kBAAkB,cAAc,MAAM,YAAY,SAAS;;;;;;;;;;;CAYpE,aAAa,cAmBX,MACA,YACA,UAqBA;EACA,MAAM,WAAW,IAAI,KAAK,YAAY,SAAS;AAC/C,QAAM,SAAS,aAAa,KAAK;AACjC,SAAO"}