langchain 0.0.174 → 0.0.175

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,173 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { makeFunctionReference, } from "convex/server";
3
+ import { Document } from "../document.js";
4
+ import { VectorStore } from "./base.js";
5
+ /**
6
+ * Class that is a wrapper around Convex storage and vector search. It is used
7
+ * to insert embeddings in Convex documents with a vector search index,
8
+ * and perform a vector search on them.
9
+ *
10
+ * ConvexVectorStore does NOT implement maxMarginalRelevanceSearch.
11
+ */
12
+ export class ConvexVectorStore extends VectorStore {
13
+ _vectorstoreType() {
14
+ return "convex";
15
+ }
16
+ constructor(embeddings, config) {
17
+ super(embeddings, config);
18
+ Object.defineProperty(this, "ctx", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: void 0
23
+ });
24
+ Object.defineProperty(this, "table", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: void 0
29
+ });
30
+ Object.defineProperty(this, "index", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: void 0
35
+ });
36
+ Object.defineProperty(this, "textField", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: void 0
41
+ });
42
+ Object.defineProperty(this, "embeddingField", {
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true,
46
+ value: void 0
47
+ });
48
+ Object.defineProperty(this, "metadataField", {
49
+ enumerable: true,
50
+ configurable: true,
51
+ writable: true,
52
+ value: void 0
53
+ });
54
+ Object.defineProperty(this, "insert", {
55
+ enumerable: true,
56
+ configurable: true,
57
+ writable: true,
58
+ value: void 0
59
+ });
60
+ Object.defineProperty(this, "get", {
61
+ enumerable: true,
62
+ configurable: true,
63
+ writable: true,
64
+ value: void 0
65
+ });
66
+ this.ctx = config.ctx;
67
+ this.table = config.table ?? "documents";
68
+ this.index = config.index ?? "byEmbedding";
69
+ this.textField = config.textField ?? "text";
70
+ this.embeddingField =
71
+ config.embeddingField ?? "embedding";
72
+ this.metadataField =
73
+ config.metadataField ?? "metadata";
74
+ this.insert =
75
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
76
+ config.insert ?? makeFunctionReference("langchain/db:insert");
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ this.get = config.get ?? makeFunctionReference("langchain/db:get");
79
+ }
80
+ /**
81
+ * Add vectors and their corresponding documents to the Convex table.
82
+ * @param vectors Vectors to be added.
83
+ * @param documents Corresponding documents to be added.
84
+ * @returns Promise that resolves when the vectors and documents have been added.
85
+ */
86
+ async addVectors(vectors, documents) {
87
+ const convexDocuments = vectors.map((embedding, idx) => ({
88
+ [this.textField]: documents[idx].pageContent,
89
+ [this.embeddingField]: embedding,
90
+ [this.metadataField]: documents[idx].metadata,
91
+ }));
92
+ // TODO: Remove chunking when Convex handles the concurrent requests correctly
93
+ const PAGE_SIZE = 16;
94
+ for (let i = 0; i < convexDocuments.length; i += PAGE_SIZE) {
95
+ await Promise.all(convexDocuments.slice(i, i + PAGE_SIZE).map((document) => this.ctx.runMutation(this.insert, {
96
+ table: this.table,
97
+ document,
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ })));
100
+ }
101
+ }
102
+ /**
103
+ * Add documents to the Convex table. It first converts
104
+ * the documents to vectors using the embeddings and then calls the
105
+ * addVectors method.
106
+ * @param documents Documents to be added.
107
+ * @returns Promise that resolves when the documents have been added.
108
+ */
109
+ async addDocuments(documents) {
110
+ const texts = documents.map(({ pageContent }) => pageContent);
111
+ return this.addVectors(await this.embeddings.embedDocuments(texts), documents);
112
+ }
113
+ /**
114
+ * Similarity search on the vectors stored in the
115
+ * Convex table. It returns a list of documents and their
116
+ * corresponding similarity scores.
117
+ * @param query Query vector for the similarity search.
118
+ * @param k Number of nearest neighbors to return.
119
+ * @param filter Optional filter to be applied.
120
+ * @returns Promise that resolves to a list of documents and their corresponding similarity scores.
121
+ */
122
+ async similaritySearchVectorWithScore(query, k, filter) {
123
+ const idsAndScores = await this.ctx.vectorSearch(this.table, this.index, {
124
+ vector: query,
125
+ limit: k,
126
+ filter: filter?.filter,
127
+ });
128
+ const documents = await Promise.all(idsAndScores.map(({ _id }) =>
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
+ this.ctx.runQuery(this.get, { id: _id })));
131
+ return documents.map(({ [this.textField]: text, [this.embeddingField]: embedding, [this.metadataField]: metadata, }, idx) => [
132
+ new Document({
133
+ pageContent: text,
134
+ metadata: {
135
+ ...metadata,
136
+ ...(filter?.includeEmbeddings ? { embedding } : null),
137
+ },
138
+ }),
139
+ idsAndScores[idx]._score,
140
+ ]);
141
+ }
142
+ /**
143
+ * Static method to create an instance of ConvexVectorStore from a
144
+ * list of texts. It first converts the texts to vectors and then adds
145
+ * them to the Convex table.
146
+ * @param texts List of texts to be converted to vectors.
147
+ * @param metadatas Metadata for the texts.
148
+ * @param embeddings Embeddings to be used for conversion.
149
+ * @param dbConfig Database configuration for Convex.
150
+ * @returns Promise that resolves to a new instance of ConvexVectorStore.
151
+ */
152
+ static async fromTexts(texts, metadatas, embeddings, dbConfig) {
153
+ const docs = texts.map((text, i) => new Document({
154
+ pageContent: text,
155
+ metadata: Array.isArray(metadatas) ? metadatas[i] : metadatas,
156
+ }));
157
+ return ConvexVectorStore.fromDocuments(docs, embeddings, dbConfig);
158
+ }
159
+ /**
160
+ * Static method to create an instance of ConvexVectorStore from a
161
+ * list of documents. It first converts the documents to vectors and then
162
+ * adds them to the Convex table.
163
+ * @param docs List of documents to be converted to vectors.
164
+ * @param embeddings Embeddings to be used for conversion.
165
+ * @param dbConfig Database configuration for Convex.
166
+ * @returns Promise that resolves to a new instance of ConvexVectorStore.
167
+ */
168
+ static async fromDocuments(docs, embeddings, dbConfig) {
169
+ const instance = new this(embeddings, dbConfig);
170
+ await instance.addDocuments(docs);
171
+ return instance;
172
+ }
173
+ }
@@ -577,11 +577,13 @@ function genCollectionName() {
577
577
  }
