@mastra/vectorize 0.1.6-alpha.1 → 0.1.6-alpha.3
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 +25 -0
- package/README.md +36 -1
- package/dist/_tsup-dts-rollup.d.cts +43 -0
- package/dist/_tsup-dts-rollup.d.ts +12 -8
- package/dist/index.cjs +184 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.js +12 -7
- package/package.json +7 -3
- package/src/vector/filter.ts +5 -5
- package/src/vector/index.test.ts +345 -93
- package/src/vector/index.ts +26 -24
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/vectorize@0.1.6-alpha.
|
|
3
|
-
> tsup src/index.ts --format esm --experimental-dts --clean --treeshake
|
|
2
|
+
> @mastra/vectorize@0.1.6-alpha.3 build /home/runner/work/mastra/mastra/stores/vectorize
|
|
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 12974ms
|
|
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/vectorize/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/vectorize/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 17317ms
|
|
15
17
|
[34mCLI[39m Cleaning output folder
|
|
16
18
|
[34mESM[39m Build start
|
|
17
|
-
[
|
|
18
|
-
[
|
|
19
|
+
[34mCJS[39m Build start
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m5.68 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 465ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m5.48 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 465ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @mastra/vectorize
|
|
2
2
|
|
|
3
|
+
## 0.1.6-alpha.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0fd78ac: Update vector store functions to use object params
|
|
8
|
+
- fd14a3f: Updating filter location from @mastra/core/filter to @mastra/core/vector/filter
|
|
9
|
+
- c4fdac3: Updated tests for upstash and astra
|
|
10
|
+
- 4d4e1e1: Updated vector tests and pinecone
|
|
11
|
+
- bb4f447: Add support for commonjs
|
|
12
|
+
- Updated dependencies [0fd78ac]
|
|
13
|
+
- Updated dependencies [0d25b75]
|
|
14
|
+
- Updated dependencies [fd14a3f]
|
|
15
|
+
- Updated dependencies [3f369a2]
|
|
16
|
+
- Updated dependencies [4d4e1e1]
|
|
17
|
+
- Updated dependencies [bb4f447]
|
|
18
|
+
- @mastra/core@0.4.3-alpha.3
|
|
19
|
+
|
|
20
|
+
## 0.1.6-alpha.2
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies [2512a93]
|
|
25
|
+
- Updated dependencies [e62de74]
|
|
26
|
+
- @mastra/core@0.4.3-alpha.2
|
|
27
|
+
|
|
3
28
|
## 0.1.6-alpha.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -14,7 +14,33 @@ npm install @mastra/vectorize
|
|
|
14
14
|
import { VectorizeStore } from '@mastra/vectorize';
|
|
15
15
|
|
|
16
16
|
const vectorStore = new VectorizeStore({
|
|
17
|
-
|
|
17
|
+
apiKey: process.env.VECTORIZE_API_KEY,
|
|
18
|
+
projectId: process.env.VECTORIZE_PROJECT_ID
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Create a new index
|
|
22
|
+
await vectorStore.createIndex({
|
|
23
|
+
indexName: 'my-index',
|
|
24
|
+
dimension: 1536,
|
|
25
|
+
metric: 'cosine'
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Add vectors
|
|
29
|
+
const vectors = [[0.1, 0.2, ...], [0.3, 0.4, ...]];
|
|
30
|
+
const metadata = [{ text: 'doc1' }, { text: 'doc2' }];
|
|
31
|
+
const ids = await vectorStore.upsert({
|
|
32
|
+
indexName: 'my-index',
|
|
33
|
+
vectors,
|
|
34
|
+
metadata
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Query vectors
|
|
38
|
+
const results = await vectorStore.query({
|
|
39
|
+
indexName: 'my-index',
|
|
40
|
+
queryVector: [0.1, 0.2, ...],
|
|
41
|
+
topK: 10,
|
|
42
|
+
filter: { text: { $eq: 'doc1' } },
|
|
43
|
+
includeVector: false
|
|
18
44
|
});
|
|
19
45
|
```
|
|
20
46
|
|
|
@@ -34,6 +60,15 @@ The Vectorize vector store requires the following configuration:
|
|
|
34
60
|
- Scalable architecture
|
|
35
61
|
- Real-time updates and queries
|
|
36
62
|
|
|
63
|
+
## Methods
|
|
64
|
+
|
|
65
|
+
- `createIndex({ indexName, dimension, metric? })`: Create a new index
|
|
66
|
+
- `upsert({ indexName, vectors, metadata?, ids? })`: Add or update vectors
|
|
67
|
+
- `query({ indexName, queryVector, topK?, filter?, includeVector? })`: Search for similar vectors
|
|
68
|
+
- `listIndexes()`: List all indexes
|
|
69
|
+
- `describeIndex(indexName)`: Get index statistics
|
|
70
|
+
- `deleteIndex(indexName)`: Delete an index
|
|
71
|
+
|
|
37
72
|
## Related Links
|
|
38
73
|
|
|
39
74
|
- [Vectorize Documentation](https://www.vectorize.com/docs)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import Cloudflare from 'cloudflare';
|
|
3
|
+
import type { CreateIndexParams } 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
|
+
declare class CloudflareVector extends MastraVector {
|
|
13
|
+
client: Cloudflare;
|
|
14
|
+
accountId: string;
|
|
15
|
+
constructor({ accountId, apiToken }: {
|
|
16
|
+
accountId: string;
|
|
17
|
+
apiToken: string;
|
|
18
|
+
});
|
|
19
|
+
upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]>;
|
|
20
|
+
transformFilter(filter?: VectorFilter): VectorFilter;
|
|
21
|
+
createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
|
|
22
|
+
query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]>;
|
|
23
|
+
listIndexes(): Promise<string[]>;
|
|
24
|
+
describeIndex(indexName: string): Promise<{
|
|
25
|
+
dimension: number;
|
|
26
|
+
count: number;
|
|
27
|
+
metric: "cosine" | "euclidean" | "dotproduct";
|
|
28
|
+
}>;
|
|
29
|
+
deleteIndex(indexName: string): Promise<void>;
|
|
30
|
+
createMetadataIndex(indexName: string, propertyName: string, indexType: 'string' | 'number' | 'boolean'): Promise<void>;
|
|
31
|
+
deleteMetadataIndex(indexName: string, propertyName: string): Promise<void>;
|
|
32
|
+
listMetadataIndexes(indexName: string): Promise<Cloudflare.Vectorize.Indexes.MetadataIndex.MetadataIndexListResponse.MetadataIndex[]>;
|
|
33
|
+
}
|
|
34
|
+
export { CloudflareVector }
|
|
35
|
+
export { CloudflareVector as CloudflareVector_alias_1 }
|
|
36
|
+
|
|
37
|
+
export declare class VectorizeFilterTranslator extends BaseFilterTranslator {
|
|
38
|
+
protected getSupportedOperators(): OperatorSupport;
|
|
39
|
+
translate(filter?: VectorFilter): VectorFilter;
|
|
40
|
+
private translateNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { }
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
2
|
import Cloudflare from 'cloudflare';
|
|
3
|
-
import type {
|
|
3
|
+
import type { CreateIndexParams } 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
|
declare class CloudflareVector extends MastraVector {
|
|
9
13
|
client: Cloudflare;
|
|
@@ -12,10 +16,10 @@ declare class CloudflareVector extends MastraVector {
|
|
|
12
16
|
accountId: string;
|
|
13
17
|
apiToken: string;
|
|
14
18
|
});
|
|
15
|
-
upsert(
|
|
16
|
-
transformFilter(filter?:
|
|
17
|
-
createIndex(
|
|
18
|
-
query(
|
|
19
|
+
upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]>;
|
|
20
|
+
transformFilter(filter?: VectorFilter): VectorFilter;
|
|
21
|
+
createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void>;
|
|
22
|
+
query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]>;
|
|
19
23
|
listIndexes(): Promise<string[]>;
|
|
20
24
|
describeIndex(indexName: string): Promise<{
|
|
21
25
|
dimension: number;
|
|
@@ -32,7 +36,7 @@ export { CloudflareVector as CloudflareVector_alias_1 }
|
|
|
32
36
|
|
|
33
37
|
export declare class VectorizeFilterTranslator extends BaseFilterTranslator {
|
|
34
38
|
protected getSupportedOperators(): OperatorSupport;
|
|
35
|
-
translate(filter?:
|
|
39
|
+
translate(filter?: VectorFilter): VectorFilter;
|
|
36
40
|
private translateNode;
|
|
37
41
|
}
|
|
38
42
|
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var vector = require('@mastra/core/vector');
|
|
4
|
+
var Cloudflare = require('cloudflare');
|
|
5
|
+
var filter = require('@mastra/core/vector/filter');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
|
|
10
|
+
|
|
11
|
+
// src/vector/index.ts
|
|
12
|
+
var VectorizeFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
13
|
+
getSupportedOperators() {
|
|
14
|
+
return {
|
|
15
|
+
...filter.BaseFilterTranslator.DEFAULT_OPERATORS,
|
|
16
|
+
logical: [],
|
|
17
|
+
array: ["$in", "$nin"],
|
|
18
|
+
element: [],
|
|
19
|
+
regex: [],
|
|
20
|
+
custom: []
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
translate(filter) {
|
|
24
|
+
if (this.isEmpty(filter)) return filter;
|
|
25
|
+
this.validateFilter(filter);
|
|
26
|
+
return this.translateNode(filter);
|
|
27
|
+
}
|
|
28
|
+
translateNode(node, currentPath = "") {
|
|
29
|
+
if (this.isRegex(node)) {
|
|
30
|
+
throw new Error("Regex is not supported in Vectorize");
|
|
31
|
+
}
|
|
32
|
+
if (this.isPrimitive(node)) return { $eq: this.normalizeComparisonValue(node) };
|
|
33
|
+
if (Array.isArray(node)) return { $in: this.normalizeArrayValues(node) };
|
|
34
|
+
const entries = Object.entries(node);
|
|
35
|
+
const firstEntry = entries[0];
|
|
36
|
+
if (entries.length === 1 && firstEntry && this.isOperator(firstEntry[0])) {
|
|
37
|
+
const [operator, value] = firstEntry;
|
|
38
|
+
return { [operator]: this.normalizeComparisonValue(value) };
|
|
39
|
+
}
|
|
40
|
+
const result = {};
|
|
41
|
+
for (const [key, value] of entries) {
|
|
42
|
+
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
43
|
+
if (this.isOperator(key)) {
|
|
44
|
+
result[key] = this.normalizeComparisonValue(value);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
48
|
+
if (Object.keys(value).length === 0) {
|
|
49
|
+
result[newPath] = this.translateNode(value);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const hasOperators = Object.keys(value).some((k) => this.isOperator(k));
|
|
53
|
+
if (hasOperators) {
|
|
54
|
+
result[newPath] = this.translateNode(value);
|
|
55
|
+
} else {
|
|
56
|
+
Object.assign(result, this.translateNode(value, newPath));
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
result[newPath] = this.translateNode(value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/vector/index.ts
|
|
67
|
+
var CloudflareVector = class extends vector.MastraVector {
|
|
68
|
+
client;
|
|
69
|
+
accountId;
|
|
70
|
+
constructor({ accountId, apiToken }) {
|
|
71
|
+
super();
|
|
72
|
+
this.accountId = accountId;
|
|
73
|
+
this.client = new Cloudflare__default.default({
|
|
74
|
+
apiKey: apiToken
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async upsert(...args) {
|
|
78
|
+
const params = this.normalizeArgs("upsert", args);
|
|
79
|
+
const { indexName, vectors, metadata, ids } = params;
|
|
80
|
+
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
81
|
+
const ndjson = vectors.map(
|
|
82
|
+
(vector, index) => JSON.stringify({
|
|
83
|
+
id: generatedIds[index],
|
|
84
|
+
values: vector,
|
|
85
|
+
metadata: metadata?.[index]
|
|
86
|
+
})
|
|
87
|
+
).join("\n");
|
|
88
|
+
await this.client.vectorize.indexes.upsert(
|
|
89
|
+
indexName,
|
|
90
|
+
{
|
|
91
|
+
account_id: this.accountId,
|
|
92
|
+
body: ndjson
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
__binaryRequest: true
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
return generatedIds;
|
|
99
|
+
}
|
|
100
|
+
transformFilter(filter) {
|
|
101
|
+
const translator = new VectorizeFilterTranslator();
|
|
102
|
+
return translator.translate(filter);
|
|
103
|
+
}
|
|
104
|
+
async createIndex(...args) {
|
|
105
|
+
const params = this.normalizeArgs("createIndex", args);
|
|
106
|
+
const { indexName, dimension, metric = "cosine" } = params;
|
|
107
|
+
await this.client.vectorize.indexes.create({
|
|
108
|
+
account_id: this.accountId,
|
|
109
|
+
config: {
|
|
110
|
+
dimensions: dimension,
|
|
111
|
+
metric: metric === "dotproduct" ? "dot-product" : metric
|
|
112
|
+
},
|
|
113
|
+
name: indexName
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async query(...args) {
|
|
117
|
+
const params = this.normalizeArgs("query", args);
|
|
118
|
+
const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
|
|
119
|
+
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
120
|
+
const response = await this.client.vectorize.indexes.query(indexName, {
|
|
121
|
+
account_id: this.accountId,
|
|
122
|
+
vector: queryVector,
|
|
123
|
+
returnValues: includeVector,
|
|
124
|
+
returnMetadata: "all",
|
|
125
|
+
topK,
|
|
126
|
+
filter: translatedFilter
|
|
127
|
+
});
|
|
128
|
+
return response?.matches?.map((match) => {
|
|
129
|
+
return {
|
|
130
|
+
id: match.id,
|
|
131
|
+
metadata: match.metadata,
|
|
132
|
+
score: match.score,
|
|
133
|
+
vector: match.values
|
|
134
|
+
};
|
|
135
|
+
}) || [];
|
|
136
|
+
}
|
|
137
|
+
async listIndexes() {
|
|
138
|
+
const res = await this.client.vectorize.indexes.list({
|
|
139
|
+
account_id: this.accountId
|
|
140
|
+
});
|
|
141
|
+
return res?.result?.map((index) => index.name) || [];
|
|
142
|
+
}
|
|
143
|
+
async describeIndex(indexName) {
|
|
144
|
+
const index = await this.client.vectorize.indexes.get(indexName, {
|
|
145
|
+
account_id: this.accountId
|
|
146
|
+
});
|
|
147
|
+
const described = await this.client.vectorize.indexes.info(indexName, {
|
|
148
|
+
account_id: this.accountId
|
|
149
|
+
});
|
|
150
|
+
return {
|
|
151
|
+
dimension: described?.dimensions,
|
|
152
|
+
// Since vector_count is not available in the response,
|
|
153
|
+
// we might need a separate API call to get the count if needed
|
|
154
|
+
count: described?.vectorCount || 0,
|
|
155
|
+
metric: index?.config?.metric
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async deleteIndex(indexName) {
|
|
159
|
+
await this.client.vectorize.indexes.delete(indexName, {
|
|
160
|
+
account_id: this.accountId
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
async createMetadataIndex(indexName, propertyName, indexType) {
|
|
164
|
+
await this.client.vectorize.indexes.metadataIndex.create(indexName, {
|
|
165
|
+
account_id: this.accountId,
|
|
166
|
+
propertyName,
|
|
167
|
+
indexType
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async deleteMetadataIndex(indexName, propertyName) {
|
|
171
|
+
await this.client.vectorize.indexes.metadataIndex.delete(indexName, {
|
|
172
|
+
account_id: this.accountId,
|
|
173
|
+
propertyName
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
async listMetadataIndexes(indexName) {
|
|
177
|
+
const res = await this.client.vectorize.indexes.metadataIndex.list(indexName, {
|
|
178
|
+
account_id: this.accountId
|
|
179
|
+
});
|
|
180
|
+
return res?.metadataIndexes ?? [];
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
exports.CloudflareVector = CloudflareVector;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CloudflareVector } from './_tsup-dts-rollup.cjs';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
2
|
import Cloudflare from 'cloudflare';
|
|
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 VectorizeFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -68,7 +68,9 @@ var CloudflareVector = class extends MastraVector {
|
|
|
68
68
|
apiKey: apiToken
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
-
async upsert(
|
|
71
|
+
async upsert(...args) {
|
|
72
|
+
const params = this.normalizeArgs("upsert", args);
|
|
73
|
+
const { indexName, vectors, metadata, ids } = params;
|
|
72
74
|
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
73
75
|
const ndjson = vectors.map(
|
|
74
76
|
(vector, index) => JSON.stringify({
|
|
@@ -91,10 +93,11 @@ var CloudflareVector = class extends MastraVector {
|
|
|
91
93
|
}
|
|
92
94
|
transformFilter(filter) {
|
|
93
95
|
const translator = new VectorizeFilterTranslator();
|
|
94
|
-
|
|
95
|
-
return translatedFilter;
|
|
96
|
+
return translator.translate(filter);
|
|
96
97
|
}
|
|
97
|
-
async createIndex(
|
|
98
|
+
async createIndex(...args) {
|
|
99
|
+
const params = this.normalizeArgs("createIndex", args);
|
|
100
|
+
const { indexName, dimension, metric = "cosine" } = params;
|
|
98
101
|
await this.client.vectorize.indexes.create({
|
|
99
102
|
account_id: this.accountId,
|
|
100
103
|
config: {
|
|
@@ -104,8 +107,10 @@ var CloudflareVector = class extends MastraVector {
|
|
|
104
107
|
name: indexName
|
|
105
108
|
});
|
|
106
109
|
}
|
|
107
|
-
async query(
|
|
108
|
-
const
|
|
110
|
+
async query(...args) {
|
|
111
|
+
const params = this.normalizeArgs("query", args);
|
|
112
|
+
const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
|
|
113
|
+
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
109
114
|
const response = await this.client.vectorize.indexes.query(indexName, {
|
|
110
115
|
account_id: this.accountId,
|
|
111
116
|
vector: queryVector,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/vectorize",
|
|
3
|
-
"version": "0.1.6-alpha.
|
|
3
|
+
"version": "0.1.6-alpha.3",
|
|
4
4
|
"description": "Cloudflare Vectorize 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
|
"cloudflare": "^4.0.0",
|
|
19
|
-
"@mastra/core": "^0.4.3-alpha.
|
|
23
|
+
"@mastra/core": "^0.4.3-alpha.3"
|
|
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 {
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
2
|
+
import type { VectorFilter, FieldCondition, OperatorSupport } from '@mastra/core/vector/filter';
|
|
3
3
|
|
|
4
4
|
export class VectorizeFilterTranslator extends BaseFilterTranslator {
|
|
5
5
|
protected override getSupportedOperators(): OperatorSupport {
|
|
@@ -13,13 +13,13 @@ export class VectorizeFilterTranslator extends BaseFilterTranslator {
|
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
translate(filter?:
|
|
16
|
+
translate(filter?: VectorFilter): VectorFilter {
|
|
17
17
|
if (this.isEmpty(filter)) return filter;
|
|
18
|
-
this.validateFilter(filter
|
|
18
|
+
this.validateFilter(filter);
|
|
19
19
|
return this.translateNode(filter);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
private translateNode(node:
|
|
22
|
+
private translateNode(node: VectorFilter | FieldCondition, currentPath: string = ''): any {
|
|
23
23
|
if (this.isRegex(node)) {
|
|
24
24
|
throw new Error('Regex is not supported in Vectorize');
|
|
25
25
|
}
|
package/src/vector/index.test.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach, vi, afterEach } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { CloudflareVector } from './';
|
|
5
5
|
|
|
6
|
+
vi.setConfig({ testTimeout: 80_000, hookTimeout: 80_000 });
|
|
7
|
+
|
|
6
8
|
function waitUntilReady(vector: CloudflareVector, indexName: string) {
|
|
7
9
|
return new Promise(resolve => {
|
|
8
10
|
const interval = setInterval(async () => {
|
|
@@ -106,7 +108,7 @@ describe('CloudflareVector', () => {
|
|
|
106
108
|
const tempIndexName = 'test_temp_index';
|
|
107
109
|
|
|
108
110
|
it('should create and list indexes', async () => {
|
|
109
|
-
await vectorDB.createIndex(tempIndexName, VECTOR_DIMENSION, 'cosine');
|
|
111
|
+
await vectorDB.createIndex({ indexName: tempIndexName, dimension: VECTOR_DIMENSION, metric: 'cosine' });
|
|
110
112
|
await waitUntilReady(vectorDB, tempIndexName);
|
|
111
113
|
const indexes = await vectorDB.listIndexes();
|
|
112
114
|
expect(indexes).toContain(tempIndexName);
|
|
@@ -131,7 +133,7 @@ describe('CloudflareVector', () => {
|
|
|
131
133
|
describe('Vector Operations', () => {
|
|
132
134
|
let vectorIds: string[];
|
|
133
135
|
it('should create index before operations', async () => {
|
|
134
|
-
await vectorDB.createIndex(testIndexName, VECTOR_DIMENSION, 'cosine');
|
|
136
|
+
await vectorDB.createIndex({ indexName: testIndexName, dimension: VECTOR_DIMENSION, metric: 'cosine' });
|
|
135
137
|
await waitUntilReady(vectorDB, testIndexName);
|
|
136
138
|
const indexes = await vectorDB.listIndexes();
|
|
137
139
|
expect(indexes).toContain(testIndexName);
|
|
@@ -142,14 +144,14 @@ describe('CloudflareVector', () => {
|
|
|
142
144
|
|
|
143
145
|
const testMetadata = [{ label: 'first-dimension' }, { label: 'second-dimension' }, { label: 'third-dimension' }];
|
|
144
146
|
|
|
145
|
-
vectorIds = await vectorDB.upsert(testIndexName, testVectors, testMetadata);
|
|
147
|
+
vectorIds = await vectorDB.upsert({ indexName: testIndexName, vectors: testVectors, metadata: testMetadata });
|
|
146
148
|
expect(vectorIds).toHaveLength(3);
|
|
147
149
|
|
|
148
150
|
await waitUntilVectorsIndexed(vectorDB, testIndexName, 3);
|
|
149
151
|
const stats = await vectorDB.describeIndex(testIndexName);
|
|
150
152
|
expect(stats.count).toBeGreaterThan(0);
|
|
151
153
|
|
|
152
|
-
const results = await vectorDB.query(testIndexName, createVector(0, 0.9), 3);
|
|
154
|
+
const results = await vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 3 });
|
|
153
155
|
expect(results).toHaveLength(3);
|
|
154
156
|
|
|
155
157
|
if (results.length > 0) {
|
|
@@ -158,7 +160,12 @@ describe('CloudflareVector', () => {
|
|
|
158
160
|
}, 30000);
|
|
159
161
|
|
|
160
162
|
it('should query vectors and return vector in results', async () => {
|
|
161
|
-
const results = await vectorDB.query(
|
|
163
|
+
const results = await vectorDB.query({
|
|
164
|
+
indexName: testIndexName,
|
|
165
|
+
queryVector: createVector(0, 0.9),
|
|
166
|
+
topK: 3,
|
|
167
|
+
includeVector: true,
|
|
168
|
+
});
|
|
162
169
|
|
|
163
170
|
expect(results).toHaveLength(3);
|
|
164
171
|
|
|
@@ -171,23 +178,27 @@ describe('CloudflareVector', () => {
|
|
|
171
178
|
|
|
172
179
|
describe('Error Handling', () => {
|
|
173
180
|
it('should handle invalid dimension vectors', async () => {
|
|
174
|
-
await expect(vectorDB.upsert(testIndexName, [[1.0, 0.0]])).rejects.toThrow();
|
|
181
|
+
await expect(vectorDB.upsert({ indexName: testIndexName, vectors: [[1.0, 0.0]] })).rejects.toThrow();
|
|
175
182
|
});
|
|
176
183
|
|
|
177
184
|
it('should handle querying with wrong dimensions', async () => {
|
|
178
|
-
await expect(vectorDB.query(testIndexName, [1.0, 0.0])).rejects.toThrow();
|
|
185
|
+
await expect(vectorDB.query({ indexName: testIndexName, queryVector: [1.0, 0.0] })).rejects.toThrow();
|
|
179
186
|
});
|
|
180
187
|
|
|
181
188
|
it('should handle non-existent index operations', async () => {
|
|
182
189
|
const nonExistentIndex = 'non_existent_index';
|
|
183
|
-
await expect(
|
|
190
|
+
await expect(
|
|
191
|
+
vectorDB.query({ indexName: nonExistentIndex, queryVector: createVector(0, 1.0) }),
|
|
192
|
+
).rejects.toThrow();
|
|
184
193
|
});
|
|
185
194
|
|
|
186
195
|
it('rejects queries with filter keys longer than 512 characters', async () => {
|
|
187
196
|
const longKey = 'a'.repeat(513);
|
|
188
197
|
const filter = { [longKey]: 'value' };
|
|
189
198
|
|
|
190
|
-
await expect(
|
|
199
|
+
await expect(
|
|
200
|
+
vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
|
|
201
|
+
).rejects.toThrow();
|
|
191
202
|
});
|
|
192
203
|
|
|
193
204
|
it('rejects queries with filter keys containing invalid characters', async () => {
|
|
@@ -198,7 +209,9 @@ describe('CloudflareVector', () => {
|
|
|
198
209
|
];
|
|
199
210
|
|
|
200
211
|
for (const filter of invalidFilters) {
|
|
201
|
-
await expect(
|
|
212
|
+
await expect(
|
|
213
|
+
vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
|
|
214
|
+
).rejects.toThrow();
|
|
202
215
|
}
|
|
203
216
|
});
|
|
204
217
|
|
|
@@ -210,13 +223,17 @@ describe('CloudflareVector', () => {
|
|
|
210
223
|
];
|
|
211
224
|
|
|
212
225
|
for (const filter of validFilters) {
|
|
213
|
-
await expect(
|
|
226
|
+
await expect(
|
|
227
|
+
vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter }),
|
|
228
|
+
).resolves.not.toThrow();
|
|
214
229
|
}
|
|
215
230
|
});
|
|
216
231
|
|
|
217
232
|
it('rejects queries with empty object field values', async () => {
|
|
218
233
|
const emptyFilters = { field: {} };
|
|
219
|
-
await expect(
|
|
234
|
+
await expect(
|
|
235
|
+
vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter: emptyFilters }),
|
|
236
|
+
).rejects.toThrow();
|
|
220
237
|
});
|
|
221
238
|
|
|
222
239
|
it('rejects oversized filter queries', async () => {
|
|
@@ -225,19 +242,27 @@ describe('CloudflareVector', () => {
|
|
|
225
242
|
field2: { $in: Array(1000).fill(123) },
|
|
226
243
|
};
|
|
227
244
|
|
|
228
|
-
await expect(
|
|
245
|
+
await expect(
|
|
246
|
+
vectorDB.query({ indexName: testIndexName, queryVector: createVector(0, 0.9), topK: 10, filter: largeFilter }),
|
|
247
|
+
).rejects.toThrow();
|
|
229
248
|
});
|
|
230
249
|
|
|
231
250
|
it('rejects queries with array values in comparison operators', async () => {
|
|
232
251
|
await expect(
|
|
233
|
-
vectorDB.query(
|
|
234
|
-
|
|
252
|
+
vectorDB.query({
|
|
253
|
+
indexName: testIndexName,
|
|
254
|
+
queryVector: createVector(0, 0.9),
|
|
255
|
+
topK: 10,
|
|
256
|
+
filter: { field: { $gt: [] } },
|
|
235
257
|
}),
|
|
236
258
|
).rejects.toThrow();
|
|
237
259
|
|
|
238
260
|
await expect(
|
|
239
|
-
vectorDB.query(
|
|
240
|
-
|
|
261
|
+
vectorDB.query({
|
|
262
|
+
indexName: testIndexName,
|
|
263
|
+
queryVector: createVector(0, 0.9),
|
|
264
|
+
topK: 10,
|
|
265
|
+
filter: { field: { $lt: [1, 2, 3] } },
|
|
241
266
|
}),
|
|
242
267
|
).rejects.toThrow();
|
|
243
268
|
});
|
|
@@ -245,7 +270,7 @@ describe('CloudflareVector', () => {
|
|
|
245
270
|
|
|
246
271
|
describe('Metadata Filter Tests', () => {
|
|
247
272
|
beforeAll(async () => {
|
|
248
|
-
await vectorDB.createIndex(testIndexName2, VECTOR_DIMENSION, 'cosine');
|
|
273
|
+
await vectorDB.createIndex({ indexName: testIndexName2, dimension: VECTOR_DIMENSION, metric: 'cosine' });
|
|
249
274
|
await waitUntilReady(vectorDB, testIndexName2);
|
|
250
275
|
|
|
251
276
|
await vectorDB.createMetadataIndex(testIndexName2, 'price', 'number');
|
|
@@ -327,12 +352,12 @@ describe('CloudflareVector', () => {
|
|
|
327
352
|
},
|
|
328
353
|
];
|
|
329
354
|
|
|
330
|
-
await vectorDB.upsert(testIndexName2, vectors, metadata);
|
|
355
|
+
await vectorDB.upsert({ indexName: testIndexName2, vectors, metadata });
|
|
331
356
|
await waitUntilVectorsIndexed(vectorDB, testIndexName2, vectors.length);
|
|
332
357
|
|
|
333
358
|
const stats = await vectorDB.describeIndex(testIndexName2);
|
|
334
359
|
expect(stats.count).toBe(vectors.length);
|
|
335
|
-
},
|
|
360
|
+
}, 800000);
|
|
336
361
|
|
|
337
362
|
afterAll(async () => {
|
|
338
363
|
const currentMetadata = await vectorDB.listMetadataIndexes(testIndexName2);
|
|
@@ -340,12 +365,14 @@ describe('CloudflareVector', () => {
|
|
|
340
365
|
await vectorDB.deleteMetadataIndex(testIndexName2, propertyName as string);
|
|
341
366
|
}
|
|
342
367
|
await vectorDB.deleteIndex(testIndexName2);
|
|
343
|
-
},
|
|
368
|
+
}, 800000);
|
|
344
369
|
|
|
345
370
|
describe('Basic Equality Operators', () => {
|
|
346
371
|
it('filters with $eq operator', async () => {
|
|
347
|
-
const results = await vectorDB.query(
|
|
348
|
-
|
|
372
|
+
const results = await vectorDB.query({
|
|
373
|
+
indexName: testIndexName2,
|
|
374
|
+
queryVector: createVector(0, 1.0),
|
|
375
|
+
filter: { category: 'electronics' },
|
|
349
376
|
});
|
|
350
377
|
expect(results.length).toBe(2);
|
|
351
378
|
results.forEach(result => {
|
|
@@ -354,8 +381,10 @@ describe('CloudflareVector', () => {
|
|
|
354
381
|
});
|
|
355
382
|
|
|
356
383
|
it('filters with $ne operator', async () => {
|
|
357
|
-
const results = await vectorDB.query(
|
|
358
|
-
|
|
384
|
+
const results = await vectorDB.query({
|
|
385
|
+
indexName: testIndexName2,
|
|
386
|
+
queryVector: createVector(0, 1.0),
|
|
387
|
+
filter: { category: { $ne: 'electronics' } },
|
|
359
388
|
});
|
|
360
389
|
expect(results.length).toBe(2);
|
|
361
390
|
results.forEach(result => {
|
|
@@ -366,8 +395,10 @@ describe('CloudflareVector', () => {
|
|
|
366
395
|
|
|
367
396
|
describe('Numeric Comparison Operators', () => {
|
|
368
397
|
it('filters with $gt operator', async () => {
|
|
369
|
-
const results = await vectorDB.query(
|
|
370
|
-
|
|
398
|
+
const results = await vectorDB.query({
|
|
399
|
+
indexName: testIndexName2,
|
|
400
|
+
queryVector: createVector(0, 1.0),
|
|
401
|
+
filter: { price: { $gt: 150 } },
|
|
371
402
|
});
|
|
372
403
|
expect(results.length).toBe(1);
|
|
373
404
|
results.forEach(result => {
|
|
@@ -376,8 +407,10 @@ describe('CloudflareVector', () => {
|
|
|
376
407
|
});
|
|
377
408
|
|
|
378
409
|
it('filters with $gte operator', async () => {
|
|
379
|
-
const results = await vectorDB.query(
|
|
380
|
-
|
|
410
|
+
const results = await vectorDB.query({
|
|
411
|
+
indexName: testIndexName2,
|
|
412
|
+
queryVector: createVector(0, 1.0),
|
|
413
|
+
filter: { price: { $gte: 100 } },
|
|
381
414
|
});
|
|
382
415
|
expect(results.length).toBe(3);
|
|
383
416
|
results.forEach(result => {
|
|
@@ -387,8 +420,10 @@ describe('CloudflareVector', () => {
|
|
|
387
420
|
});
|
|
388
421
|
|
|
389
422
|
it('filters with $lt operator', async () => {
|
|
390
|
-
const results = await vectorDB.query(
|
|
391
|
-
|
|
423
|
+
const results = await vectorDB.query({
|
|
424
|
+
indexName: testIndexName2,
|
|
425
|
+
queryVector: createVector(0, 1.0),
|
|
426
|
+
filter: { price: { $lt: 150 } },
|
|
392
427
|
});
|
|
393
428
|
expect(results.length).toBe(2);
|
|
394
429
|
results.forEach(result => {
|
|
@@ -398,8 +433,10 @@ describe('CloudflareVector', () => {
|
|
|
398
433
|
});
|
|
399
434
|
|
|
400
435
|
it('filters with $lte operator', async () => {
|
|
401
|
-
const results = await vectorDB.query(
|
|
402
|
-
|
|
436
|
+
const results = await vectorDB.query({
|
|
437
|
+
indexName: testIndexName2,
|
|
438
|
+
queryVector: createVector(0, 1.0),
|
|
439
|
+
filter: { price: { $lte: 150 } },
|
|
403
440
|
});
|
|
404
441
|
expect(results.length).toBe(3);
|
|
405
442
|
results.forEach(result => {
|
|
@@ -411,8 +448,10 @@ describe('CloudflareVector', () => {
|
|
|
411
448
|
|
|
412
449
|
describe('Array Operators', () => {
|
|
413
450
|
it('filters with $in operator for exact matches', async () => {
|
|
414
|
-
const results = await vectorDB.query(
|
|
415
|
-
|
|
451
|
+
const results = await vectorDB.query({
|
|
452
|
+
indexName: testIndexName2,
|
|
453
|
+
queryVector: createVector(0, 1.0),
|
|
454
|
+
filter: { category: { $in: ['electronics'] } },
|
|
416
455
|
});
|
|
417
456
|
expect(results.length).toBe(2);
|
|
418
457
|
results.forEach(result => {
|
|
@@ -421,8 +460,10 @@ describe('CloudflareVector', () => {
|
|
|
421
460
|
});
|
|
422
461
|
|
|
423
462
|
it('filters with $nin operator', async () => {
|
|
424
|
-
const results = await vectorDB.query(
|
|
425
|
-
|
|
463
|
+
const results = await vectorDB.query({
|
|
464
|
+
indexName: testIndexName2,
|
|
465
|
+
queryVector: createVector(0, 1.0),
|
|
466
|
+
filter: { category: { $nin: ['electronics'] } },
|
|
426
467
|
});
|
|
427
468
|
expect(results.length).toBe(2);
|
|
428
469
|
results.forEach(result => {
|
|
@@ -433,16 +474,20 @@ describe('CloudflareVector', () => {
|
|
|
433
474
|
|
|
434
475
|
describe('Boolean Operations', () => {
|
|
435
476
|
it('filters with boolean values', async () => {
|
|
436
|
-
const results = await vectorDB.query(
|
|
437
|
-
|
|
477
|
+
const results = await vectorDB.query({
|
|
478
|
+
indexName: testIndexName2,
|
|
479
|
+
queryVector: createVector(0, 1.0),
|
|
480
|
+
filter: { isActive: true },
|
|
438
481
|
});
|
|
439
482
|
expect(results.length).toBe(1);
|
|
440
483
|
expect(results[0]?.metadata?.isActive).toBe(true);
|
|
441
484
|
}, 5000);
|
|
442
485
|
|
|
443
486
|
it('filters with $ne on boolean values', async () => {
|
|
444
|
-
const results = await vectorDB.query(
|
|
445
|
-
|
|
487
|
+
const results = await vectorDB.query({
|
|
488
|
+
indexName: testIndexName2,
|
|
489
|
+
queryVector: createVector(0, 1.0),
|
|
490
|
+
filter: { isActive: { $ne: true } },
|
|
446
491
|
});
|
|
447
492
|
expect(results.length).toBe(3);
|
|
448
493
|
results.forEach(result => {
|
|
@@ -453,8 +498,10 @@ describe('CloudflareVector', () => {
|
|
|
453
498
|
|
|
454
499
|
describe('Nested Field Operations', () => {
|
|
455
500
|
it('filters on nested fields with comparison operators', async () => {
|
|
456
|
-
const results = await vectorDB.query(
|
|
457
|
-
|
|
501
|
+
const results = await vectorDB.query({
|
|
502
|
+
indexName: testIndexName2,
|
|
503
|
+
queryVector: createVector(0, 1.0),
|
|
504
|
+
filter: { 'nested.number': { $gt: 100 } },
|
|
458
505
|
});
|
|
459
506
|
expect(results.length).toBe(2);
|
|
460
507
|
results.forEach(result => {
|
|
@@ -463,9 +510,10 @@ describe('CloudflareVector', () => {
|
|
|
463
510
|
});
|
|
464
511
|
|
|
465
512
|
it('combines nested field filters with top-level filters', async () => {
|
|
466
|
-
const results = await vectorDB.query(
|
|
467
|
-
|
|
468
|
-
|
|
513
|
+
const results = await vectorDB.query({
|
|
514
|
+
indexName: testIndexName2,
|
|
515
|
+
queryVector: createVector(0, 1.0),
|
|
516
|
+
filter: { 'nested.number': { $lt: 200 }, category: 'electronics' },
|
|
469
517
|
});
|
|
470
518
|
expect(results.length).toBe(1);
|
|
471
519
|
expect(results[0]?.metadata?.nested?.number).toBeLessThan(200);
|
|
@@ -473,8 +521,10 @@ describe('CloudflareVector', () => {
|
|
|
473
521
|
});
|
|
474
522
|
|
|
475
523
|
it('handles nested string equality', async () => {
|
|
476
|
-
const results = await vectorDB.query(
|
|
477
|
-
|
|
524
|
+
const results = await vectorDB.query({
|
|
525
|
+
indexName: testIndexName2,
|
|
526
|
+
queryVector: createVector(0, 1.0),
|
|
527
|
+
filter: { 'nested.string': 'premium' },
|
|
478
528
|
});
|
|
479
529
|
expect(results.length).toBe(3);
|
|
480
530
|
results.forEach(result => {
|
|
@@ -483,9 +533,10 @@ describe('CloudflareVector', () => {
|
|
|
483
533
|
}, 10000);
|
|
484
534
|
|
|
485
535
|
it('combines nested numeric and boolean conditions', async () => {
|
|
486
|
-
const results = await vectorDB.query(
|
|
487
|
-
|
|
488
|
-
|
|
536
|
+
const results = await vectorDB.query({
|
|
537
|
+
indexName: testIndexName2,
|
|
538
|
+
queryVector: createVector(0, 1.0),
|
|
539
|
+
filter: { 'nested.number': { $gt: 100 }, 'nested.boolean': true },
|
|
489
540
|
});
|
|
490
541
|
expect(results.length).toBe(1);
|
|
491
542
|
expect(results[0]?.metadata?.nested?.number).toBeGreaterThan(100);
|
|
@@ -493,10 +544,10 @@ describe('CloudflareVector', () => {
|
|
|
493
544
|
}, 10000);
|
|
494
545
|
|
|
495
546
|
it('handles multiple nested field comparisons', async () => {
|
|
496
|
-
const results = await vectorDB.query(
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
'nested.boolean': true,
|
|
547
|
+
const results = await vectorDB.query({
|
|
548
|
+
indexName: testIndexName2,
|
|
549
|
+
queryVector: createVector(0, 1.0),
|
|
550
|
+
filter: { 'nested.string': 'premium', 'nested.number': { $lt: 200 }, 'nested.boolean': true },
|
|
500
551
|
});
|
|
501
552
|
expect(results.length).toBe(2);
|
|
502
553
|
const result = results[0]?.metadata?.nested;
|
|
@@ -506,8 +557,10 @@ describe('CloudflareVector', () => {
|
|
|
506
557
|
}, 10000);
|
|
507
558
|
|
|
508
559
|
it('handles $in with nested string values', async () => {
|
|
509
|
-
const results = await vectorDB.query(
|
|
510
|
-
|
|
560
|
+
const results = await vectorDB.query({
|
|
561
|
+
indexName: testIndexName2,
|
|
562
|
+
queryVector: createVector(0, 1.0),
|
|
563
|
+
filter: { 'nested.string': { $in: ['premium', 'basic'] } },
|
|
511
564
|
});
|
|
512
565
|
expect(results.length).toBe(4);
|
|
513
566
|
results.forEach(result => {
|
|
@@ -518,17 +571,20 @@ describe('CloudflareVector', () => {
|
|
|
518
571
|
|
|
519
572
|
describe('String Operations', () => {
|
|
520
573
|
it('handles string numbers in numeric comparisons', async () => {
|
|
521
|
-
const results = await vectorDB.query(
|
|
522
|
-
|
|
574
|
+
const results = await vectorDB.query({
|
|
575
|
+
indexName: testIndexName2,
|
|
576
|
+
queryVector: createVector(0, 1.0),
|
|
577
|
+
filter: { price: { $gt: '150' } }, // String number
|
|
523
578
|
});
|
|
524
579
|
expect(results.length).toBe(1);
|
|
525
580
|
expect(Number(results[0]?.metadata?.price)).toBeGreaterThan(150);
|
|
526
581
|
});
|
|
527
582
|
|
|
528
583
|
it('handles mixed numeric and string comparisons', async () => {
|
|
529
|
-
const results = await vectorDB.query(
|
|
530
|
-
|
|
531
|
-
|
|
584
|
+
const results = await vectorDB.query({
|
|
585
|
+
indexName: testIndexName2,
|
|
586
|
+
queryVector: createVector(0, 1.0),
|
|
587
|
+
filter: { price: { $gt: 100 }, category: { $in: ['electronics'] } },
|
|
532
588
|
});
|
|
533
589
|
expect(results.length).toBe(1);
|
|
534
590
|
expect(Number(results[0]?.metadata?.price)).toBeGreaterThan(100);
|
|
@@ -538,16 +594,20 @@ describe('CloudflareVector', () => {
|
|
|
538
594
|
|
|
539
595
|
describe('Filter Validation and Edge Cases', () => {
|
|
540
596
|
it('handles numeric zero values correctly', async () => {
|
|
541
|
-
const results = await vectorDB.query(
|
|
542
|
-
|
|
597
|
+
const results = await vectorDB.query({
|
|
598
|
+
indexName: testIndexName2,
|
|
599
|
+
queryVector: createVector(0, 1.0),
|
|
600
|
+
filter: { rating: { $eq: 0 } },
|
|
543
601
|
});
|
|
544
602
|
expect(results.length).toBe(1);
|
|
545
603
|
expect(results[0]?.metadata?.rating).toBe(0);
|
|
546
604
|
});
|
|
547
605
|
|
|
548
606
|
it('handles multiple conditions on same field', async () => {
|
|
549
|
-
const results = await vectorDB.query(
|
|
550
|
-
|
|
607
|
+
const results = await vectorDB.query({
|
|
608
|
+
indexName: testIndexName2,
|
|
609
|
+
queryVector: createVector(0, 1.0),
|
|
610
|
+
filter: { price: { $gt: 75, $lt: 200 } },
|
|
551
611
|
});
|
|
552
612
|
expect(results.length).toBe(2);
|
|
553
613
|
results.forEach(result => {
|
|
@@ -558,16 +618,20 @@ describe('CloudflareVector', () => {
|
|
|
558
618
|
});
|
|
559
619
|
|
|
560
620
|
it('handles exact numeric equality', async () => {
|
|
561
|
-
const results = await vectorDB.query(
|
|
562
|
-
|
|
621
|
+
const results = await vectorDB.query({
|
|
622
|
+
indexName: testIndexName2,
|
|
623
|
+
queryVector: createVector(0, 1.0),
|
|
624
|
+
filter: { price: { $eq: 100 } },
|
|
563
625
|
});
|
|
564
626
|
expect(results.length).toBe(1);
|
|
565
627
|
expect(results[0]?.metadata?.price).toBe(100);
|
|
566
628
|
});
|
|
567
629
|
|
|
568
630
|
it('handles boundary conditions in ranges', async () => {
|
|
569
|
-
const results = await vectorDB.query(
|
|
570
|
-
|
|
631
|
+
const results = await vectorDB.query({
|
|
632
|
+
indexName: testIndexName2,
|
|
633
|
+
queryVector: createVector(0, 1.0),
|
|
634
|
+
filter: { price: { $gte: 75, $lte: 75 } },
|
|
571
635
|
});
|
|
572
636
|
expect(results.length).toBe(1);
|
|
573
637
|
expect(results[0]?.metadata?.price).toBe(75);
|
|
@@ -576,16 +640,20 @@ describe('CloudflareVector', () => {
|
|
|
576
640
|
|
|
577
641
|
describe('String Range Queries', () => {
|
|
578
642
|
it('handles lexicographical ordering in string range queries', async () => {
|
|
579
|
-
const results = await vectorDB.query(
|
|
580
|
-
|
|
643
|
+
const results = await vectorDB.query({
|
|
644
|
+
indexName: testIndexName2,
|
|
645
|
+
queryVector: createVector(0, 1.0),
|
|
646
|
+
filter: { code: { $gt: 'A123', $lt: 'C789' } },
|
|
581
647
|
});
|
|
582
648
|
expect(results.length).toBe(1);
|
|
583
649
|
expect(results[0]?.metadata?.code).toBe('B456');
|
|
584
650
|
}, 5000);
|
|
585
651
|
|
|
586
652
|
it('handles string range queries with special characters', async () => {
|
|
587
|
-
const results = await vectorDB.query(
|
|
588
|
-
|
|
653
|
+
const results = await vectorDB.query({
|
|
654
|
+
indexName: testIndexName2,
|
|
655
|
+
queryVector: createVector(0, 1.0),
|
|
656
|
+
filter: { code: { $gte: 'A', $lt: 'C' } },
|
|
589
657
|
});
|
|
590
658
|
expect(results.length).toBe(2);
|
|
591
659
|
results.forEach(result => {
|
|
@@ -596,15 +664,19 @@ describe('CloudflareVector', () => {
|
|
|
596
664
|
|
|
597
665
|
describe('Null and Special Values', () => {
|
|
598
666
|
it('handles $in with null values', async () => {
|
|
599
|
-
const results = await vectorDB.query(
|
|
600
|
-
|
|
667
|
+
const results = await vectorDB.query({
|
|
668
|
+
indexName: testIndexName2,
|
|
669
|
+
queryVector: createVector(0, 1.0),
|
|
670
|
+
filter: { optionalField: { $in: [null, 'exists'] } },
|
|
601
671
|
});
|
|
602
672
|
expect(results.length).toBe(1);
|
|
603
673
|
}, 5000);
|
|
604
674
|
|
|
605
675
|
it('handles $ne with null values', async () => {
|
|
606
|
-
const results = await vectorDB.query(
|
|
607
|
-
|
|
676
|
+
const results = await vectorDB.query({
|
|
677
|
+
indexName: testIndexName2,
|
|
678
|
+
queryVector: createVector(0, 1.0),
|
|
679
|
+
filter: { optionalField: { $ne: null } },
|
|
608
680
|
});
|
|
609
681
|
expect(results.length).toBe(4);
|
|
610
682
|
expect(results[0]?.metadata?.optionalField).toBe('exists');
|
|
@@ -613,16 +685,19 @@ describe('CloudflareVector', () => {
|
|
|
613
685
|
|
|
614
686
|
describe('Mixed Type Arrays and Values', () => {
|
|
615
687
|
it('handles $in with mixed type arrays', async () => {
|
|
616
|
-
const results = await vectorDB.query(
|
|
617
|
-
|
|
688
|
+
const results = await vectorDB.query({
|
|
689
|
+
indexName: testIndexName2,
|
|
690
|
+
queryVector: createVector(0, 1.0),
|
|
691
|
+
filter: { mixedField: { $in: ['string value', 10, null] } },
|
|
618
692
|
});
|
|
619
693
|
expect(results.length).toBe(2);
|
|
620
694
|
}, 5000);
|
|
621
695
|
|
|
622
696
|
it('combines different types of filters', async () => {
|
|
623
|
-
const results = await vectorDB.query(
|
|
624
|
-
|
|
625
|
-
|
|
697
|
+
const results = await vectorDB.query({
|
|
698
|
+
indexName: testIndexName2,
|
|
699
|
+
queryVector: createVector(0, 1.0),
|
|
700
|
+
filter: { mixedField: { $in: ['string value', true] }, price: { $eq: 100 } },
|
|
626
701
|
});
|
|
627
702
|
expect(results.length).toBe(1);
|
|
628
703
|
}, 5000);
|
|
@@ -638,7 +713,13 @@ describe('CloudflareVector', () => {
|
|
|
638
713
|
'nested.string': longString.slice(0, 200),
|
|
639
714
|
};
|
|
640
715
|
|
|
641
|
-
await expect(
|
|
716
|
+
await expect(
|
|
717
|
+
vectorDB.query({
|
|
718
|
+
indexName: testIndexName2,
|
|
719
|
+
queryVector: createVector(0, 1.0),
|
|
720
|
+
filter,
|
|
721
|
+
}),
|
|
722
|
+
).resolves.toBeDefined();
|
|
642
723
|
}, 5000);
|
|
643
724
|
|
|
644
725
|
it('handles valid range query combinations', async () => {
|
|
@@ -650,30 +731,201 @@ describe('CloudflareVector', () => {
|
|
|
650
731
|
];
|
|
651
732
|
|
|
652
733
|
for (const filter of validRangeCombinations) {
|
|
653
|
-
await expect(
|
|
734
|
+
await expect(
|
|
735
|
+
vectorDB.query({
|
|
736
|
+
indexName: testIndexName2,
|
|
737
|
+
queryVector: createVector(0, 1.0),
|
|
738
|
+
filter,
|
|
739
|
+
}),
|
|
740
|
+
).resolves.toBeDefined();
|
|
654
741
|
}
|
|
655
742
|
}, 5000);
|
|
656
743
|
|
|
657
744
|
it('should handle undefined filter', async () => {
|
|
658
|
-
const results1 = await vectorDB.query(
|
|
659
|
-
|
|
745
|
+
const results1 = await vectorDB.query({
|
|
746
|
+
indexName: testIndexName2,
|
|
747
|
+
queryVector: createVector(0, 1.0),
|
|
748
|
+
filter: undefined,
|
|
749
|
+
});
|
|
750
|
+
const results2 = await vectorDB.query({
|
|
751
|
+
indexName: testIndexName2,
|
|
752
|
+
queryVector: createVector(0, 1.0),
|
|
753
|
+
});
|
|
660
754
|
expect(results1).toEqual(results2);
|
|
661
755
|
expect(results1.length).toBeGreaterThan(0);
|
|
662
756
|
});
|
|
663
757
|
|
|
664
758
|
it('should handle empty object filter', async () => {
|
|
665
|
-
const results = await vectorDB.query(
|
|
666
|
-
|
|
759
|
+
const results = await vectorDB.query({
|
|
760
|
+
indexName: testIndexName2,
|
|
761
|
+
queryVector: createVector(0, 1.0),
|
|
762
|
+
filter: {},
|
|
763
|
+
});
|
|
764
|
+
const results2 = await vectorDB.query({
|
|
765
|
+
indexName: testIndexName2,
|
|
766
|
+
queryVector: createVector(0, 1.0),
|
|
767
|
+
});
|
|
667
768
|
expect(results).toEqual(results2);
|
|
668
769
|
expect(results.length).toBeGreaterThan(0);
|
|
669
770
|
});
|
|
670
771
|
|
|
671
772
|
it('should handle null filter', async () => {
|
|
672
|
-
const results = await vectorDB.query(
|
|
673
|
-
|
|
773
|
+
const results = await vectorDB.query({
|
|
774
|
+
indexName: testIndexName2,
|
|
775
|
+
queryVector: createVector(0, 1.0),
|
|
776
|
+
filter: null,
|
|
777
|
+
});
|
|
778
|
+
const results2 = await vectorDB.query({
|
|
779
|
+
indexName: testIndexName2,
|
|
780
|
+
queryVector: createVector(0, 1.0),
|
|
781
|
+
});
|
|
674
782
|
expect(results).toEqual(results2);
|
|
675
783
|
expect(results.length).toBeGreaterThan(0);
|
|
676
784
|
});
|
|
677
785
|
});
|
|
678
|
-
},
|
|
786
|
+
}, 800000);
|
|
787
|
+
describe('Deprecation Warnings', () => {
|
|
788
|
+
const indexName = 'testdeprecationwarnings';
|
|
789
|
+
|
|
790
|
+
const indexName2 = 'testdeprecationwarnings2';
|
|
791
|
+
|
|
792
|
+
const indexName3 = 'testdeprecationwarnings3';
|
|
793
|
+
|
|
794
|
+
const indexName4 = 'testdeprecationwarnings4';
|
|
795
|
+
|
|
796
|
+
let warnSpy;
|
|
797
|
+
|
|
798
|
+
beforeAll(async () => {
|
|
799
|
+
try {
|
|
800
|
+
await vectorDB.deleteIndex(indexName);
|
|
801
|
+
} catch {
|
|
802
|
+
// Ignore errors if index doesn't exist
|
|
803
|
+
}
|
|
804
|
+
try {
|
|
805
|
+
await vectorDB.deleteIndex(indexName2);
|
|
806
|
+
} catch {
|
|
807
|
+
// Ignore errors if index doesn't exist
|
|
808
|
+
}
|
|
809
|
+
try {
|
|
810
|
+
await vectorDB.deleteIndex(indexName3);
|
|
811
|
+
} catch {
|
|
812
|
+
// Ignore errors if index doesn't exist
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
await vectorDB.deleteIndex(indexName4);
|
|
816
|
+
} catch {
|
|
817
|
+
// Ignore errors if index doesn't exist
|
|
818
|
+
}
|
|
819
|
+
await vectorDB.createIndex({ indexName: indexName, dimension: VECTOR_DIMENSION });
|
|
820
|
+
await waitUntilReady(vectorDB, indexName);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
afterAll(async () => {
|
|
824
|
+
try {
|
|
825
|
+
await vectorDB.deleteIndex(indexName);
|
|
826
|
+
} catch {
|
|
827
|
+
// Ignore errors if index doesn't exist
|
|
828
|
+
}
|
|
829
|
+
try {
|
|
830
|
+
await vectorDB.deleteIndex(indexName2);
|
|
831
|
+
} catch {
|
|
832
|
+
// Ignore errors if index doesn't exist
|
|
833
|
+
}
|
|
834
|
+
try {
|
|
835
|
+
await vectorDB.deleteIndex(indexName3);
|
|
836
|
+
} catch {
|
|
837
|
+
// Ignore errors if index doesn't exist
|
|
838
|
+
}
|
|
839
|
+
try {
|
|
840
|
+
await vectorDB.deleteIndex(indexName4);
|
|
841
|
+
} catch {
|
|
842
|
+
// Ignore errors if index doesn't exist
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
beforeEach(async () => {
|
|
847
|
+
warnSpy = vi.spyOn(vectorDB['logger'], 'warn');
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
afterEach(async () => {
|
|
851
|
+
warnSpy.mockRestore();
|
|
852
|
+
try {
|
|
853
|
+
await vectorDB.deleteIndex(indexName2);
|
|
854
|
+
} catch (error) {
|
|
855
|
+
console.warn('Failed to delete test index:', error);
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
it('should show deprecation warning when using individual args for createIndex', async () => {
|
|
860
|
+
await vectorDB.createIndex(indexName2, VECTOR_DIMENSION, 'cosine');
|
|
861
|
+
await waitUntilReady(vectorDB, indexName2);
|
|
862
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
863
|
+
expect.stringContaining('Deprecation Warning: Passing individual arguments to createIndex() is deprecated'),
|
|
864
|
+
);
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it('should show deprecation warning when using individual args for upsert', async () => {
|
|
868
|
+
await vectorDB.upsert(indexName, [createVector(0, 1.0)], [{ test: 'data' }]);
|
|
869
|
+
|
|
870
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
871
|
+
expect.stringContaining('Deprecation Warning: Passing individual arguments to upsert() is deprecated'),
|
|
872
|
+
);
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
it('should show deprecation warning when using individual args for query', async () => {
|
|
876
|
+
await vectorDB.query(indexName, createVector(0, 1.0), 5);
|
|
877
|
+
|
|
878
|
+
expect(warnSpy).toHaveBeenCalledWith(
|
|
879
|
+
expect.stringContaining('Deprecation Warning: Passing individual arguments to query() is deprecated'),
|
|
880
|
+
);
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
it('should not show deprecation warning when using object param for query', async () => {
|
|
884
|
+
await vectorDB.query({
|
|
885
|
+
indexName,
|
|
886
|
+
queryVector: createVector(0, 1.0),
|
|
887
|
+
topK: 5,
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
it('should not show deprecation warning when using object param for createIndex', async () => {
|
|
894
|
+
await vectorDB.createIndex({
|
|
895
|
+
indexName: indexName3,
|
|
896
|
+
dimension: VECTOR_DIMENSION,
|
|
897
|
+
metric: 'cosine',
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
901
|
+
});
|
|
902
|
+
|
|
903
|
+
it('should not show deprecation warning when using object param for upsert', async () => {
|
|
904
|
+
await vectorDB.upsert({
|
|
905
|
+
indexName,
|
|
906
|
+
vectors: [createVector(0, 1.0)],
|
|
907
|
+
metadata: [{ test: 'data' }],
|
|
908
|
+
});
|
|
909
|
+
|
|
910
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
it('should maintain backward compatibility with individual args', async () => {
|
|
914
|
+
// Query
|
|
915
|
+
const queryResults = await vectorDB.query(indexName, createVector(0, 1.0), 5);
|
|
916
|
+
expect(Array.isArray(queryResults)).toBe(true);
|
|
917
|
+
|
|
918
|
+
// CreateIndex
|
|
919
|
+
await expect(vectorDB.createIndex(indexName4, VECTOR_DIMENSION, 'cosine')).resolves.not.toThrow();
|
|
920
|
+
await waitUntilReady(vectorDB, indexName4);
|
|
921
|
+
// Upsert
|
|
922
|
+
const upsertResults = await vectorDB.upsert({
|
|
923
|
+
indexName,
|
|
924
|
+
vectors: [createVector(0, 1.0)],
|
|
925
|
+
metadata: [{ test: 'data' }],
|
|
926
|
+
});
|
|
927
|
+
expect(Array.isArray(upsertResults)).toBe(true);
|
|
928
|
+
expect(upsertResults).toHaveLength(1);
|
|
929
|
+
});
|
|
930
|
+
}, 80000);
|
|
679
931
|
});
|
package/src/vector/index.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type { Filter } from '@mastra/core/filter';
|
|
2
1
|
import { MastraVector } from '@mastra/core/vector';
|
|
3
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
QueryResult,
|
|
4
|
+
CreateIndexParams,
|
|
5
|
+
UpsertVectorParams,
|
|
6
|
+
QueryVectorParams,
|
|
7
|
+
ParamsToArgs,
|
|
8
|
+
} from '@mastra/core/vector';
|
|
9
|
+
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
4
10
|
import Cloudflare from 'cloudflare';
|
|
5
11
|
|
|
6
12
|
import { VectorizeFilterTranslator } from './filter';
|
|
@@ -18,12 +24,11 @@ export class CloudflareVector extends MastraVector {
|
|
|
18
24
|
});
|
|
19
25
|
}
|
|
20
26
|
|
|
21
|
-
async upsert(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
): Promise<string[]> {
|
|
27
|
+
async upsert(...args: ParamsToArgs<UpsertVectorParams>): Promise<string[]> {
|
|
28
|
+
const params = this.normalizeArgs<UpsertVectorParams>('upsert', args);
|
|
29
|
+
|
|
30
|
+
const { indexName, vectors, metadata, ids } = params;
|
|
31
|
+
|
|
27
32
|
const generatedIds = ids || vectors.map(() => crypto.randomUUID());
|
|
28
33
|
|
|
29
34
|
// Create NDJSON string - each line is a JSON object
|
|
@@ -52,17 +57,16 @@ export class CloudflareVector extends MastraVector {
|
|
|
52
57
|
return generatedIds;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
transformFilter(filter?:
|
|
60
|
+
transformFilter(filter?: VectorFilter) {
|
|
56
61
|
const translator = new VectorizeFilterTranslator();
|
|
57
|
-
|
|
58
|
-
return translatedFilter;
|
|
62
|
+
return translator.translate(filter);
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
async createIndex(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
async createIndex(...args: ParamsToArgs<CreateIndexParams>): Promise<void> {
|
|
66
|
+
const params = this.normalizeArgs<CreateIndexParams>('createIndex', args);
|
|
67
|
+
|
|
68
|
+
const { indexName, dimension, metric = 'cosine' } = params;
|
|
69
|
+
|
|
66
70
|
await this.client.vectorize.indexes.create({
|
|
67
71
|
account_id: this.accountId,
|
|
68
72
|
config: {
|
|
@@ -73,14 +77,12 @@ export class CloudflareVector extends MastraVector {
|
|
|
73
77
|
});
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
async query(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
topK
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
): Promise<QueryResult[]> {
|
|
83
|
-
const translatedFilter = this.transformFilter(filter);
|
|
80
|
+
async query(...args: ParamsToArgs<QueryVectorParams>): Promise<QueryResult[]> {
|
|
81
|
+
const params = this.normalizeArgs<QueryVectorParams>('query', args);
|
|
82
|
+
|
|
83
|
+
const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;
|
|
84
|
+
|
|
85
|
+
const translatedFilter = this.transformFilter(filter) ?? {};
|
|
84
86
|
const response = await this.client.vectorize.indexes.query(indexName, {
|
|
85
87
|
account_id: this.accountId,
|
|
86
88
|
vector: queryVector,
|