@mastra/chroma 0.0.0-trigger-playground-ui-package-20250506151043 → 0.0.0-update-stores-peerDeps-20250723031338
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 +346 -4
- package/LICENSE.md +12 -4
- package/dist/_tsup-dts-rollup.d.cts +49 -22
- package/dist/_tsup-dts-rollup.d.ts +49 -22
- package/dist/index.cjs +214 -75
- package/dist/index.js +213 -74
- package/package.json +13 -10
- package/src/vector/filter.test.ts +24 -19
- package/src/vector/filter.ts +35 -4
- package/src/vector/index.test.ts +89 -138
- package/src/vector/index.ts +229 -110
package/src/vector/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';
|
|
1
2
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
3
|
import type {
|
|
3
4
|
QueryResult,
|
|
@@ -5,29 +6,25 @@ import type {
|
|
|
5
6
|
CreateIndexParams,
|
|
6
7
|
UpsertVectorParams,
|
|
7
8
|
QueryVectorParams,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
DescribeIndexParams,
|
|
10
|
+
DeleteIndexParams,
|
|
11
|
+
DeleteVectorParams,
|
|
12
|
+
UpdateVectorParams,
|
|
11
13
|
} from '@mastra/core/vector';
|
|
12
|
-
|
|
13
|
-
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
14
14
|
import { ChromaClient } from 'chromadb';
|
|
15
15
|
import type { UpdateRecordsParams, Collection } from 'chromadb';
|
|
16
|
+
import type { ChromaVectorDocumentFilter, ChromaVectorFilter } from './filter';
|
|
16
17
|
import { ChromaFilterTranslator } from './filter';
|
|
17
18
|
|
|
18
19
|
interface ChromaUpsertVectorParams extends UpsertVectorParams {
|
|
19
20
|
documents?: string[];
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
interface ChromaQueryVectorParams extends QueryVectorParams {
|
|
25
|
-
documentFilter?: VectorFilter;
|
|
23
|
+
interface ChromaQueryVectorParams extends QueryVectorParams<ChromaVectorFilter> {
|
|
24
|
+
documentFilter?: ChromaVectorDocumentFilter;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export class ChromaVector extends MastraVector {
|
|
27
|
+
export class ChromaVector extends MastraVector<ChromaVectorFilter> {
|
|
31
28
|
private client: ChromaClient;
|
|
32
29
|
private collections: Map<string, any>;
|
|
33
30
|
|
|
@@ -72,33 +69,35 @@ export class ChromaVector extends MastraVector {
|
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
|
|
75
|
-
async upsert(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const { indexName, vectors, metadata, ids, documents } = params;
|
|
79
|
-
|
|
80
|
-
const collection = await this.getCollection(indexName);
|
|
81
|
-
|
|
82
|
-
// Get index stats to check dimension
|
|
83
|
-
const stats = await this.describeIndex(indexName);
|
|
84
|
-
|
|
85
|
-
// Validate vector dimensions
|
|
86
|
-
this.validateVectorDimensions(vectors, stats.dimension);
|
|
87
|
-
|
|
88
|
-
// Generate IDs if not provided
|
|
89
|
-
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
72
|
+
async upsert({ indexName, vectors, metadata, ids, documents }: ChromaUpsertVectorParams): Promise<string[]> {
|
|
73
|
+
try {
|
|
74
|
+
const collection = await this.getCollection(indexName);
|
|
90
75
|
|
|
91
|
-
|
|
92
|
-
|
|
76
|
+
const stats = await this.describeIndex({ indexName });
|
|
77
|
+
this.validateVectorDimensions(vectors, stats.dimension);
|
|
78
|
+
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
79
|
+
const normalizedMetadata = metadata || vectors.map(() => ({}));
|
|
93
80
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
81
|
+
await collection.upsert({
|
|
82
|
+
ids: generatedIds,
|
|
83
|
+
embeddings: vectors,
|
|
84
|
+
metadatas: normalizedMetadata,
|
|
85
|
+
documents: documents,
|
|
86
|
+
});
|
|
100
87
|
|
|
101
|
-
|
|
88
|
+
return generatedIds;
|
|
89
|
+
} catch (error: any) {
|
|
90
|
+
if (error instanceof MastraError) throw error;
|
|
91
|
+
throw new MastraError(
|
|
92
|
+
{
|
|
93
|
+
id: 'CHROMA_VECTOR_UPSERT_FAILED',
|
|
94
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
95
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
96
|
+
details: { indexName },
|
|
97
|
+
},
|
|
98
|
+
error,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
private HnswSpaceMap = {
|
|
@@ -109,113 +108,233 @@ export class ChromaVector extends MastraVector {
|
|
|
109
108
|
ip: 'dotproduct',
|
|
110
109
|
};
|
|
111
110
|
|
|
112
|
-
async createIndex(
|
|
113
|
-
const params = this.normalizeArgs<CreateIndexParams>('createIndex', args);
|
|
114
|
-
|
|
115
|
-
const { indexName, dimension, metric = 'cosine' } = params;
|
|
116
|
-
|
|
111
|
+
async createIndex({ indexName, dimension, metric = 'cosine' }: CreateIndexParams): Promise<void> {
|
|
117
112
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
118
|
-
throw new
|
|
113
|
+
throw new MastraError({
|
|
114
|
+
id: 'CHROMA_VECTOR_CREATE_INDEX_INVALID_DIMENSION',
|
|
115
|
+
text: 'Dimension must be a positive integer',
|
|
116
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
117
|
+
category: ErrorCategory.USER,
|
|
118
|
+
details: { dimension },
|
|
119
|
+
});
|
|
119
120
|
}
|
|
120
121
|
const hnswSpace = this.HnswSpaceMap[metric];
|
|
121
|
-
if (!['cosine', 'l2', 'ip'].includes(hnswSpace)) {
|
|
122
|
-
throw new
|
|
122
|
+
if (!hnswSpace || !['cosine', 'l2', 'ip'].includes(hnswSpace)) {
|
|
123
|
+
throw new MastraError({
|
|
124
|
+
id: 'CHROMA_VECTOR_CREATE_INDEX_INVALID_METRIC',
|
|
125
|
+
text: `Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`,
|
|
126
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
127
|
+
category: ErrorCategory.USER,
|
|
128
|
+
details: { metric },
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
await this.client.createCollection({
|
|
133
|
+
name: indexName,
|
|
134
|
+
metadata: {
|
|
135
|
+
dimension,
|
|
136
|
+
'hnsw:space': hnswSpace,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
} catch (error: any) {
|
|
140
|
+
// Check for 'already exists' error
|
|
141
|
+
const message = error?.message || error?.toString();
|
|
142
|
+
if (message && message.toLowerCase().includes('already exists')) {
|
|
143
|
+
// Fetch collection info and check dimension
|
|
144
|
+
await this.validateExistingIndex(indexName, dimension, metric);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
throw new MastraError(
|
|
148
|
+
{
|
|
149
|
+
id: 'CHROMA_VECTOR_CREATE_INDEX_FAILED',
|
|
150
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
151
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
152
|
+
details: { indexName },
|
|
153
|
+
},
|
|
154
|
+
error,
|
|
155
|
+
);
|
|
123
156
|
}
|
|
124
|
-
await this.client.createCollection({
|
|
125
|
-
name: indexName,
|
|
126
|
-
metadata: {
|
|
127
|
-
dimension,
|
|
128
|
-
'hnsw:space': this.HnswSpaceMap[metric],
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
157
|
}
|
|
132
158
|
|
|
133
|
-
transformFilter(filter?:
|
|
159
|
+
transformFilter(filter?: ChromaVectorFilter) {
|
|
134
160
|
const translator = new ChromaFilterTranslator();
|
|
135
161
|
return translator.translate(filter);
|
|
136
162
|
}
|
|
137
|
-
async query(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
async query({
|
|
164
|
+
indexName,
|
|
165
|
+
queryVector,
|
|
166
|
+
topK = 10,
|
|
167
|
+
filter,
|
|
168
|
+
includeVector = false,
|
|
169
|
+
documentFilter,
|
|
170
|
+
}: ChromaQueryVectorParams): Promise<QueryResult[]> {
|
|
171
|
+
try {
|
|
172
|
+
const collection = await this.getCollection(indexName, true);
|
|
173
|
+
|
|
174
|
+
const defaultInclude = ['documents', 'metadatas', 'distances'];
|
|
175
|
+
|
|
176
|
+
const translatedFilter = this.transformFilter(filter);
|
|
177
|
+
const results = await collection.query({
|
|
178
|
+
queryEmbeddings: [queryVector],
|
|
179
|
+
nResults: topK,
|
|
180
|
+
where: translatedFilter,
|
|
181
|
+
whereDocument: documentFilter,
|
|
182
|
+
include: includeVector ? [...defaultInclude, 'embeddings'] : defaultInclude,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return (results.ids[0] || []).map((id: string, index: number) => ({
|
|
186
|
+
id,
|
|
187
|
+
score: results.distances?.[0]?.[index] || 0,
|
|
188
|
+
metadata: results.metadatas?.[0]?.[index] || {},
|
|
189
|
+
document: results.documents?.[0]?.[index],
|
|
190
|
+
...(includeVector && { vector: results.embeddings?.[0]?.[index] || [] }),
|
|
191
|
+
}));
|
|
192
|
+
} catch (error: any) {
|
|
193
|
+
if (error instanceof MastraError) throw error;
|
|
194
|
+
throw new MastraError(
|
|
195
|
+
{
|
|
196
|
+
id: 'CHROMA_VECTOR_QUERY_FAILED',
|
|
197
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
198
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
199
|
+
details: { indexName },
|
|
200
|
+
},
|
|
201
|
+
error,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
163
204
|
}
|
|
164
205
|
|
|
165
206
|
async listIndexes(): Promise<string[]> {
|
|
166
|
-
|
|
167
|
-
|
|
207
|
+
try {
|
|
208
|
+
const collections = await this.client.listCollections();
|
|
209
|
+
return collections.map(collection => collection);
|
|
210
|
+
} catch (error: any) {
|
|
211
|
+
throw new MastraError(
|
|
212
|
+
{
|
|
213
|
+
id: 'CHROMA_VECTOR_LIST_INDEXES_FAILED',
|
|
214
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
215
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
216
|
+
},
|
|
217
|
+
error,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
168
220
|
}
|
|
169
221
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Retrieves statistics about a vector index.
|
|
224
|
+
*
|
|
225
|
+
* @param {string} indexName - The name of the index to describe
|
|
226
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
227
|
+
*/
|
|
228
|
+
async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {
|
|
229
|
+
try {
|
|
230
|
+
const collection = await this.getCollection(indexName);
|
|
231
|
+
const count = await collection.count();
|
|
232
|
+
const metadata = collection.metadata;
|
|
174
233
|
|
|
175
|
-
|
|
234
|
+
const hnswSpace = metadata?.['hnsw:space'] as 'cosine' | 'l2' | 'ip';
|
|
176
235
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
236
|
+
return {
|
|
237
|
+
dimension: metadata?.dimension || 0,
|
|
238
|
+
count,
|
|
239
|
+
metric: this.HnswSpaceMap[hnswSpace] as 'cosine' | 'euclidean' | 'dotproduct',
|
|
240
|
+
};
|
|
241
|
+
} catch (error: any) {
|
|
242
|
+
if (error instanceof MastraError) throw error;
|
|
243
|
+
throw new MastraError(
|
|
244
|
+
{
|
|
245
|
+
id: 'CHROMA_VECTOR_DESCRIBE_INDEX_FAILED',
|
|
246
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
247
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
248
|
+
details: { indexName },
|
|
249
|
+
},
|
|
250
|
+
error,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
182
253
|
}
|
|
183
254
|
|
|
184
|
-
async deleteIndex(indexName:
|
|
185
|
-
|
|
186
|
-
|
|
255
|
+
async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {
|
|
256
|
+
try {
|
|
257
|
+
await this.client.deleteCollection({ name: indexName });
|
|
258
|
+
this.collections.delete(indexName);
|
|
259
|
+
} catch (error: any) {
|
|
260
|
+
throw new MastraError(
|
|
261
|
+
{
|
|
262
|
+
id: 'CHROMA_VECTOR_DELETE_INDEX_FAILED',
|
|
263
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
264
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
265
|
+
details: { indexName },
|
|
266
|
+
},
|
|
267
|
+
error,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
187
270
|
}
|
|
188
271
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
274
|
+
* @param indexName - The name of the index containing the vector.
|
|
275
|
+
* @param id - The ID of the vector to update.
|
|
276
|
+
* @param update - An object containing the vector and/or metadata to update.
|
|
277
|
+
* @param update.vector - An optional array of numbers representing the new vector.
|
|
278
|
+
* @param update.metadata - An optional record containing the new metadata.
|
|
279
|
+
* @returns A promise that resolves when the update is complete.
|
|
280
|
+
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
281
|
+
*/
|
|
282
|
+
async updateVector({ indexName, id, update }: UpdateVectorParams): Promise<void> {
|
|
194
283
|
if (!update.vector && !update.metadata) {
|
|
195
|
-
throw new
|
|
284
|
+
throw new MastraError({
|
|
285
|
+
id: 'CHROMA_VECTOR_UPDATE_NO_PAYLOAD',
|
|
286
|
+
text: 'No updates provided for vector',
|
|
287
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
288
|
+
category: ErrorCategory.USER,
|
|
289
|
+
details: { indexName, id },
|
|
290
|
+
});
|
|
196
291
|
}
|
|
197
292
|
|
|
198
|
-
|
|
293
|
+
try {
|
|
294
|
+
const collection: Collection = await this.getCollection(indexName, true);
|
|
199
295
|
|
|
200
|
-
|
|
296
|
+
const updateOptions: UpdateRecordsParams = { ids: [id] };
|
|
201
297
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
298
|
+
if (update?.vector) {
|
|
299
|
+
const stats = await this.describeIndex({ indexName });
|
|
300
|
+
this.validateVectorDimensions([update.vector], stats.dimension);
|
|
301
|
+
updateOptions.embeddings = [update.vector];
|
|
302
|
+
}
|
|
205
303
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
304
|
+
if (update?.metadata) {
|
|
305
|
+
updateOptions.metadatas = [update.metadata];
|
|
306
|
+
}
|
|
209
307
|
|
|
210
|
-
|
|
308
|
+
return await collection.update(updateOptions);
|
|
309
|
+
} catch (error: any) {
|
|
310
|
+
if (error instanceof MastraError) throw error;
|
|
311
|
+
throw new MastraError(
|
|
312
|
+
{
|
|
313
|
+
id: 'CHROMA_VECTOR_UPDATE_FAILED',
|
|
314
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
315
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
316
|
+
details: { indexName, id },
|
|
317
|
+
},
|
|
318
|
+
error,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
211
321
|
}
|
|
212
322
|
|
|
213
|
-
async
|
|
323
|
+
async deleteVector({ indexName, id }: DeleteVectorParams): Promise<void> {
|
|
214
324
|
try {
|
|
215
325
|
const collection: Collection = await this.getCollection(indexName, true);
|
|
216
326
|
await collection.delete({ ids: [id] });
|
|
217
327
|
} catch (error: any) {
|
|
218
|
-
|
|
328
|
+
if (error instanceof MastraError) throw error;
|
|
329
|
+
throw new MastraError(
|
|
330
|
+
{
|
|
331
|
+
id: 'CHROMA_VECTOR_DELETE_FAILED',
|
|
332
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
333
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
334
|
+
details: { indexName, id },
|
|
335
|
+
},
|
|
336
|
+
error,
|
|
337
|
+
);
|
|
219
338
|
}
|
|
220
339
|
}
|
|
221
340
|
}
|