@mastra/chroma 0.0.0-vnextWorkflows-20250422081019 → 0.0.0-workflow-deno-20250616115451

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.
package/dist/index.cjs CHANGED
@@ -124,11 +124,9 @@ var ChromaVector = class extends vector.MastraVector {
124
124
  }
125
125
  }
126
126
  }
127
- async upsert(...args) {
128
- const params = this.normalizeArgs("upsert", args, ["documents"]);
129
- const { indexName, vectors, metadata, ids, documents } = params;
127
+ async upsert({ indexName, vectors, metadata, ids, documents }) {
130
128
  const collection = await this.getCollection(indexName);
131
- const stats = await this.describeIndex(indexName);
129
+ const stats = await this.describeIndex({ indexName });
132
130
  this.validateVectorDimensions(vectors, stats.dimension);
133
131
  const generatedIds = ids || vectors.map(() => crypto.randomUUID());
134
132
  const normalizedMetadata = metadata || vectors.map(() => ({}));
@@ -147,9 +145,7 @@ var ChromaVector = class extends vector.MastraVector {
147
145
  l2: "euclidean",
148
146
  ip: "dotproduct"
149
147
  };
150
- async createIndex(...args) {
151
- const params = this.normalizeArgs("createIndex", args);
152
- const { indexName, dimension, metric = "cosine" } = params;
148
+ async createIndex({ indexName, dimension, metric = "cosine" }) {
153
149
  if (!Number.isInteger(dimension) || dimension <= 0) {
154
150
  throw new Error("Dimension must be a positive integer");
155
151
  }
@@ -157,21 +153,35 @@ var ChromaVector = class extends vector.MastraVector {
157
153
  if (!["cosine", "l2", "ip"].includes(hnswSpace)) {
158
154
  throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
159
155
  }
160
- await this.client.createCollection({
161
- name: indexName,
162
- metadata: {
163
- dimension,
164
- "hnsw:space": this.HnswSpaceMap[metric]
156
+ try {
157
+ await this.client.createCollection({
158
+ name: indexName,
159
+ metadata: {
160
+ dimension,
161
+ "hnsw:space": hnswSpace
162
+ }
163
+ });
164
+ } catch (error) {
165
+ const message = error?.message || error?.toString();
166
+ if (message && message.toLowerCase().includes("already exists")) {
167
+ await this.validateExistingIndex(indexName, dimension, metric);
168
+ return;
165
169
  }
166
- });
170
+ throw error;
171
+ }
167
172
  }
168
173
  transformFilter(filter) {
169
174
  const translator = new ChromaFilterTranslator();
170
175
  return translator.translate(filter);
171
176
  }
172
- async query(...args) {
173
- const params = this.normalizeArgs("query", args, ["documentFilter"]);
174
- const { indexName, queryVector, topK = 10, filter, includeVector = false, documentFilter } = params;
177
+ async query({
178
+ indexName,
179
+ queryVector,
180
+ topK = 10,
181
+ filter,
182
+ includeVector = false,
183
+ documentFilter
184
+ }) {
175
185
  const collection = await this.getCollection(indexName, true);
176
186
  const defaultInclude = ["documents", "metadatas", "distances"];
177
187
  const translatedFilter = this.transformFilter(filter);
@@ -194,7 +204,13 @@ var ChromaVector = class extends vector.MastraVector {
194
204
  const collections = await this.client.listCollections();
195
205
  return collections.map((collection) => collection);
196
206
  }
197
- async describeIndex(indexName) {
207
+ /**
208
+ * Retrieves statistics about a vector index.
209
+ *
210
+ * @param {string} indexName - The name of the index to describe
211
+ * @returns A promise that resolves to the index statistics including dimension, count and metric
212
+ */
213
+ async describeIndex({ indexName }) {
198
214
  const collection = await this.getCollection(indexName);
199
215
  const count = await collection.count();
200
216
  const metadata = collection.metadata;
@@ -205,32 +221,126 @@ var ChromaVector = class extends vector.MastraVector {
205
221
  metric: this.HnswSpaceMap[hnswSpace]
206
222
  };
207
223
  }
208
- async deleteIndex(indexName) {
224
+ async deleteIndex({ indexName }) {
209
225
  await this.client.deleteCollection({ name: indexName });
210
226
  this.collections.delete(indexName);
211
227
  }
212
- async updateIndexById(indexName, id, update) {
213
- if (!update.vector && !update.metadata) {
214
- throw new Error("No updates provided");
215
- }
216
- const collection = await this.getCollection(indexName, true);
217
- const updateOptions = { ids: [id] };
218
- if (update?.vector) {
219
- updateOptions.embeddings = [update.vector];
220
- }
221
- if (update?.metadata) {
222
- updateOptions.metadatas = [update.metadata];
228
+ /**
229
+ * Updates a vector by its ID with the provided vector and/or metadata.
230
+ * @param indexName - The name of the index containing the vector.
231
+ * @param id - The ID of the vector to update.
232
+ * @param update - An object containing the vector and/or metadata to update.
233
+ * @param update.vector - An optional array of numbers representing the new vector.
234
+ * @param update.metadata - An optional record containing the new metadata.
235
+ * @returns A promise that resolves when the update is complete.
236
+ * @throws Will throw an error if no updates are provided or if the update operation fails.
237
+ */
238
+ async updateVector({ indexName, id, update }) {
239
+ try {
240
+ if (!update.vector && !update.metadata) {
241
+ throw new Error("No updates provided");
242
+ }
243
+ const collection = await this.getCollection(indexName, true);
244
+ const updateOptions = { ids: [id] };
245
+ if (update?.vector) {
246
+ const stats = await this.describeIndex({ indexName });
247
+ this.validateVectorDimensions([update.vector], stats.dimension);
248
+ updateOptions.embeddings = [update.vector];
249
+ }
250
+ if (update?.metadata) {
251
+ updateOptions.metadatas = [update.metadata];
252
+ }
253
+ return await collection.update(updateOptions);
254
+ } catch (error) {
255
+ throw new Error(`Failed to update vector by id: ${id} for index name: ${indexName}: ${error.message}`);
223
256
  }
224
- return await collection.update(updateOptions);
225
257
  }
226
- async deleteIndexById(indexName, id) {
258
+ /**
259
+ * Deletes a vector by its ID.
260
+ * @param indexName - The name of the index containing the vector.
261
+ * @param id - The ID of the vector to delete.
262
+ * @returns A promise that resolves when the deletion is complete.
263
+ * @throws Will throw an error if the deletion operation fails.
264
+ */
265
+ async deleteVector({ indexName, id }) {
227
266
  try {
228
267
  const collection = await this.getCollection(indexName, true);
229
268
  await collection.delete({ ids: [id] });
230
269
  } catch (error) {
231
- throw new Error(`Failed to delete index by id: ${id} for index name: ${indexName}: ${error.message}`);
270
+ throw new Error(`Failed to delete vector by id: ${id} for index name: ${indexName}: ${error.message}`);
232
271
  }
233
272
  }
234
273
  };
235
274
 
275
+ // src/vector/prompt.ts
276
+ var CHROMA_PROMPT = `When querying Chroma, you can ONLY use the operators listed below. Any other operators will be rejected.
277
+ Important: Don't explain how to construct the filter - use the specified operators and fields to search the content and return relevant results.
278
+ If a user tries to give an explicit operator that is not supported, reject the filter entirely and let them know that the operator is not supported.
279
+
280
+ Basic Comparison Operators:
281
+ - $eq: Exact match (default when using field: value)
282
+ Example: { "category": "electronics" }
283
+ - $ne: Not equal
284
+ Example: { "category": { "$ne": "electronics" } }
285
+ - $gt: Greater than
286
+ Example: { "price": { "$gt": 100 } }
287
+ - $gte: Greater than or equal
288
+ Example: { "price": { "$gte": 100 } }
289
+ - $lt: Less than
290
+ Example: { "price": { "$lt": 100 } }
291
+ - $lte: Less than or equal
292
+ Example: { "price": { "$lte": 100 } }
293
+
294
+ Array Operators:
295
+ - $in: Match any value in array
296
+ Example: { "category": { "$in": ["electronics", "books"] } }
297
+ - $nin: Does not match any value in array
298
+ Example: { "category": { "$nin": ["electronics", "books"] } }
299
+
300
+ Logical Operators:
301
+ - $and: Logical AND
302
+ Example: { "$and": [{ "price": { "$gt": 100 } }, { "category": "electronics" }] }
303
+ - $or: Logical OR
304
+ Example: { "$or": [{ "price": { "$lt": 50 } }, { "category": "books" }] }
305
+
306
+ Restrictions:
307
+ - Regex patterns are not supported
308
+ - Element operators are not supported
309
+ - Only $and and $or logical operators are supported
310
+ - Nested fields are supported using dot notation
311
+ - Multiple conditions on the same field are supported with both implicit and explicit $and
312
+ - Empty arrays in $in/$nin will return no results
313
+ - If multiple top-level fields exist, they're wrapped in $and
314
+ - Only logical operators ($and, $or) can be used at the top level
315
+ - All other operators must be used within a field condition
316
+ Valid: { "field": { "$gt": 100 } }
317
+ Valid: { "$and": [...] }
318
+ Invalid: { "$gt": 100 }
319
+ Invalid: { "$in": [...] }
320
+ - Logical operators must contain field conditions, not direct operators
321
+ Valid: { "$and": [{ "field": { "$gt": 100 } }] }
322
+ Invalid: { "$and": [{ "$gt": 100 }] }
323
+ - Logical operators ($and, $or):
324
+ - Can only be used at top level or nested within other logical operators
325
+ - Can not be used on a field level, or be nested inside a field
326
+ - Can not be used inside an operator
327
+ - Valid: { "$and": [{ "field": { "$gt": 100 } }] }
328
+ - Valid: { "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }
329
+ - Invalid: { "field": { "$and": [{ "$gt": 100 }] } }
330
+ - Invalid: { "field": { "$or": [{ "$gt": 100 }] } }
331
+ - Invalid: { "field": { "$gt": { "$and": [{...}] } } }
332
+
333
+ Example Complex Query:
334
+ {
335
+ "$and": [
336
+ { "category": { "$in": ["electronics", "computers"] } },
337
+ { "price": { "$gte": 100, "$lte": 1000 } },
338
+ { "$or": [
339
+ { "inStock": true },
340
+ { "preorder": true }
341
+ ]}
342
+ ]
343
+ }`;
344
+
345
+ exports.CHROMA_PROMPT = CHROMA_PROMPT;
236
346
  exports.ChromaVector = ChromaVector;
package/dist/index.d.cts CHANGED
@@ -1 +1,2 @@
1
+ export { CHROMA_PROMPT } from './_tsup-dts-rollup.cjs';
1
2
  export { ChromaVector } from './_tsup-dts-rollup.cjs';
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
+ export { CHROMA_PROMPT } from './_tsup-dts-rollup.js';
1
2
  export { ChromaVector } from './_tsup-dts-rollup.js';
package/dist/index.js CHANGED
@@ -122,11 +122,9 @@ var ChromaVector = class extends MastraVector {
122
122
  }
123
123
  }
124
124
  }
125
- async upsert(...args) {
126
- const params = this.normalizeArgs("upsert", args, ["documents"]);
127
- const { indexName, vectors, metadata, ids, documents } = params;
125
+ async upsert({ indexName, vectors, metadata, ids, documents }) {
128
126
  const collection = await this.getCollection(indexName);
129
- const stats = await this.describeIndex(indexName);
127
+ const stats = await this.describeIndex({ indexName });
130
128
  this.validateVectorDimensions(vectors, stats.dimension);
131
129
  const generatedIds = ids || vectors.map(() => crypto.randomUUID());
132
130
  const normalizedMetadata = metadata || vectors.map(() => ({}));
@@ -145,9 +143,7 @@ var ChromaVector = class extends MastraVector {
145
143
  l2: "euclidean",
146
144
  ip: "dotproduct"
147
145
  };
148
- async createIndex(...args) {
149
- const params = this.normalizeArgs("createIndex", args);
150
- const { indexName, dimension, metric = "cosine" } = params;
146
+ async createIndex({ indexName, dimension, metric = "cosine" }) {
151
147
  if (!Number.isInteger(dimension) || dimension <= 0) {
152
148
  throw new Error("Dimension must be a positive integer");
153
149
  }
@@ -155,21 +151,35 @@ var ChromaVector = class extends MastraVector {
155
151
  if (!["cosine", "l2", "ip"].includes(hnswSpace)) {
156
152
  throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
157
153
  }
158
- await this.client.createCollection({
159
- name: indexName,
160
- metadata: {
161
- dimension,
162
- "hnsw:space": this.HnswSpaceMap[metric]
154
+ try {
155
+ await this.client.createCollection({
156
+ name: indexName,
157
+ metadata: {
158
+ dimension,
159
+ "hnsw:space": hnswSpace
160
+ }
161
+ });
162
+ } catch (error) {
163
+ const message = error?.message || error?.toString();
164
+ if (message && message.toLowerCase().includes("already exists")) {
165
+ await this.validateExistingIndex(indexName, dimension, metric);
166
+ return;
163
167
  }
164
- });
168
+ throw error;
169
+ }
165
170
  }
166
171
  transformFilter(filter) {
167
172
  const translator = new ChromaFilterTranslator();
168
173
  return translator.translate(filter);
169
174
  }
170
- async query(...args) {
171
- const params = this.normalizeArgs("query", args, ["documentFilter"]);
172
- const { indexName, queryVector, topK = 10, filter, includeVector = false, documentFilter } = params;
175
+ async query({
176
+ indexName,
177
+ queryVector,
178
+ topK = 10,
179
+ filter,
180
+ includeVector = false,
181
+ documentFilter
182
+ }) {
173
183
  const collection = await this.getCollection(indexName, true);
174
184
  const defaultInclude = ["documents", "metadatas", "distances"];
175
185
  const translatedFilter = this.transformFilter(filter);
@@ -192,7 +202,13 @@ var ChromaVector = class extends MastraVector {
192
202
  const collections = await this.client.listCollections();
193
203
  return collections.map((collection) => collection);
194
204
  }
195
- async describeIndex(indexName) {
205
+ /**
206
+ * Retrieves statistics about a vector index.
207
+ *
208
+ * @param {string} indexName - The name of the index to describe
209
+ * @returns A promise that resolves to the index statistics including dimension, count and metric
210
+ */
211
+ async describeIndex({ indexName }) {
196
212
  const collection = await this.getCollection(indexName);
197
213
  const count = await collection.count();
198
214
  const metadata = collection.metadata;
@@ -203,32 +219,125 @@ var ChromaVector = class extends MastraVector {
203
219
  metric: this.HnswSpaceMap[hnswSpace]
204
220
  };
205
221
  }
206
- async deleteIndex(indexName) {
222
+ async deleteIndex({ indexName }) {
207
223
  await this.client.deleteCollection({ name: indexName });
208
224
  this.collections.delete(indexName);
209
225
  }
210
- async updateIndexById(indexName, id, update) {
211
- if (!update.vector && !update.metadata) {
212
- throw new Error("No updates provided");
213
- }
214
- const collection = await this.getCollection(indexName, true);
215
- const updateOptions = { ids: [id] };
216
- if (update?.vector) {
217
- updateOptions.embeddings = [update.vector];
218
- }
219
- if (update?.metadata) {
220
- updateOptions.metadatas = [update.metadata];
226
+ /**
227
+ * Updates a vector by its ID with the provided vector and/or metadata.
228
+ * @param indexName - The name of the index containing the vector.
229
+ * @param id - The ID of the vector to update.
230
+ * @param update - An object containing the vector and/or metadata to update.
231
+ * @param update.vector - An optional array of numbers representing the new vector.
232
+ * @param update.metadata - An optional record containing the new metadata.
233
+ * @returns A promise that resolves when the update is complete.
234
+ * @throws Will throw an error if no updates are provided or if the update operation fails.
235
+ */
236
+ async updateVector({ indexName, id, update }) {
237
+ try {
238
+ if (!update.vector && !update.metadata) {
239
+ throw new Error("No updates provided");
240
+ }
241
+ const collection = await this.getCollection(indexName, true);
242
+ const updateOptions = { ids: [id] };
243
+ if (update?.vector) {
244
+ const stats = await this.describeIndex({ indexName });
245
+ this.validateVectorDimensions([update.vector], stats.dimension);
246
+ updateOptions.embeddings = [update.vector];
247
+ }
248
+ if (update?.metadata) {
249
+ updateOptions.metadatas = [update.metadata];
250
+ }
251
+ return await collection.update(updateOptions);
252
+ } catch (error) {
253
+ throw new Error(`Failed to update vector by id: ${id} for index name: ${indexName}: ${error.message}`);
221
254
  }
222
- return await collection.update(updateOptions);
223
255
  }
224
- async deleteIndexById(indexName, id) {
256
+ /**
257
+ * Deletes a vector by its ID.
258
+ * @param indexName - The name of the index containing the vector.
259
+ * @param id - The ID of the vector to delete.
260
+ * @returns A promise that resolves when the deletion is complete.
261
+ * @throws Will throw an error if the deletion operation fails.
262
+ */
263
+ async deleteVector({ indexName, id }) {
225
264
  try {
226
265
  const collection = await this.getCollection(indexName, true);
227
266
  await collection.delete({ ids: [id] });
228
267
  } catch (error) {
229
- throw new Error(`Failed to delete index by id: ${id} for index name: ${indexName}: ${error.message}`);
268
+ throw new Error(`Failed to delete vector by id: ${id} for index name: ${indexName}: ${error.message}`);
230
269
  }
231
270
  }
232
271
  };
233
272
 
234
- export { ChromaVector };
273
+ // src/vector/prompt.ts
274
+ var CHROMA_PROMPT = `When querying Chroma, you can ONLY use the operators listed below. Any other operators will be rejected.
275
+ Important: Don't explain how to construct the filter - use the specified operators and fields to search the content and return relevant results.
276
+ If a user tries to give an explicit operator that is not supported, reject the filter entirely and let them know that the operator is not supported.
277
+
278
+ Basic Comparison Operators:
279
+ - $eq: Exact match (default when using field: value)
280
+ Example: { "category": "electronics" }
281
+ - $ne: Not equal
282
+ Example: { "category": { "$ne": "electronics" } }
283
+ - $gt: Greater than
284
+ Example: { "price": { "$gt": 100 } }
285
+ - $gte: Greater than or equal
286
+ Example: { "price": { "$gte": 100 } }
287
+ - $lt: Less than
288
+ Example: { "price": { "$lt": 100 } }
289
+ - $lte: Less than or equal
290
+ Example: { "price": { "$lte": 100 } }
291
+
292
+ Array Operators:
293
+ - $in: Match any value in array
294
+ Example: { "category": { "$in": ["electronics", "books"] } }
295
+ - $nin: Does not match any value in array
296
+ Example: { "category": { "$nin": ["electronics", "books"] } }
297
+
298
+ Logical Operators:
299
+ - $and: Logical AND
300
+ Example: { "$and": [{ "price": { "$gt": 100 } }, { "category": "electronics" }] }
301
+ - $or: Logical OR
302
+ Example: { "$or": [{ "price": { "$lt": 50 } }, { "category": "books" }] }
303
+
304
+ Restrictions:
305
+ - Regex patterns are not supported
306
+ - Element operators are not supported
307
+ - Only $and and $or logical operators are supported
308
+ - Nested fields are supported using dot notation
309
+ - Multiple conditions on the same field are supported with both implicit and explicit $and
310
+ - Empty arrays in $in/$nin will return no results
311
+ - If multiple top-level fields exist, they're wrapped in $and
312
+ - Only logical operators ($and, $or) can be used at the top level
313
+ - All other operators must be used within a field condition
314
+ Valid: { "field": { "$gt": 100 } }
315
+ Valid: { "$and": [...] }
316
+ Invalid: { "$gt": 100 }
317
+ Invalid: { "$in": [...] }
318
+ - Logical operators must contain field conditions, not direct operators
319
+ Valid: { "$and": [{ "field": { "$gt": 100 } }] }
320
+ Invalid: { "$and": [{ "$gt": 100 }] }
321
+ - Logical operators ($and, $or):
322
+ - Can only be used at top level or nested within other logical operators
323
+ - Can not be used on a field level, or be nested inside a field
324
+ - Can not be used inside an operator
325
+ - Valid: { "$and": [{ "field": { "$gt": 100 } }] }
326
+ - Valid: { "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }
327
+ - Invalid: { "field": { "$and": [{ "$gt": 100 }] } }
328
+ - Invalid: { "field": { "$or": [{ "$gt": 100 }] } }
329
+ - Invalid: { "field": { "$gt": { "$and": [{...}] } } }
330
+
331
+ Example Complex Query:
332
+ {
333
+ "$and": [
334
+ { "category": { "$in": ["electronics", "computers"] } },
335
+ { "price": { "$gte": 100, "$lte": 1000 } },
336
+ { "$or": [
337
+ { "inStock": true },
338
+ { "preorder": true }
339
+ ]}
340
+ ]
341
+ }`;
342
+
343
+ export { CHROMA_PROMPT, ChromaVector };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/chroma",
3
- "version": "0.0.0-vnextWorkflows-20250422081019",
3
+ "version": "0.0.0-workflow-deno-20250616115451",
4
4
  "description": "Chroma vector store provider for Mastra",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,17 +20,20 @@
20
20
  },
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "chromadb": "^2.2.0",
24
- "@mastra/core": "0.0.0-vnextWorkflows-20250422081019"
23
+ "chromadb": "^2.4.6"
25
24
  },
26
25
  "devDependencies": {
27
- "@microsoft/api-extractor": "^7.52.1",
28
- "@types/node": "^20.17.27",
29
- "eslint": "^9.23.0",
30
- "tsup": "^8.4.0",
31
- "typescript": "^5.8.2",
32
- "vitest": "^3.0.9",
33
- "@internal/lint": "0.0.2"
26
+ "@microsoft/api-extractor": "^7.52.8",
27
+ "@types/node": "^20.19.0",
28
+ "eslint": "^9.28.0",
29
+ "tsup": "^8.5.0",
30
+ "typescript": "^5.8.3",
31
+ "vitest": "^3.2.3",
32
+ "@mastra/core": "0.0.0-workflow-deno-20250616115451",
33
+ "@internal/lint": "0.0.0-workflow-deno-20250616115451"
34
+ },
35
+ "peerDependencies": {
36
+ "@mastra/core": ">=0.10.4-0 <0.11.0"
34
37
  },
35
38
  "scripts": {
36
39
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './vector/index';
2
+ export { CHROMA_PROMPT } from './vector/prompt';