578
578
  function getTextFieldMaxLength(documents) {
579
579
  let textMaxLength = 0;
580
+ const textEncoder = new TextEncoder();
580
581
  // eslint-disable-next-line no-plusplus
581
582
  for (let i = 0; i < documents.length; i++) {
582
583
  const text = documents[i].pageContent;
583
- if (text.length > textMaxLength) {
584
- textMaxLength = text.length;
584
+ const textLengthInBytes = textEncoder.encode(text).length;
585
+ if (textLengthInBytes > textMaxLength) {
586
+ textMaxLength = textLengthInBytes;
585
587
  }
586
588
  }
587
589
  return textMaxLength;
@@ -550,11 +550,13 @@ function genCollectionName() {
550
550
  }
551
551
  function getTextFieldMaxLength(documents) {
552
552
  let textMaxLength = 0;
553
+ const textEncoder = new TextEncoder();
553
554
  // eslint-disable-next-line no-plusplus
554
555
  for (let i = 0; i < documents.length; i++) {
555
556
  const text = documents[i].pageContent;
556
- if (text.length > textMaxLength) {
557
- textMaxLength = text.length;
557
+ const textLengthInBytes = textEncoder.encode(text).length;
558
+ if (textLengthInBytes > textMaxLength) {
559
+ textMaxLength = textLengthInBytes;
558
560
  }
559
561
  }
560
562
  return textMaxLength;
@@ -206,14 +206,36 @@ class VercelPostgres extends base_js_1.VectorStore {
206
206
  */
207
207
  async similaritySearchVectorWithScore(query, k, filter) {
208
208
  const embeddingString = `[${query.join(",")}]`;
209
- const _filter = filter ?? "{}";
209
+ const _filter = filter ?? {};
210
+ const whereClauses = [];
211
+ const values = [embeddingString, k];
212
+ let paramCount = values.length;
213
+ for (const [key, value] of Object.entries(_filter)) {
214
+ if (typeof value === "object" && value !== null) {
215
+ const currentParamCount = paramCount;
216
+ const placeholders = value.in
217
+ .map((_, index) => `$${currentParamCount + index + 1}`)
218
+ .join(",");
219
+ whereClauses.push(`${this.metadataColumnName}->>'${key}' IN (${placeholders})`);
220
+ values.push(...value.in);
221
+ paramCount += value.in.length;
222
+ }
223
+ else {
224
+ paramCount += 1;
225
+ whereClauses.push(`${this.metadataColumnName}->>'${key}' = $${paramCount}`);
226
+ values.push(value);
227
+ }
228
+ }
229
+ const whereClause = whereClauses.length
230
+ ? `WHERE ${whereClauses.join(" AND ")}`
231
+ : "";
210
232
  const queryString = `
211
- SELECT *, ${this.vectorColumnName} <=> $1 as "_distance"
212
- FROM ${this.tableName}
213
- WHERE ${this.metadataColumnName} @> $2
214
- ORDER BY "_distance" ASC
215
- LIMIT $3;`;
216
- const documents = (await this.client.query(queryString, [embeddingString, _filter, k])).rows;
233
+ SELECT *, ${this.vectorColumnName} <=> $1 as "_distance"
234
+ FROM ${this.tableName}
235
+ ${whereClause}
236
+ ORDER BY "_distance" ASC
237
+ LIMIT $2;`;
238
+ const documents = (await this.client.query(queryString, values)).rows;
217
239
  const results = [];
218
240
  for (const doc of documents) {
219
241
  if (doc._distance != null && doc[this.contentColumnName] != null) {
@@ -2,7 +2,7 @@ import { type VercelPool, type VercelPoolClient, type VercelPostgresPoolConfig }
2
2
  import { VectorStore } from "./base.js";
3
3
  import { Embeddings } from "../embeddings/base.js";
4
4
  import { Document } from "../document.js";
5
- type Metadata = Record<string, unknown>;
5
+ type Metadata = Record<string, string | number | Record<"in", string[]>>;
6
6
  /**
7
7
  * Interface that defines the arguments required to create a
8
8
  * `VercelPostgres` instance. It includes Postgres connection options,
@@ -203,14 +203,36 @@ export class VercelPostgres extends VectorStore {
203
203
  */
204
204
  async similaritySearchVectorWithScore(query, k, filter) {
205
205
  const embeddingString = `[${query.join(",")}]`;
206
- const _filter = filter ?? "{}";
206
+ const _filter = filter ?? {};
207
+ const whereClauses = [];
208
+ const values = [embeddingString, k];
209
+ let paramCount = values.length;
210
+ for (const [key, value] of Object.entries(_filter)) {
211
+ if (typeof value === "object" && value !== null) {
212
+ const currentParamCount = paramCount;
213
+ const placeholders = value.in
214
+ .map((_, index) => `$${currentParamCount + index + 1}`)
215
+ .join(",");
216
+ whereClauses.push(`${this.metadataColumnName}->>'${key}' IN (${placeholders})`);
217
+ values.push(...value.in);
218
+ paramCount += value.in.length;
219
+ }
220
+ else {
221
+ paramCount += 1;
222
+ whereClauses.push(`${this.metadataColumnName}->>'${key}' = $${paramCount}`);
223
+ values.push(value);
224
+ }
225
+ }
226
+ const whereClause = whereClauses.length
227
+ ? `WHERE ${whereClauses.join(" AND ")}`
228
+ : "";
207
229
  const queryString = `
208
- SELECT *, ${this.vectorColumnName} <=> $1 as "_distance"
209
- FROM ${this.tableName}
210
- WHERE ${this.metadataColumnName} @> $2
211
- ORDER BY "_distance" ASC
212
- LIMIT $3;`;
213
- const documents = (await this.client.query(queryString, [embeddingString, _filter, k])).rows;
230
+ SELECT *, ${this.vectorColumnName} <=> $1 as "_distance"
231
+ FROM ${this.tableName}
232
+ ${whereClause}
233
+ ORDER BY "_distance" ASC
234
+ LIMIT $2;`;
235
+ const documents = (await this.client.query(queryString, values)).rows;
214
236
  const results = [];
215
237
  for (const doc of documents) {
216
238
  if (doc._distance != null && doc[this.contentColumnName] != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "langchain",
3
- "version": "0.0.174",
3
+ "version": "0.0.175",
4
4
  "description": "Typescript bindings for langchain",
5
5
  "type": "module",
6
6
  "engines": {
@@ -223,6 +223,9 @@
223
223
  "vectorstores/cassandra.cjs",
224
224
  "vectorstores/cassandra.js",
225
225
  "vectorstores/cassandra.d.ts",
226
+ "vectorstores/convex.cjs",
227
+ "vectorstores/convex.js",
228
+ "vectorstores/convex.d.ts",
226
229
  "vectorstores/elasticsearch.cjs",
227
230
  "vectorstores/elasticsearch.js",
228
231
  "vectorstores/elasticsearch.d.ts",
@@ -646,6 +649,9 @@
646
649
  "stores/file/node.cjs",
647
650
  "stores/file/node.js",
648
651
  "stores/file/node.d.ts",
652
+ "stores/message/convex.cjs",
653
+ "stores/message/convex.js",
654
+ "stores/message/convex.d.ts",
649
655
  "stores/message/cloudflare_d1.cjs",
650
656
  "stores/message/cloudflare_d1.js",
651
657
  "stores/message/cloudflare_d1.d.ts",
@@ -679,6 +685,9 @@
679
685
  "stores/message/xata.cjs",
680
686
  "stores/message/xata.js",
681
687
  "stores/message/xata.d.ts",
688
+ "storage/convex.cjs",
689
+ "storage/convex.js",
690
+ "storage/convex.d.ts",
682
691
  "storage/encoder_backed.cjs",
683
692
  "storage/encoder_backed.js",
684
693
  "storage/encoder_backed.d.ts",
@@ -703,6 +712,9 @@
703
712
  "hub.cjs",
704
713
  "hub.js",
705
714
  "hub.d.ts",
715
+ "util/convex.cjs",
716
+ "util/convex.js",
717
+ "util/convex.d.ts",
706
718
  "util/document.cjs",
707
719
  "util/document.js",
708
720
  "util/document.d.ts",
@@ -853,6 +865,7 @@
853
865
  "closevector-node": "0.1.0-alpha.10",
854
866
  "closevector-web": "0.1.0-alpha.15",
855
867
  "cohere-ai": ">=6.0.0",
868
+ "convex": "^1.3.1",
856
869
  "d3-dsv": "^2.0.0",
857
870
  "dotenv": "^16.0.3",
858
871
  "dpdm": "^3.12.0",
@@ -969,6 +982,7 @@
969
982
  "closevector-node": "0.1.0-alpha.10",
970
983
  "closevector-web": "0.1.0-alpha.16",
971
984
  "cohere-ai": ">=6.0.0",
985
+ "convex": "^1.3.1",
972
986
  "d3-dsv": "^2.0.0",
973
987
  "epub2": "^3.0.1",
974
988
  "faiss-node": "^0.5.1",
@@ -1174,6 +1188,9 @@
1174
1188
  "cohere-ai": {
1175
1189
  "optional": true
1176
1190
  },
1191
+ "convex": {
1192
+ "optional": true
1193
+ },
1177
1194
  "d3-dsv": {
1178
1195
  "optional": true
1179
1196
  },
@@ -1695,6 +1712,11 @@
1695
1712
  "import": "./vectorstores/cassandra.js",
1696
1713
  "require": "./vectorstores/cassandra.cjs"
1697
1714
  },
1715
+ "./vectorstores/convex": {
1716
+ "types": "./vectorstores/convex.d.ts",
1717
+ "import": "./vectorstores/convex.js",
1718
+ "require": "./vectorstores/convex.cjs"
1719
+ },
1698
1720
  "./vectorstores/elasticsearch": {
1699
1721
  "types": "./vectorstores/elasticsearch.d.ts",
1700
1722
  "import": "./vectorstores/elasticsearch.js",
@@ -2400,6 +2422,11 @@
2400
2422
  "import": "./stores/file/node.js",
2401
2423
  "require": "./stores/file/node.cjs"
2402
2424
  },
2425
+ "./stores/message/convex": {
2426
+ "types": "./stores/message/convex.d.ts",
2427
+ "import": "./stores/message/convex.js",
2428
+ "require": "./stores/message/convex.cjs"
2429
+ },
2403
2430
  "./stores/message/cloudflare_d1": {
2404
2431
  "types": "./stores/message/cloudflare_d1.d.ts",
2405
2432
  "import": "./stores/message/cloudflare_d1.js",
@@ -2455,6 +2482,11 @@
2455
2482
  "import": "./stores/message/xata.js",
2456
2483
  "require": "./stores/message/xata.cjs"
2457
2484
  },
2485
+ "./storage/convex": {
2486
+ "types": "./storage/convex.d.ts",
2487
+ "import": "./storage/convex.js",
2488
+ "require": "./storage/convex.cjs"
2489
+ },
2458
2490
  "./storage/encoder_backed": {
2459
2491
  "types": "./storage/encoder_backed.d.ts",
2460
2492
  "import": "./storage/encoder_backed.js",
@@ -2495,6 +2527,11 @@
2495
2527
  "import": "./hub.js",
2496
2528
  "require": "./hub.cjs"
2497
2529
  },
2530
+ "./util/convex": {
2531
+ "types": "./util/convex.d.ts",
2532
+ "import": "./util/convex.js",
2533
+ "require": "./util/convex.cjs"
2534
+ },
2498
2535
  "./util/document": {
2499
2536
  "types": "./util/document.d.ts",
2500
2537
  "import": "./util/document.js",
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/storage/convex.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/storage/convex.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/storage/convex.js'
@@ -0,0 +1 @@
1
+ module.exports = require('../../dist/stores/message/convex.cjs');
@@ -0,0 +1 @@
1
+ export * from '../../dist/stores/message/convex.js'
@@ -0,0 +1 @@
1
+ export * from '../../dist/stores/message/convex.js'
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/util/convex.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/util/convex.js'
package/util/convex.js ADDED
@@ -0,0 +1 @@
1
+ export * from '../dist/util/convex.js'
@@ -0,0 +1 @@
1
+ module.exports = require('../dist/vectorstores/convex.cjs');
@@ -0,0 +1 @@
1
+ export * from '../dist/vectorstores/convex.js'
@@ -0,0 +1 @@
1
+ export * from '../dist/vectorstores/convex.js'