UNPKG

@langchain/community

Version:
1 lines • 11.9 kB
{"version":3,"file":"libsql.cjs","names":["VectorStore","embeddings: EmbeddingsInterface","options: LibSQLVectorStoreArgs","documents: Document<Metadata>[]","vectors: number[][]","ids: string[]","insertQueries: InStatement[]","query: number[]","k: number","filter?: this[\"FilterType\"]","SqliteWhereBuilder","row: any","Document","params: {\n ids?: string[] | number[];\n deleteAll?: boolean;\n }","texts: string[]","metadatas: Metadata[] | Metadata","docs: Document<Metadata>[]"],"sources":["../../src/vectorstores/libsql.ts"],"sourcesContent":["import { Document } from \"@langchain/core/documents\";\nimport type { EmbeddingsInterface } from \"@langchain/core/embeddings\";\nimport { VectorStore } from \"@langchain/core/vectorstores\";\nimport type { Client, InStatement } from \"@libsql/client\";\nimport {\n SqliteWhereBuilder,\n WhereCondition,\n} from \"../utils/sqlite_where_builder.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype MetadataDefault = Record<string, any>;\n\n/**\n * Interface for LibSQLVectorStore configuration options.\n */\nexport interface LibSQLVectorStoreArgs {\n db: Client;\n /** Name of the table to store vectors. Defaults to \"vectors\". */\n table?: string;\n /** Name of the column to store embeddings. Defaults to \"embedding\". */\n column?: string;\n // TODO: Support adding additional columns to the table for metadata.\n}\n\n/**\n * A vector store using LibSQL/Turso for storage and retrieval.\n */\nexport class LibSQLVectorStore<\n Metadata extends MetadataDefault = MetadataDefault,\n> extends VectorStore {\n declare FilterType: string | InStatement | WhereCondition<Metadata>;\n\n private db;\n\n private readonly table: string;\n\n private readonly column: string;\n\n /**\n * Returns the type of vector store.\n * @returns {string} The string \"libsql\".\n */\n _vectorstoreType(): string {\n return \"libsql\";\n }\n\n /**\n * Initializes a new instance of the LibSQLVectorStore.\n * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n * @param {Client} db - The LibSQL client instance.\n * @param {LibSQLVectorStoreArgs} options - Configuration options for the vector store.\n */\n constructor(embeddings: EmbeddingsInterface, options: LibSQLVectorStoreArgs) {\n super(embeddings, options);\n\n this.db = options.db;\n this.table = options.table || \"vectors\";\n this.column = options.column || \"embedding\";\n }\n\n /**\n * Adds documents to the vector store.\n * @param {Document<Metadata>[]} documents - The documents to add.\n * @returns {Promise<string[]>} The IDs of the added documents.\n */\n async addDocuments(documents: Document<Metadata>[]): Promise<string[]> {\n const texts = documents.map(({ pageContent }) => pageContent);\n const embeddings = await this.embeddings.embedDocuments(texts);\n\n return this.addVectors(embeddings, documents);\n }\n\n /**\n * Adds vectors to the vector store.\n * @param {number[][]} vectors - The vectors to add.\n * @param {Document<Metadata>[]} documents - The documents associated with the vectors.\n * @returns {Promise<string[]>} The IDs of the added vectors.\n */\n async addVectors(\n vectors: number[][],\n documents: Document<Metadata>[]\n ): Promise<string[]> {\n const rows = vectors.map((embedding, idx) => ({\n content: documents[idx].pageContent,\n embedding: `[${embedding.join(\",\")}]`,\n metadata: JSON.stringify(documents[idx].metadata),\n }));\n\n const batchSize = 100;\n const ids: string[] = [];\n\n for (let i = 0; i < rows.length; i += batchSize) {\n const chunk = rows.slice(i, i + batchSize);\n\n const insertQueries: InStatement[] = chunk.map((row) => ({\n sql: `INSERT INTO ${this.table} (content, metadata, ${this.column}) VALUES (:content, :metadata, vector(:embedding)) RETURNING ${this.table}.rowid AS id`,\n args: row,\n }));\n\n const results = await this.db.batch(insertQueries);\n\n ids.push(\n ...results.flatMap((result) => result.rows.map((row) => String(row.id)))\n );\n }\n\n return ids;\n }\n\n /**\n * Performs a similarity search using a vector query and returns documents with their scores.\n * @param {number[]} query - The query vector.\n * @param {number} k - The number of results to return.\n * @returns {Promise<[Document<Metadata>, number][]>} An array of tuples containing the similar documents and their scores.\n */\n async similaritySearchVectorWithScore(\n query: number[],\n k: number,\n filter?: this[\"FilterType\"]\n ): Promise<[Document<Metadata>, number][]> {\n // Potential SQL injection risk if query vector is not properly sanitized.\n if (!query.every((num) => typeof num === \"number\" && !Number.isNaN(num))) {\n throw new Error(\"Invalid query vector: all elements must be numbers\");\n }\n\n const queryVector = `[${query.join(\",\")}]`;\n\n const sql = {\n sql: `SELECT ${this.table}.rowid as id, ${this.table}.content, ${this.table}.metadata, vector_distance_cos(${this.table}.${this.column}, vector(:queryVector)) AS distance\n FROM vector_top_k('idx_${this.table}_${this.column}', vector(:queryVector), CAST(:k AS INTEGER)) as top_k\n JOIN ${this.table} ON top_k.rowid = ${this.table}.rowid`,\n args: { queryVector, k },\n } satisfies InStatement;\n\n // Filter is a raw sql where clause, so append it to the join\n if (typeof filter === \"string\") {\n sql.sql += ` AND ${filter}`;\n } else if (typeof filter === \"object\") {\n // Filter is an in statement.\n if (\"sql\" in filter) {\n sql.sql += ` AND ${filter.sql}`;\n sql.args = {\n ...filter.args,\n ...sql.args,\n };\n } else {\n const builder = new SqliteWhereBuilder(filter);\n const where = builder.buildWhereClause();\n\n sql.sql += ` AND ${where.sql}`;\n sql.args = {\n ...where.args,\n ...sql.args,\n };\n }\n }\n\n const results = await this.db.execute(sql);\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return results.rows.map((row: any) => {\n const metadata = JSON.parse(row.metadata);\n\n const doc = new Document<Metadata>({\n id: String(row.id),\n metadata,\n pageContent: row.content,\n });\n\n return [doc, row.distance];\n });\n }\n\n /**\n * Deletes vectors from the store.\n * @param {Object} params - Delete parameters.\n * @param {string[] | number[]} [params.ids] - The ids of the vectors to delete.\n * @returns {Promise<void>}\n */\n async delete(params: {\n ids?: string[] | number[];\n deleteAll?: boolean;\n }): Promise<void> {\n if (params.deleteAll) {\n await this.db.execute(`DELETE FROM ${this.table}`);\n } else if (params.ids !== undefined) {\n await this.db.batch(\n params.ids.map((id) => ({\n sql: `DELETE FROM ${this.table} WHERE rowid = :id`,\n args: { id },\n }))\n );\n } else {\n throw new Error(\n `You must provide an \"ids\" parameter or a \"deleteAll\" parameter.`\n );\n }\n }\n\n /**\n * Creates a new LibSQLVectorStore instance from texts.\n * @param {string[]} texts - The texts to add to the store.\n * @param {object[] | object} metadatas - The metadata for the texts.\n * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n * @param {Client} dbClient - The LibSQL client instance.\n * @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.\n * @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.\n */\n static async fromTexts<Metadata extends MetadataDefault = MetadataDefault>(\n texts: string[],\n metadatas: Metadata[] | Metadata,\n embeddings: EmbeddingsInterface,\n options: LibSQLVectorStoreArgs\n ): Promise<LibSQLVectorStore<Metadata>> {\n const docs = texts.map((text, i) => {\n const metadata = Array.isArray(metadatas) ? metadatas[i] : metadatas;\n\n return new Document({ pageContent: text, metadata });\n });\n\n return LibSQLVectorStore.fromDocuments(docs, embeddings, options);\n }\n\n /**\n * Creates a new LibSQLVectorStore instance from documents.\n * @param {Document[]} docs - The documents to add to the store.\n * @param {EmbeddingsInterface} embeddings - The embeddings interface to use.\n * @param {Client} dbClient - The LibSQL client instance.\n * @param {LibSQLVectorStoreArgs} [options] - Configuration options for the vector store.\n * @returns {Promise<LibSQLVectorStore>} A new LibSQLVectorStore instance.\n */\n static async fromDocuments<\n Metadata extends MetadataDefault = MetadataDefault,\n >(\n docs: Document<Metadata>[],\n embeddings: EmbeddingsInterface,\n options: LibSQLVectorStoreArgs\n ): Promise<LibSQLVectorStore<Metadata>> {\n const instance = new this<Metadata>(embeddings, options);\n\n await instance.addDocuments(docs);\n\n return instance;\n }\n}\n"],"mappings":"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"}