@mastra/chroma 0.0.0-storage-20250225005900 → 0.0.0-vnext-inngest-20250506121901
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/CHANGELOG.md +946 -3
- package/LICENSE.md +7 -0
- package/README.md +26 -16
- package/dist/_tsup-dts-rollup.d.cts +75 -0
- package/dist/_tsup-dts-rollup.d.ts +43 -11
- package/dist/index.cjs +307 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +124 -12
- package/docker-compose.yaml +7 -0
- package/eslint.config.js +6 -0
- package/package.json +18 -10
- package/src/index.ts +1 -0
- package/src/vector/filter.ts +5 -10
- package/src/vector/index.test.ts +909 -199
- package/src/vector/index.ts +98 -30
- package/src/vector/prompt.ts +72 -0
- package/.turbo/turbo-build.log +0 -19
- package/LICENSE +0 -44
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
1
|
import { MastraVector } from '@mastra/core/vector';
|
|
3
2
|
import { ChromaClient } from 'chromadb';
|
|
3
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
4
4
|
|
|
5
5
|
// src/vector/index.ts
|
|
6
6
|
var ChromaFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -105,7 +105,7 @@ var ChromaVector = class extends MastraVector {
|
|
|
105
105
|
try {
|
|
106
106
|
const collection = await this.client.getCollection({ name: indexName, embeddingFunction: void 0 });
|
|
107
107
|
this.collections.set(indexName, collection);
|
|
108
|
-
} catch
|
|
108
|
+
} catch {
|
|
109
109
|
if (throwIfNotExists) {
|
|
110
110
|
throw new Error(`Index ${indexName} does not exist`);
|
|
111
111
|
}
|
|
@@ -122,7 +122,9 @@ var ChromaVector = class extends MastraVector {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
async upsert(
|
|
125
|
+
async upsert(...args) {
|
|
126
|
+
const params = this.normalizeArgs("upsert", args, ["documents"]);
|
|
127
|
+
const { indexName, vectors, metadata, ids, documents } = params;
|
|
126
128
|
const collection = await this.getCollection(indexName);
|
|
127
129
|
const stats = await this.describeIndex(indexName);
|
|
128
130
|
this.validateVectorDimensions(vectors, stats.dimension);
|
|
@@ -131,28 +133,43 @@ var ChromaVector = class extends MastraVector {
|
|
|
131
133
|
await collection.upsert({
|
|
132
134
|
ids: generatedIds,
|
|
133
135
|
embeddings: vectors,
|
|
134
|
-
metadatas: normalizedMetadata
|
|
136
|
+
metadatas: normalizedMetadata,
|
|
137
|
+
documents
|
|
135
138
|
});
|
|
136
139
|
return generatedIds;
|
|
137
140
|
}
|
|
138
|
-
|
|
141
|
+
HnswSpaceMap = {
|
|
142
|
+
cosine: "cosine",
|
|
143
|
+
euclidean: "l2",
|
|
144
|
+
dotproduct: "ip",
|
|
145
|
+
l2: "euclidean",
|
|
146
|
+
ip: "dotproduct"
|
|
147
|
+
};
|
|
148
|
+
async createIndex(...args) {
|
|
149
|
+
const params = this.normalizeArgs("createIndex", args);
|
|
150
|
+
const { indexName, dimension, metric = "cosine" } = params;
|
|
139
151
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
140
152
|
throw new Error("Dimension must be a positive integer");
|
|
141
153
|
}
|
|
154
|
+
const hnswSpace = this.HnswSpaceMap[metric];
|
|
155
|
+
if (!["cosine", "l2", "ip"].includes(hnswSpace)) {
|
|
156
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
157
|
+
}
|
|
142
158
|
await this.client.createCollection({
|
|
143
159
|
name: indexName,
|
|
144
160
|
metadata: {
|
|
145
161
|
dimension,
|
|
146
|
-
metric
|
|
162
|
+
"hnsw:space": this.HnswSpaceMap[metric]
|
|
147
163
|
}
|
|
148
164
|
});
|
|
149
165
|
}
|
|
150
166
|
transformFilter(filter) {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
return translatedFilter;
|
|
167
|
+
const translator = new ChromaFilterTranslator();
|
|
168
|
+
return translator.translate(filter);
|
|
154
169
|
}
|
|
155
|
-
async query(
|
|
170
|
+
async query(...args) {
|
|
171
|
+
const params = this.normalizeArgs("query", args, ["documentFilter"]);
|
|
172
|
+
const { indexName, queryVector, topK = 10, filter, includeVector = false, documentFilter } = params;
|
|
156
173
|
const collection = await this.getCollection(indexName, true);
|
|
157
174
|
const defaultInclude = ["documents", "metadatas", "distances"];
|
|
158
175
|
const translatedFilter = this.transformFilter(filter);
|
|
@@ -160,12 +177,14 @@ var ChromaVector = class extends MastraVector {
|
|
|
160
177
|
queryEmbeddings: [queryVector],
|
|
161
178
|
nResults: topK,
|
|
162
179
|
where: translatedFilter,
|
|
180
|
+
whereDocument: documentFilter,
|
|
163
181
|
include: includeVector ? [...defaultInclude, "embeddings"] : defaultInclude
|
|
164
182
|
});
|
|
165
183
|
return (results.ids[0] || []).map((id, index) => ({
|
|
166
184
|
id,
|
|
167
185
|
score: results.distances?.[0]?.[index] || 0,
|
|
168
186
|
metadata: results.metadatas?.[0]?.[index] || {},
|
|
187
|
+
document: results.documents?.[0]?.[index],
|
|
169
188
|
...includeVector && { vector: results.embeddings?.[0]?.[index] || [] }
|
|
170
189
|
}));
|
|
171
190
|
}
|
|
@@ -177,16 +196,109 @@ var ChromaVector = class extends MastraVector {
|
|
|
177
196
|
const collection = await this.getCollection(indexName);
|
|
178
197
|
const count = await collection.count();
|
|
179
198
|
const metadata = collection.metadata;
|
|
199
|
+
const hnswSpace = metadata?.["hnsw:space"];
|
|
180
200
|
return {
|
|
181
201
|
dimension: metadata?.dimension || 0,
|
|
182
202
|
count,
|
|
183
|
-
metric:
|
|
203
|
+
metric: this.HnswSpaceMap[hnswSpace]
|
|
184
204
|
};
|
|
185
205
|
}
|
|
186
206
|
async deleteIndex(indexName) {
|
|
187
207
|
await this.client.deleteCollection({ name: indexName });
|
|
188
208
|
this.collections.delete(indexName);
|
|
189
209
|
}
|
|
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];
|
|
221
|
+
}
|
|
222
|
+
return await collection.update(updateOptions);
|
|
223
|
+
}
|
|
224
|
+
async deleteIndexById(indexName, id) {
|
|
225
|
+
try {
|
|
226
|
+
const collection = await this.getCollection(indexName, true);
|
|
227
|
+
await collection.delete({ ids: [id] });
|
|
228
|
+
} catch (error) {
|
|
229
|
+
throw new Error(`Failed to delete index by id: ${id} for index name: ${indexName}: ${error.message}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
190
232
|
};
|
|
191
233
|
|
|
192
|
-
|
|
234
|
+
// src/vector/prompt.ts
|
|
235
|
+
var CHROMA_PROMPT = `When querying Chroma, you can ONLY use the operators listed below. Any other operators will be rejected.
|
|
236
|
+
Important: Don't explain how to construct the filter - use the specified operators and fields to search the content and return relevant results.
|
|
237
|
+
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.
|
|
238
|
+
|
|
239
|
+
Basic Comparison Operators:
|
|
240
|
+
- $eq: Exact match (default when using field: value)
|
|
241
|
+
Example: { "category": "electronics" }
|
|
242
|
+
- $ne: Not equal
|
|
243
|
+
Example: { "category": { "$ne": "electronics" } }
|
|
244
|
+
- $gt: Greater than
|
|
245
|
+
Example: { "price": { "$gt": 100 } }
|
|
246
|
+
- $gte: Greater than or equal
|
|
247
|
+
Example: { "price": { "$gte": 100 } }
|
|
248
|
+
- $lt: Less than
|
|
249
|
+
Example: { "price": { "$lt": 100 } }
|
|
250
|
+
- $lte: Less than or equal
|
|
251
|
+
Example: { "price": { "$lte": 100 } }
|
|
252
|
+
|
|
253
|
+
Array Operators:
|
|
254
|
+
- $in: Match any value in array
|
|
255
|
+
Example: { "category": { "$in": ["electronics", "books"] } }
|
|
256
|
+
- $nin: Does not match any value in array
|
|
257
|
+
Example: { "category": { "$nin": ["electronics", "books"] } }
|
|
258
|
+
|
|
259
|
+
Logical Operators:
|
|
260
|
+
- $and: Logical AND
|
|
261
|
+
Example: { "$and": [{ "price": { "$gt": 100 } }, { "category": "electronics" }] }
|
|
262
|
+
- $or: Logical OR
|
|
263
|
+
Example: { "$or": [{ "price": { "$lt": 50 } }, { "category": "books" }] }
|
|
264
|
+
|
|
265
|
+
Restrictions:
|
|
266
|
+
- Regex patterns are not supported
|
|
267
|
+
- Element operators are not supported
|
|
268
|
+
- Only $and and $or logical operators are supported
|
|
269
|
+
- Nested fields are supported using dot notation
|
|
270
|
+
- Multiple conditions on the same field are supported with both implicit and explicit $and
|
|
271
|
+
- Empty arrays in $in/$nin will return no results
|
|
272
|
+
- If multiple top-level fields exist, they're wrapped in $and
|
|
273
|
+
- Only logical operators ($and, $or) can be used at the top level
|
|
274
|
+
- All other operators must be used within a field condition
|
|
275
|
+
Valid: { "field": { "$gt": 100 } }
|
|
276
|
+
Valid: { "$and": [...] }
|
|
277
|
+
Invalid: { "$gt": 100 }
|
|
278
|
+
Invalid: { "$in": [...] }
|
|
279
|
+
- Logical operators must contain field conditions, not direct operators
|
|
280
|
+
Valid: { "$and": [{ "field": { "$gt": 100 } }] }
|
|
281
|
+
Invalid: { "$and": [{ "$gt": 100 }] }
|
|
282
|
+
- Logical operators ($and, $or):
|
|
283
|
+
- Can only be used at top level or nested within other logical operators
|
|
284
|
+
- Can not be used on a field level, or be nested inside a field
|
|
285
|
+
- Can not be used inside an operator
|
|
286
|
+
- Valid: { "$and": [{ "field": { "$gt": 100 } }] }
|
|
287
|
+
- Valid: { "$or": [{ "$and": [{ "field": { "$gt": 100 } }] }] }
|
|
288
|
+
- Invalid: { "field": { "$and": [{ "$gt": 100 }] } }
|
|
289
|
+
- Invalid: { "field": { "$or": [{ "$gt": 100 }] } }
|
|
290
|
+
- Invalid: { "field": { "$gt": { "$and": [{...}] } } }
|
|
291
|
+
|
|
292
|
+
Example Complex Query:
|
|
293
|
+
{
|
|
294
|
+
"$and": [
|
|
295
|
+
{ "category": { "$in": ["electronics", "computers"] } },
|
|
296
|
+
{ "price": { "$gte": 100, "$lte": 1000 } },
|
|
297
|
+
{ "$or": [
|
|
298
|
+
{ "inStock": true },
|
|
299
|
+
{ "preorder": true }
|
|
300
|
+
]}
|
|
301
|
+
]
|
|
302
|
+
}`;
|
|
303
|
+
|
|
304
|
+
export { CHROMA_PROMPT, ChromaVector };
|
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/chroma",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-vnext-inngest-20250506121901",
|
|
4
4
|
"description": "Chroma vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,24 +10,32 @@
|
|
|
10
10
|
"import": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.cts",
|
|
16
|
+
"default": "./dist/index.cjs"
|
|
13
17
|
}
|
|
14
18
|
},
|
|
15
19
|
"./package.json": "./package.json"
|
|
16
20
|
},
|
|
21
|
+
"license": "MIT",
|
|
17
22
|
"dependencies": {
|
|
18
|
-
"chromadb": "^
|
|
19
|
-
"@mastra/core": "
|
|
23
|
+
"chromadb": "^2.2.0",
|
|
24
|
+
"@mastra/core": "0.0.0-vnext-inngest-20250506121901"
|
|
20
25
|
},
|
|
21
26
|
"devDependencies": {
|
|
22
|
-
"@microsoft/api-extractor": "^7.
|
|
23
|
-
"@types/node": "^
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
+
"@microsoft/api-extractor": "^7.52.5",
|
|
28
|
+
"@types/node": "^20.17.27",
|
|
29
|
+
"eslint": "^9.23.0",
|
|
30
|
+
"tsup": "^8.4.0",
|
|
31
|
+
"typescript": "^5.8.2",
|
|
32
|
+
"vitest": "^3.1.2",
|
|
33
|
+
"@internal/lint": "0.0.0-vnext-inngest-20250506121901"
|
|
27
34
|
},
|
|
28
35
|
"scripts": {
|
|
29
|
-
"build": "tsup src/index.ts --format esm --experimental-dts --clean --treeshake",
|
|
36
|
+
"build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
|
|
30
37
|
"build:watch": "pnpm build --watch",
|
|
31
|
-
"test": "vitest run"
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"lint": "eslint ."
|
|
32
40
|
}
|
|
33
41
|
}
|
package/src/index.ts
CHANGED
package/src/vector/filter.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type FieldCondition,
|
|
4
|
-
type Filter,
|
|
5
|
-
type OperatorSupport,
|
|
6
|
-
type QueryOperator,
|
|
7
|
-
} from '@mastra/core/filter';
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import type { FieldCondition, VectorFilter, OperatorSupport, QueryOperator } from '@mastra/core/vector/filter';
|
|
8
3
|
|
|
9
4
|
/**
|
|
10
5
|
* Translator for Chroma filter queries.
|
|
@@ -23,14 +18,14 @@ export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
|
23
18
|
};
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
translate(filter?:
|
|
21
|
+
translate(filter?: VectorFilter): VectorFilter {
|
|
27
22
|
if (this.isEmpty(filter)) return filter;
|
|
28
|
-
this.validateFilter(filter
|
|
23
|
+
this.validateFilter(filter);
|
|
29
24
|
|
|
30
25
|
return this.translateNode(filter);
|
|
31
26
|
}
|
|
32
27
|
|
|
33
|
-
private translateNode(node:
|
|
28
|
+
private translateNode(node: VectorFilter | FieldCondition, currentPath: string = ''): any {
|
|
34
29
|
// Handle primitive values and arrays
|
|
35
30
|
if (this.isRegex(node)) {
|
|
36
31
|
throw new Error('Regex is not supported in Chroma');
|