@mastra/chroma 0.1.0-alpha.36 → 0.1.0-alpha.38
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 +14 -0
- package/dist/_tsup-dts-rollup.d.ts +43 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +192 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @mastra/chroma
|
|
2
2
|
|
|
3
|
+
## 0.1.0-alpha.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [4534e77]
|
|
8
|
+
- @mastra/core@0.2.0-alpha.103
|
|
9
|
+
|
|
10
|
+
## 0.1.0-alpha.37
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [a9345f9]
|
|
15
|
+
- @mastra/core@0.2.0-alpha.102
|
|
16
|
+
|
|
3
17
|
## 0.1.0-alpha.36
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
+
import { Filter } from '@mastra/core/filter';
|
|
3
|
+
import { IndexStats } from '@mastra/core/vector';
|
|
4
|
+
import { MastraVector } from '@mastra/core/vector';
|
|
5
|
+
import { OperatorSupport } from '@mastra/core/filter';
|
|
6
|
+
import { QueryResult } from '@mastra/core/vector';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Translator for Chroma filter queries.
|
|
10
|
+
* Maintains MongoDB-compatible syntax while ensuring proper validation
|
|
11
|
+
* and normalization of values.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
14
|
+
protected getSupportedOperators(): OperatorSupport;
|
|
15
|
+
translate(filter?: Filter): Filter | undefined;
|
|
16
|
+
private translateNode;
|
|
17
|
+
private translateOperator;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare class ChromaVector extends MastraVector {
|
|
21
|
+
private client;
|
|
22
|
+
private collections;
|
|
23
|
+
constructor({ path, auth, }: {
|
|
24
|
+
path: string;
|
|
25
|
+
auth?: {
|
|
26
|
+
provider: string;
|
|
27
|
+
credentials: string;
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
private getCollection;
|
|
31
|
+
private validateVectorDimensions;
|
|
32
|
+
upsert(indexName: string, vectors: number[][], metadata?: Record<string, any>[], ids?: string[]): Promise<string[]>;
|
|
33
|
+
createIndex(indexName: string, dimension: number, metric?: 'cosine' | 'euclidean' | 'dotproduct'): Promise<void>;
|
|
34
|
+
transformFilter(filter?: Filter): Filter | undefined;
|
|
35
|
+
query(indexName: string, queryVector: number[], topK?: number, filter?: Filter, includeVector?: boolean): Promise<QueryResult[]>;
|
|
36
|
+
listIndexes(): Promise<string[]>;
|
|
37
|
+
describeIndex(indexName: string): Promise<IndexStats>;
|
|
38
|
+
deleteIndex(indexName: string): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
export { ChromaVector }
|
|
41
|
+
export { ChromaVector as ChromaVector_alias_1 }
|
|
42
|
+
|
|
43
|
+
export { }
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChromaVector } from './_tsup-dts-rollup.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
+
import { MastraVector } from '@mastra/core/vector';
|
|
3
|
+
import { ChromaClient } from 'chromadb';
|
|
4
|
+
|
|
5
|
+
// src/vector/index.ts
|
|
6
|
+
var ChromaFilterTranslator = class extends BaseFilterTranslator {
|
|
7
|
+
getSupportedOperators() {
|
|
8
|
+
return {
|
|
9
|
+
...BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
10
|
+
logical: ["$and", "$or"],
|
|
11
|
+
array: ["$in", "$nin"],
|
|
12
|
+
element: [],
|
|
13
|
+
regex: [],
|
|
14
|
+
custom: []
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
translate(filter) {
|
|
18
|
+
if (this.isEmpty(filter)) return filter;
|
|
19
|
+
this.validateFilter(filter);
|
|
20
|
+
return this.translateNode(filter);
|
|
21
|
+
}
|
|
22
|
+
translateNode(node, currentPath = "") {
|
|
23
|
+
if (this.isRegex(node)) {
|
|
24
|
+
throw new Error("Regex is not supported in Chroma");
|
|
25
|
+
}
|
|
26
|
+
if (this.isPrimitive(node)) return this.normalizeComparisonValue(node);
|
|
27
|
+
if (Array.isArray(node)) return { $in: this.normalizeArrayValues(node) };
|
|
28
|
+
const entries = Object.entries(node);
|
|
29
|
+
const firstEntry = entries[0];
|
|
30
|
+
if (entries.length === 1 && firstEntry && this.isOperator(firstEntry[0])) {
|
|
31
|
+
const [operator, value] = firstEntry;
|
|
32
|
+
const translated = this.translateOperator(operator, value);
|
|
33
|
+
return this.isLogicalOperator(operator) ? { [operator]: translated } : translated;
|
|
34
|
+
}
|
|
35
|
+
const result = {};
|
|
36
|
+
const multiOperatorConditions = [];
|
|
37
|
+
for (const [key, value] of entries) {
|
|
38
|
+
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
39
|
+
if (this.isOperator(key)) {
|
|
40
|
+
result[key] = this.translateOperator(key, value);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
44
|
+
const valueEntries = Object.entries(value);
|
|
45
|
+
if (valueEntries.every(([op]) => this.isOperator(op)) && valueEntries.length > 1) {
|
|
46
|
+
valueEntries.forEach(([op, opValue]) => {
|
|
47
|
+
multiOperatorConditions.push({
|
|
48
|
+
[newPath]: { [op]: this.normalizeComparisonValue(opValue) }
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (Object.keys(value).length === 0) {
|
|
54
|
+
result[newPath] = this.translateNode(value);
|
|
55
|
+
} else {
|
|
56
|
+
const hasOperators = Object.keys(value).some((k) => this.isOperator(k));
|
|
57
|
+
if (hasOperators) {
|
|
58
|
+
const normalizedValue = {};
|
|
59
|
+
for (const [op, opValue] of Object.entries(value)) {
|
|
60
|
+
normalizedValue[op] = this.isOperator(op) ? this.translateOperator(op, opValue) : opValue;
|
|
61
|
+
}
|
|
62
|
+
result[newPath] = normalizedValue;
|
|
63
|
+
} else {
|
|
64
|
+
Object.assign(result, this.translateNode(value, newPath));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
result[newPath] = this.translateNode(value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (multiOperatorConditions.length > 0) {
|
|
72
|
+
return { $and: multiOperatorConditions };
|
|
73
|
+
}
|
|
74
|
+
if (Object.keys(result).length > 1 && !currentPath) {
|
|
75
|
+
return {
|
|
76
|
+
$and: Object.entries(result).map(([key, value]) => ({ [key]: value }))
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
translateOperator(operator, value) {
|
|
82
|
+
if (this.isLogicalOperator(operator)) {
|
|
83
|
+
return Array.isArray(value) ? value.map((item) => this.translateNode(item)) : this.translateNode(value);
|
|
84
|
+
}
|
|
85
|
+
return this.normalizeComparisonValue(value);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/vector/index.ts
|
|
90
|
+
var ChromaVector = class extends MastraVector {
|
|
91
|
+
client;
|
|
92
|
+
collections;
|
|
93
|
+
constructor({
|
|
94
|
+
path,
|
|
95
|
+
auth
|
|
96
|
+
}) {
|
|
97
|
+
super();
|
|
98
|
+
this.client = new ChromaClient({
|
|
99
|
+
path,
|
|
100
|
+
auth
|
|
101
|
+
});
|
|
102
|
+
this.collections = /* @__PURE__ */ new Map();
|
|
103
|
+
}
|
|
104
|
+
async getCollection(indexName, throwIfNotExists = true) {
|
|
105
|
+
try {
|
|
106
|
+
const collection = await this.client.getCollection({ name: indexName, embeddingFunction: void 0 });
|
|
107
|
+
this.collections.set(indexName, collection);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (throwIfNotExists) {
|
|
110
|
+
throw new Error(`Index ${indexName} does not exist`);
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return this.collections.get(indexName);
|
|
115
|
+
}
|
|
116
|
+
validateVectorDimensions(vectors, dimension) {
|
|
117
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
118
|
+
if (vectors?.[i]?.length !== dimension) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Vector at index ${i} has invalid dimension ${vectors?.[i]?.length}. Expected ${dimension} dimensions.`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async upsert(indexName, vectors, metadata, ids) {
|
|
126
|
+
const collection = await this.getCollection(indexName);
|
|
127
|
+
const stats = await this.describeIndex(indexName);
|
|
128
|
+
this.validateVectorDimensions(vectors, stats.dimension);
|
|
129
|
+
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
130
|
+
const normalizedMetadata = metadata || vectors.map(() => ({}));
|
|
131
|
+
await collection.upsert({
|
|
132
|
+
ids: generatedIds,
|
|
133
|
+
embeddings: vectors,
|
|
134
|
+
metadatas: normalizedMetadata
|
|
135
|
+
});
|
|
136
|
+
return generatedIds;
|
|
137
|
+
}
|
|
138
|
+
async createIndex(indexName, dimension, metric = "cosine") {
|
|
139
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
140
|
+
throw new Error("Dimension must be a positive integer");
|
|
141
|
+
}
|
|
142
|
+
await this.client.createCollection({
|
|
143
|
+
name: indexName,
|
|
144
|
+
metadata: {
|
|
145
|
+
dimension,
|
|
146
|
+
metric
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
transformFilter(filter) {
|
|
151
|
+
const chromaFilter = new ChromaFilterTranslator();
|
|
152
|
+
const translatedFilter = chromaFilter.translate(filter);
|
|
153
|
+
return translatedFilter;
|
|
154
|
+
}
|
|
155
|
+
async query(indexName, queryVector, topK = 10, filter, includeVector = false) {
|
|
156
|
+
const collection = await this.getCollection(indexName, true);
|
|
157
|
+
const defaultInclude = ["documents", "metadatas", "distances"];
|
|
158
|
+
const translatedFilter = this.transformFilter(filter);
|
|
159
|
+
const results = await collection.query({
|
|
160
|
+
queryEmbeddings: [queryVector],
|
|
161
|
+
nResults: topK,
|
|
162
|
+
where: translatedFilter,
|
|
163
|
+
include: includeVector ? [...defaultInclude, "embeddings"] : defaultInclude
|
|
164
|
+
});
|
|
165
|
+
return (results.ids[0] || []).map((id, index) => ({
|
|
166
|
+
id,
|
|
167
|
+
score: results.distances?.[0]?.[index] || 0,
|
|
168
|
+
metadata: results.metadatas?.[0]?.[index] || {},
|
|
169
|
+
...includeVector && { vector: results.embeddings?.[0]?.[index] || [] }
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
async listIndexes() {
|
|
173
|
+
const collections = await this.client.listCollections();
|
|
174
|
+
return collections.map((collection) => collection);
|
|
175
|
+
}
|
|
176
|
+
async describeIndex(indexName) {
|
|
177
|
+
const collection = await this.getCollection(indexName);
|
|
178
|
+
const count = await collection.count();
|
|
179
|
+
const metadata = collection.metadata;
|
|
180
|
+
return {
|
|
181
|
+
dimension: metadata?.dimension || 0,
|
|
182
|
+
count,
|
|
183
|
+
metric: metadata?.metric
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async deleteIndex(indexName) {
|
|
187
|
+
await this.client.deleteCollection({ name: indexName });
|
|
188
|
+
this.collections.delete(indexName);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export { ChromaVector };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/chroma",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.38",
|
|
4
4
|
"description": "Chroma vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"chromadb": "^1.9.4",
|
|
19
|
-
"@mastra/core": "^0.2.0-alpha.
|
|
19
|
+
"@mastra/core": "^0.2.0-alpha.103"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@microsoft/api-extractor": "^7.49.2",
|