@mastra/chroma 0.1.6-alpha.1 → 0.1.6-alpha.4
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/.turbo/turbo-build.log +11 -6
- package/CHANGELOG.md +31 -0
- package/README.md +16 -17
- package/dist/_tsup-dts-rollup.d.cts +56 -0
- package/dist/_tsup-dts-rollup.d.ts +20 -15
- package/dist/index.cjs +214 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +12 -7
- package/package.json +7 -3
- package/src/vector/filter.ts +5 -5
- package/src/vector/index.test.ts +563 -224
- package/src/vector/index.ts +33 -29
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/chroma@0.1.6-alpha.
|
|
3
|
-
> tsup src/index.ts --format esm --experimental-dts --clean --treeshake
|
|
2
|
+
> @mastra/chroma@0.1.6-alpha.4 build /home/runner/work/mastra/mastra/stores/chroma
|
|
3
|
+
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
7
|
[34mCLI[39m tsup v8.3.6
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 6393ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.7.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/chroma/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
|
-
|
|
14
|
+
Analysis will use the bundled TypeScript version 5.7.3
|
|
15
|
+
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/chroma/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 8226ms
|
|
15
17
|
[34mCLI[39m Cleaning output folder
|
|
16
18
|
[34mESM[39m Build start
|
|
17
|
-
[
|
|
18
|
-
[32mESM[39m
|
|
19
|
+
[34mCJS[39m Build start
|
|
20
|
+
[32mESM[39m [1mdist/index.js [22m[32m7.28 KB[39m
|
|
21
|
+
[32mESM[39m ⚡️ Build success in 637ms
|
|
22
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m7.31 KB[39m
|
|
23
|
+
[32mCJS[39m ⚡️ Build success in 637ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# @mastra/chroma
|
|
2
2
|
|
|
3
|
+
## 0.1.6-alpha.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [dabecf4]
|
|
8
|
+
- @mastra/core@0.4.3-alpha.4
|
|
9
|
+
|
|
10
|
+
## 0.1.6-alpha.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 0fd78ac: Update vector store functions to use object params
|
|
15
|
+
- fd14a3f: Updating filter location from @mastra/core/filter to @mastra/core/vector/filter
|
|
16
|
+
- 4d4e1e1: Updated vector tests and pinecone
|
|
17
|
+
- bb4f447: Add support for commonjs
|
|
18
|
+
- Updated dependencies [0fd78ac]
|
|
19
|
+
- Updated dependencies [0d25b75]
|
|
20
|
+
- Updated dependencies [fd14a3f]
|
|
21
|
+
- Updated dependencies [3f369a2]
|
|
22
|
+
- Updated dependencies [4d4e1e1]
|
|
23
|
+
- Updated dependencies [bb4f447]
|
|
24
|
+
- @mastra/core@0.4.3-alpha.3
|
|
25
|
+
|
|
26
|
+
## 0.1.6-alpha.2
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [2512a93]
|
|
31
|
+
- Updated dependencies [e62de74]
|
|
32
|
+
- @mastra/core@0.4.3-alpha.2
|
|
33
|
+
|
|
3
34
|
## 0.1.6-alpha.1
|
|
4
35
|
|
|
5
36
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -22,29 +22,28 @@ const vectorStore = new ChromaVector({
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
// Create a new collection
|
|
25
|
-
await vectorStore.createIndex('my-collection', 1536, 'cosine');
|
|
25
|
+
await vectorStore.createIndex({ indexName: 'my-collection', dimension: 1536, metric: 'cosine' });
|
|
26
26
|
|
|
27
27
|
// Add vectors with documents
|
|
28
28
|
const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]];
|
|
29
29
|
const metadata = [{ text: 'doc1' }, { text: 'doc2' }];
|
|
30
30
|
const documents = ['full text 1', 'full text 2'];
|
|
31
|
-
const ids = await vectorStore.upsert(
|
|
32
|
-
'my-collection',
|
|
31
|
+
const ids = await vectorStore.upsert({
|
|
32
|
+
indexName: 'my-collection',
|
|
33
33
|
vectors,
|
|
34
34
|
metadata,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
);
|
|
35
|
+
documents, // store original text
|
|
36
|
+
});
|
|
38
37
|
|
|
39
38
|
// Query vectors with document filtering
|
|
40
|
-
const results = await vectorStore.query(
|
|
41
|
-
'my-collection',
|
|
42
|
-
[0.1, 0.2, ...],
|
|
43
|
-
10, // topK
|
|
44
|
-
{ text: { $eq: 'doc1' } }, // metadata filter
|
|
45
|
-
false, // includeVector
|
|
46
|
-
{ $contains: 'specific text' } // document content filter
|
|
47
|
-
);
|
|
39
|
+
const results = await vectorStore.query({
|
|
40
|
+
indexName: 'my-collection',
|
|
41
|
+
queryVector: [0.1, 0.2, ...],
|
|
42
|
+
topK: 10, // topK
|
|
43
|
+
filter: { text: { $eq: 'doc1' } }, // metadata filter
|
|
44
|
+
includeVector: false, // includeVector
|
|
45
|
+
documentFilter: { $contains: 'specific text' } // document content filter
|
|
46
|
+
});
|
|
48
47
|
```
|
|
49
48
|
|
|
50
49
|
## Configuration
|
|
@@ -74,9 +73,9 @@ Optional:
|
|
|
74
73
|
|
|
75
74
|
## Methods
|
|
76
75
|
|
|
77
|
-
- `createIndex(indexName, dimension, metric?)`: Create a new collection
|
|
78
|
-
- `upsert(indexName, vectors, metadata?, ids?, documents?)`: Add or update vectors with optional document storage
|
|
79
|
-
- `query(indexName, queryVector, topK?, filter?, includeVector?, documentFilter?)`: Search for similar vectors with optional document filtering
|
|
76
|
+
- `createIndex({ indexName, dimension, metric? })`: Create a new collection
|
|
77
|
+
- `upsert({ indexName, vectors, metadata?, ids?, documents? })`: Add or update vectors with optional document storage
|
|
78
|
+
- `query({ indexName, queryVector, topK?, filter?, includeVector?, documentFilter? })`: Search for similar vectors with optional document filtering
|
|
80
79
|
- `listIndexes()`: List all collections
|
|
81
80
|
- `describeIndex(indexName)`: Get collection statistics
|
|
82
81
|
- `deleteIndex(indexName)`: Delete a collection
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import type { CreateIndexParams } from '@mastra/core/vector';
|
|
3
|
+
import type { IndexStats } from '@mastra/core/vector';
|
|
4
|
+
import { MastraVector } from '@mastra/core/vector';
|
|
5
|
+
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
6
|
+
import type { ParamsToArgs } from '@mastra/core/vector';
|
|
7
|
+
import type { QueryResult } from '@mastra/core/vector';
|
|
8
|
+
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
9
|
+
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
10
|
+
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Translator for Chroma filter queries.
|
|
14
|
+
* Maintains MongoDB-compatible syntax while ensuring proper validation
|
|
15
|
+
* and normalization of values.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
18
|
+
protected getSupportedOperators(): OperatorSupport;
|
|
19
|
+
translate(filter?: VectorFilter): VectorFilter;
|
|
20
|
+
private translateNode;
|
|
21
|
+
private translateOperator;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare interface ChromaQueryVectorParams extends QueryVectorParams {
|
|
25
|
+
documentFilter?: VectorFilter;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare interface ChromaUpsertVectorParams extends UpsertVectorParams {
|
|
29
|
+
documents?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
declare class ChromaVector extends MastraVector {
|
|
33
|
+
private client;
|
|
34
|
+
private collections;
|
|
35
|
+
constructor({ path, auth, }: {
|
|
36
|
+
path: string;
|
|
37
|
+
auth?: {
|
|
38
|
+
provider: string;
|
|
39
|
+
credentials: string;
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
getCollection(indexName: string, throwIfNotExists?: boolean): Promise<any>;
|
|
43
|
+
private validateVectorDimensions;
|
|
44
|
+
upsert(...args: ParamsToArgs<ChromaUpsertVectorParams>): Promise<string[]>;
|
|
45
|
+
private HnswSpaceMap;
|
|
46
|
+
createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
|
|
47
|
+
transformFilter(filter?: VectorFilter): VectorFilter;
|
|
48
|
+
query(...args: ParamsToArgs<ChromaQueryVectorParams>): Promise<QueryResult[]>;
|
|
49
|
+
listIndexes(): Promise<string[]>;
|
|
50
|
+
describeIndex(indexName: string): Promise<IndexStats>;
|
|
51
|
+
deleteIndex(indexName: string): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
export { ChromaVector }
|
|
54
|
+
export { ChromaVector as ChromaVector_alias_1 }
|
|
55
|
+
|
|
56
|
+
export { }
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
-
import type {
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import type { CreateIndexParams } from '@mastra/core/vector';
|
|
3
3
|
import type { IndexStats } from '@mastra/core/vector';
|
|
4
4
|
import { MastraVector } from '@mastra/core/vector';
|
|
5
|
-
import type { OperatorSupport } from '@mastra/core/filter';
|
|
5
|
+
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
6
|
+
import type { ParamsToArgs } from '@mastra/core/vector';
|
|
6
7
|
import type { QueryResult } from '@mastra/core/vector';
|
|
8
|
+
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
9
|
+
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
10
|
+
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* Translator for Chroma filter queries.
|
|
@@ -12,11 +16,19 @@ import type { QueryResult } from '@mastra/core/vector';
|
|
|
12
16
|
*/
|
|
13
17
|
export declare class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
14
18
|
protected getSupportedOperators(): OperatorSupport;
|
|
15
|
-
translate(filter?:
|
|
19
|
+
translate(filter?: VectorFilter): VectorFilter;
|
|
16
20
|
private translateNode;
|
|
17
21
|
private translateOperator;
|
|
18
22
|
}
|
|
19
23
|
|
|
24
|
+
declare interface ChromaQueryVectorParams extends QueryVectorParams {
|
|
25
|
+
documentFilter?: VectorFilter;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare interface ChromaUpsertVectorParams extends UpsertVectorParams {
|
|
29
|
+
documents?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
declare class ChromaVector extends MastraVector {
|
|
21
33
|
private client;
|
|
22
34
|
private collections;
|
|
@@ -29,11 +41,11 @@ declare class ChromaVector extends MastraVector {
|
|
|
29
41
|
});
|
|
30
42
|
getCollection(indexName: string, throwIfNotExists?: boolean): Promise<any>;
|
|
31
43
|
private validateVectorDimensions;
|
|
32
|
-
upsert(
|
|
44
|
+
upsert(...args: ParamsToArgs<ChromaUpsertVectorParams>): Promise<string[]>;
|
|
33
45
|
private HnswSpaceMap;
|
|
34
|
-
createIndex(
|
|
35
|
-
transformFilter(filter?:
|
|
36
|
-
query(
|
|
46
|
+
createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
|
|
47
|
+
transformFilter(filter?: VectorFilter): VectorFilter;
|
|
48
|
+
query(...args: ParamsToArgs<ChromaQueryVectorParams>): Promise<QueryResult[]>;
|
|
37
49
|
listIndexes(): Promise<string[]>;
|
|
38
50
|
describeIndex(indexName: string): Promise<IndexStats>;
|
|
39
51
|
deleteIndex(indexName: string): Promise<void>;
|
|
@@ -41,11 +53,4 @@ declare class ChromaVector extends MastraVector {
|
|
|
41
53
|
export { ChromaVector }
|
|
42
54
|
export { ChromaVector as ChromaVector_alias_1 }
|
|
43
55
|
|
|
44
|
-
declare interface DocumentMetadata {
|
|
45
|
-
content?: string;
|
|
46
|
-
metadata?: Record<string, any>;
|
|
47
|
-
}
|
|
48
|
-
export { DocumentMetadata }
|
|
49
|
-
export { DocumentMetadata as DocumentMetadata_alias_1 }
|
|
50
|
-
|
|
51
56
|
export { }
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vector = require('@mastra/core/vector');
|
|
4
|
+
var chromadb = require('chromadb');
|
|
5
|
+
var filter = require('@mastra/core/vector/filter');
|
|
6
|
+
|
|
7
|
+
// src/vector/index.ts
|
|
8
|
+
var ChromaFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
9
|
+
getSupportedOperators() {
|
|
10
|
+
return {
|
|
11
|
+
...filter.BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
12
|
+
logical: ["$and", "$or"],
|
|
13
|
+
array: ["$in", "$nin"],
|
|
14
|
+
element: [],
|
|
15
|
+
regex: [],
|
|
16
|
+
custom: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
translate(filter) {
|
|
20
|
+
if (this.isEmpty(filter)) return filter;
|
|
21
|
+
this.validateFilter(filter);
|
|
22
|
+
return this.translateNode(filter);
|
|
23
|
+
}
|
|
24
|
+
translateNode(node, currentPath = "") {
|
|
25
|
+
if (this.isRegex(node)) {
|
|
26
|
+
throw new Error("Regex is not supported in Chroma");
|
|
27
|
+
}
|
|
28
|
+
if (this.isPrimitive(node)) return this.normalizeComparisonValue(node);
|
|
29
|
+
if (Array.isArray(node)) return { $in: this.normalizeArrayValues(node) };
|
|
30
|
+
const entries = Object.entries(node);
|
|
31
|
+
const firstEntry = entries[0];
|
|
32
|
+
if (entries.length === 1 && firstEntry && this.isOperator(firstEntry[0])) {
|
|
33
|
+
const [operator, value] = firstEntry;
|
|
34
|
+
const translated = this.translateOperator(operator, value);
|
|
35
|
+
return this.isLogicalOperator(operator) ? { [operator]: translated } : translated;
|
|
36
|
+
}
|
|
37
|
+
const result = {};
|
|
38
|
+
const multiOperatorConditions = [];
|
|
39
|
+
for (const [key, value] of entries) {
|
|
40
|
+
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
41
|
+
if (this.isOperator(key)) {
|
|
42
|
+
result[key] = this.translateOperator(key, value);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
46
|
+
const valueEntries = Object.entries(value);
|
|
47
|
+
if (valueEntries.every(([op]) => this.isOperator(op)) && valueEntries.length > 1) {
|
|
48
|
+
valueEntries.forEach(([op, opValue]) => {
|
|
49
|
+
multiOperatorConditions.push({
|
|
50
|
+
[newPath]: { [op]: this.normalizeComparisonValue(opValue) }
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (Object.keys(value).length === 0) {
|
|
56
|
+
result[newPath] = this.translateNode(value);
|
|
57
|
+
} else {
|
|
58
|
+
const hasOperators = Object.keys(value).some((k) => this.isOperator(k));
|
|
59
|
+
if (hasOperators) {
|
|
60
|
+
const normalizedValue = {};
|
|
61
|
+
for (const [op, opValue] of Object.entries(value)) {
|
|
62
|
+
normalizedValue[op] = this.isOperator(op) ? this.translateOperator(op, opValue) : opValue;
|
|
63
|
+
}
|
|
64
|
+
result[newPath] = normalizedValue;
|
|
65
|
+
} else {
|
|
66
|
+
Object.assign(result, this.translateNode(value, newPath));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
result[newPath] = this.translateNode(value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (multiOperatorConditions.length > 0) {
|
|
74
|
+
return { $and: multiOperatorConditions };
|
|
75
|
+
}
|
|
76
|
+
if (Object.keys(result).length > 1 && !currentPath) {
|
|
77
|
+
return {
|
|
78
|
+
$and: Object.entries(result).map(([key, value]) => ({ [key]: value }))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
translateOperator(operator, value) {
|
|
84
|
+
if (this.isLogicalOperator(operator)) {
|
|
85
|
+
return Array.isArray(value) ? value.map((item) => this.translateNode(item)) : this.translateNode(value);
|
|
86
|
+
}
|
|
87
|
+
return this.normalizeComparisonValue(value);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/vector/index.ts
|
|
92
|
+
var ChromaVector = class extends vector.MastraVector {
|
|
93
|
+
client;
|
|
94
|
+
collections;
|
|
95
|
+
constructor({
|
|
96
|
+
path,
|
|
97
|
+
auth
|
|
98
|
+
}) {
|
|
99
|
+
super();
|
|
100
|
+
this.client = new chromadb.ChromaClient({
|
|
101
|
+
path,
|
|
102
|
+
auth
|
|
103
|
+
});
|
|
104
|
+
this.collections = /* @__PURE__ */ new Map();
|
|
105
|
+
}
|
|
106
|
+
async getCollection(indexName, throwIfNotExists = true) {
|
|
107
|
+
try {
|
|
108
|
+
const collection = await this.client.getCollection({ name: indexName, embeddingFunction: void 0 });
|
|
109
|
+
this.collections.set(indexName, collection);
|
|
110
|
+
} catch {
|
|
111
|
+
if (throwIfNotExists) {
|
|
112
|
+
throw new Error(`Index ${indexName} does not exist`);
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return this.collections.get(indexName);
|
|
117
|
+
}
|
|
118
|
+
validateVectorDimensions(vectors, dimension) {
|
|
119
|
+
for (let i = 0; i < vectors.length; i++) {
|
|
120
|
+
if (vectors?.[i]?.length !== dimension) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Vector at index ${i} has invalid dimension ${vectors?.[i]?.length}. Expected ${dimension} dimensions.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async upsert(...args) {
|
|
128
|
+
const params = this.normalizeArgs("upsert", args, ["documents"]);
|
|
129
|
+
const { indexName, vectors, metadata, ids, documents } = params;
|
|
130
|
+
const collection = await this.getCollection(indexName);
|
|
131
|
+
const stats = await this.describeIndex(indexName);
|
|
132
|
+
this.validateVectorDimensions(vectors, stats.dimension);
|
|
133
|
+
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
134
|
+
const normalizedMetadata = metadata || vectors.map(() => ({}));
|
|
135
|
+
await collection.upsert({
|
|
136
|
+
ids: generatedIds,
|
|
137
|
+
embeddings: vectors,
|
|
138
|
+
metadatas: normalizedMetadata,
|
|
139
|
+
documents
|
|
140
|
+
});
|
|
141
|
+
return generatedIds;
|
|
142
|
+
}
|
|
143
|
+
HnswSpaceMap = {
|
|
144
|
+
cosine: "cosine",
|
|
145
|
+
euclidean: "l2",
|
|
146
|
+
dotproduct: "ip",
|
|
147
|
+
l2: "euclidean",
|
|
148
|
+
ip: "dotproduct"
|
|
149
|
+
};
|
|
150
|
+
async createIndex(...args) {
|
|
151
|
+
const params = this.normalizeArgs("createIndex", args);
|
|
152
|
+
const { indexName, dimension, metric = "cosine" } = params;
|
|
153
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
154
|
+
throw new Error("Dimension must be a positive integer");
|
|
155
|
+
}
|
|
156
|
+
const hnswSpace = this.HnswSpaceMap[metric];
|
|
157
|
+
if (!["cosine", "l2", "ip"].includes(hnswSpace)) {
|
|
158
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
159
|
+
}
|
|
160
|
+
await this.client.createCollection({
|
|
161
|
+
name: indexName,
|
|
162
|
+
metadata: {
|
|
163
|
+
dimension,
|
|
164
|
+
"hnsw:space": this.HnswSpaceMap[metric]
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
transformFilter(filter) {
|
|
169
|
+
const translator = new ChromaFilterTranslator();
|
|
170
|
+
return translator.translate(filter);
|
|
171
|
+
}
|
|
172
|
+
async query(...args) {
|
|
173
|
+
const params = this.normalizeArgs("query", args, ["documentFilter"]);
|
|
174
|
+
const { indexName, queryVector, topK = 10, filter, includeVector = false, documentFilter } = params;
|
|
175
|
+
const collection = await this.getCollection(indexName, true);
|
|
176
|
+
const defaultInclude = ["documents", "metadatas", "distances"];
|
|
177
|
+
const translatedFilter = this.transformFilter(filter);
|
|
178
|
+
const results = await collection.query({
|
|
179
|
+
queryEmbeddings: [queryVector],
|
|
180
|
+
nResults: topK,
|
|
181
|
+
where: translatedFilter,
|
|
182
|
+
whereDocument: documentFilter,
|
|
183
|
+
include: includeVector ? [...defaultInclude, "embeddings"] : defaultInclude
|
|
184
|
+
});
|
|
185
|
+
return (results.ids[0] || []).map((id, index) => ({
|
|
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
|
+
}
|
|
193
|
+
async listIndexes() {
|
|
194
|
+
const collections = await this.client.listCollections();
|
|
195
|
+
return collections.map((collection) => collection);
|
|
196
|
+
}
|
|
197
|
+
async describeIndex(indexName) {
|
|
198
|
+
const collection = await this.getCollection(indexName);
|
|
199
|
+
const count = await collection.count();
|
|
200
|
+
const metadata = collection.metadata;
|
|
201
|
+
const hnswSpace = metadata?.["hnsw:space"];
|
|
202
|
+
return {
|
|
203
|
+
dimension: metadata?.dimension || 0,
|
|
204
|
+
count,
|
|
205
|
+
metric: this.HnswSpaceMap[hnswSpace]
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async deleteIndex(indexName) {
|
|
209
|
+
await this.client.deleteCollection({ name: indexName });
|
|
210
|
+
this.collections.delete(indexName);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
exports.ChromaVector = ChromaVector;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ChromaVector } from './_tsup-dts-rollup.cjs';
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
2
|
import { ChromaClient } from 'chromadb';
|
|
3
|
-
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
3
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
4
4
|
|
|
5
5
|
// src/vector/index.ts
|
|
6
6
|
var ChromaFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -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);
|
|
@@ -143,7 +145,9 @@ var ChromaVector = class extends MastraVector {
|
|
|
143
145
|
l2: "euclidean",
|
|
144
146
|
ip: "dotproduct"
|
|
145
147
|
};
|
|
146
|
-
async createIndex(
|
|
148
|
+
async createIndex(...args) {
|
|
149
|
+
const params = this.normalizeArgs("createIndex", args);
|
|
150
|
+
const { indexName, dimension, metric = "cosine" } = params;
|
|
147
151
|
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
148
152
|
throw new Error("Dimension must be a positive integer");
|
|
149
153
|
}
|
|
@@ -160,11 +164,12 @@ var ChromaVector = class extends MastraVector {
|
|
|
160
164
|
});
|
|
161
165
|
}
|
|
162
166
|
transformFilter(filter) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
return translatedFilter;
|
|
167
|
+
const translator = new ChromaFilterTranslator();
|
|
168
|
+
return translator.translate(filter);
|
|
166
169
|
}
|
|
167
|
-
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;
|
|
168
173
|
const collection = await this.getCollection(indexName, true);
|
|
169
174
|
const defaultInclude = ["documents", "metadatas", "distances"];
|
|
170
175
|
const translatedFilter = this.transformFilter(filter);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/chroma",
|
|
3
|
-
"version": "0.1.6-alpha.
|
|
3
|
+
"version": "0.1.6-alpha.4",
|
|
4
4
|
"description": "Chroma vector store provider for Mastra",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,13 +10,17 @@
|
|
|
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
|
},
|
|
17
21
|
"dependencies": {
|
|
18
22
|
"chromadb": "^1.9.4",
|
|
19
|
-
"@mastra/core": "^0.4.3-alpha.
|
|
23
|
+
"@mastra/core": "^0.4.3-alpha.4"
|
|
20
24
|
},
|
|
21
25
|
"devDependencies": {
|
|
22
26
|
"@microsoft/api-extractor": "^7.49.2",
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
"@internal/lint": "0.0.0"
|
|
29
33
|
},
|
|
30
34
|
"scripts": {
|
|
31
|
-
"build": "tsup src/index.ts --format esm --experimental-dts --clean --treeshake",
|
|
35
|
+
"build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake",
|
|
32
36
|
"build:watch": "pnpm build --watch",
|
|
33
37
|
"test": "vitest run",
|
|
34
38
|
"lint": "eslint ."
|
package/src/vector/filter.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
-
import type { FieldCondition,
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import type { FieldCondition, VectorFilter, OperatorSupport, QueryOperator } from '@mastra/core/vector/filter';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Translator for Chroma filter queries.
|
|
@@ -18,14 +18,14 @@ export class ChromaFilterTranslator extends BaseFilterTranslator {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
translate(filter?:
|
|
21
|
+
translate(filter?: VectorFilter): VectorFilter {
|
|
22
22
|
if (this.isEmpty(filter)) return filter;
|
|
23
|
-
this.validateFilter(filter
|
|
23
|
+
this.validateFilter(filter);
|
|
24
24
|
|
|
25
25
|
return this.translateNode(filter);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
private translateNode(node:
|
|
28
|
+
private translateNode(node: VectorFilter | FieldCondition, currentPath: string = ''): any {
|
|
29
29
|
// Handle primitive values and arrays
|
|
30
30
|
if (this.isRegex(node)) {
|
|
31
31
|
throw new Error('Regex is not supported in Chroma');
|