@mastra/convex 1.0.11 → 1.1.0
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 +138 -0
- package/README.md +76 -4
- package/dist/cache/client.d.ts +21 -0
- package/dist/cache/client.d.ts.map +1 -0
- package/dist/cache/index.d.ts +35 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/types.d.ts +46 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/{chunk-FTVDAP6U.cjs → chunk-CV23JOCS.cjs} +44 -2
- package/dist/chunk-CV23JOCS.cjs.map +1 -0
- package/dist/chunk-EEELVBWO.cjs +893 -0
- package/dist/chunk-EEELVBWO.cjs.map +1 -0
- package/dist/chunk-FZDLZ4S3.js +887 -0
- package/dist/chunk-FZDLZ4S3.js.map +1 -0
- package/dist/{chunk-G5FLGAPE.js → chunk-JPWDG4L3.js} +42 -3
- package/dist/chunk-JPWDG4L3.js.map +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +44 -15
- package/dist/docs/references/reference-storage-convex.md +74 -12
- package/dist/docs/references/reference-vectors-convex.md +129 -7
- package/dist/index.cjs +515 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +471 -23
- package/dist/index.js.map +1 -1
- package/dist/schema.cjs +29 -17
- package/dist/schema.d.ts +76 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -1
- package/dist/server/cache.d.ts +5 -0
- package/dist/server/cache.d.ts.map +1 -0
- package/dist/server/index.cjs +44 -16
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/native-vector.d.ts +17 -0
- package/dist/server/native-vector.d.ts.map +1 -0
- package/dist/storage/client.d.ts +5 -0
- package/dist/storage/client.d.ts.map +1 -1
- package/dist/vector/native.d.ts +111 -0
- package/dist/vector/native.d.ts.map +1 -0
- package/package.json +5 -5
- package/dist/chunk-C6QDNSBM.cjs +0 -425
- package/dist/chunk-C6QDNSBM.cjs.map +0 -1
- package/dist/chunk-FTVDAP6U.cjs.map +0 -1
- package/dist/chunk-G5FLGAPE.js.map +0 -1
- package/dist/chunk-NXNW2MK5.js +0 -423
- package/dist/chunk-NXNW2MK5.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
export { ConvexServerCache, ConvexCacheClient, type ConvexServerCacheConfig, type ConvexCacheClientConfig, } from './cache/index.js';
|
|
1
2
|
export { ConvexStore, type ConvexStoreConfig } from './storage/index.js';
|
|
2
3
|
export { ConvexVector, type ConvexVectorConfig } from './vector/index.js';
|
|
4
|
+
export { ConvexNativeVector, type ConvexNativeVectorConfig, type ConvexNativeVectorFilter, type ConvexNativeVectorIndexConfig, } from './vector/native.js';
|
|
3
5
|
export * from './server/index.js';
|
|
4
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACjE,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,GAC7B,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,GACnC,MAAM,iBAAiB,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { mastraStorage } from './chunk-
|
|
2
|
-
export { TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT, mastraDocumentsTable, mastraMessagesTable, mastraResourcesTable, mastraScoresTable, mastraThreadsTable, mastraVectorIndexesTable, mastraVectorsTable, mastraWorkflowSnapshotsTable } from './chunk-
|
|
1
|
+
export { mastraCache, mastraNativeVectorAction, mastraNativeVectorMutation, mastraNativeVectorQuery, mastraStorage } from './chunk-FZDLZ4S3.js';
|
|
2
|
+
export { TABLE_MESSAGES, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT, defineMastraNativeVectorTable, mastraCacheListItemsTable, mastraCacheTable, mastraDocumentsTable, mastraMessagesTable, mastraResourcesTable, mastraScoresTable, mastraThreadsTable, mastraVectorIndexesTable, mastraVectorsTable, mastraWorkflowSnapshotsTable } from './chunk-JPWDG4L3.js';
|
|
3
|
+
import { MastraServerCache } from '@mastra/core/cache';
|
|
3
4
|
import { MastraCompositeStore, createVectorErrorId, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, createStorageErrorId, normalizePerPage, calculatePagination, filterByDateRange, safelyParseJSON, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, BackgroundTasksStorage, TABLE_BACKGROUND_TASKS } from '@mastra/core/storage';
|
|
4
5
|
import crypto from 'crypto';
|
|
5
6
|
import { MastraBase } from '@mastra/core/base';
|
|
@@ -7,6 +8,186 @@ import { MessageList } from '@mastra/core/agent';
|
|
|
7
8
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
8
9
|
import { MastraVector } from '@mastra/core/vector';
|
|
9
10
|
|
|
11
|
+
// src/cache/client.ts
|
|
12
|
+
var DEFAULT_CACHE_FUNCTION = "mastra/cache:handle";
|
|
13
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
14
|
+
var trimTrailingSlashes = (value) => {
|
|
15
|
+
let end = value.length;
|
|
16
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) {
|
|
17
|
+
end -= 1;
|
|
18
|
+
}
|
|
19
|
+
return value.slice(0, end);
|
|
20
|
+
};
|
|
21
|
+
var ConvexCacheClient = class {
|
|
22
|
+
deploymentUrl;
|
|
23
|
+
adminAuthToken;
|
|
24
|
+
cacheFunction;
|
|
25
|
+
requestTimeoutMs;
|
|
26
|
+
constructor({ deploymentUrl, adminAuthToken, cacheFunction, requestTimeoutMs }) {
|
|
27
|
+
const normalizedDeploymentUrl = deploymentUrl.trim();
|
|
28
|
+
const normalizedAdminAuthToken = adminAuthToken.trim();
|
|
29
|
+
const normalizedCacheFunction = cacheFunction?.trim();
|
|
30
|
+
if (!normalizedDeploymentUrl) {
|
|
31
|
+
throw new Error("ConvexCacheClient: deploymentUrl is required.");
|
|
32
|
+
}
|
|
33
|
+
if (!normalizedAdminAuthToken) {
|
|
34
|
+
throw new Error("ConvexCacheClient: adminAuthToken is required.");
|
|
35
|
+
}
|
|
36
|
+
if (requestTimeoutMs !== void 0 && requestTimeoutMs < 0) {
|
|
37
|
+
throw new Error("ConvexCacheClient: requestTimeoutMs must be greater than or equal to 0.");
|
|
38
|
+
}
|
|
39
|
+
this.deploymentUrl = trimTrailingSlashes(normalizedDeploymentUrl);
|
|
40
|
+
this.adminAuthToken = normalizedAdminAuthToken;
|
|
41
|
+
this.cacheFunction = normalizedCacheFunction || DEFAULT_CACHE_FUNCTION;
|
|
42
|
+
this.requestTimeoutMs = requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
43
|
+
}
|
|
44
|
+
async callCacheRaw(request) {
|
|
45
|
+
const controller = this.requestTimeoutMs > 0 ? new AbortController() : void 0;
|
|
46
|
+
const timeoutId = controller ? setTimeout(() => controller.abort(), this.requestTimeoutMs) : void 0;
|
|
47
|
+
let response;
|
|
48
|
+
try {
|
|
49
|
+
response = await fetch(`${this.deploymentUrl}/api/mutation`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: {
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
Authorization: `Convex ${this.adminAuthToken}`
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
path: this.cacheFunction,
|
|
57
|
+
args: request,
|
|
58
|
+
format: "json"
|
|
59
|
+
}),
|
|
60
|
+
signal: controller?.signal
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (controller?.signal.aborted) {
|
|
64
|
+
throw new Error(`Convex cache request timed out after ${this.requestTimeoutMs} ms.`);
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
} finally {
|
|
68
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
const text = await response.text();
|
|
72
|
+
throw new Error(`Convex API error: ${response.status} ${text}`);
|
|
73
|
+
}
|
|
74
|
+
const result = await response.json();
|
|
75
|
+
if (result.status === "error") {
|
|
76
|
+
const error = new Error(result.errorMessage || "Unknown Convex error");
|
|
77
|
+
error.code = result.errorCode ?? result.code;
|
|
78
|
+
error.details = result.details;
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
const cacheResponse = result.value;
|
|
82
|
+
if (!cacheResponse?.ok) {
|
|
83
|
+
const errResponse = cacheResponse;
|
|
84
|
+
const error = new Error(errResponse?.error || "Unknown Convex cache error");
|
|
85
|
+
error.code = errResponse?.code;
|
|
86
|
+
error.details = errResponse?.details;
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
result: cacheResponse.result,
|
|
91
|
+
hasMore: cacheResponse.hasMore
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async callCache(request) {
|
|
95
|
+
const { result } = await this.callCacheRaw(request);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/cache/index.ts
|
|
101
|
+
var DEFAULT_KEY_PREFIX = "mastra:cache:";
|
|
102
|
+
var DEFAULT_TTL_MS = 3e5;
|
|
103
|
+
var MAX_CACHE_OPERATION_BATCHES = 1e3;
|
|
104
|
+
var isClientConfig = (config) => "client" in config;
|
|
105
|
+
var ConvexServerCache = class extends MastraServerCache {
|
|
106
|
+
client;
|
|
107
|
+
keyPrefix;
|
|
108
|
+
ttlMs;
|
|
109
|
+
constructor(config) {
|
|
110
|
+
super({ name: "ConvexServerCache" });
|
|
111
|
+
this.client = isClientConfig(config) ? config.client : new ConvexCacheClient(config);
|
|
112
|
+
this.keyPrefix = config.keyPrefix ?? DEFAULT_KEY_PREFIX;
|
|
113
|
+
this.ttlMs = config.ttlMs ?? DEFAULT_TTL_MS;
|
|
114
|
+
}
|
|
115
|
+
getKey(key) {
|
|
116
|
+
return `${this.keyPrefix}${key}`;
|
|
117
|
+
}
|
|
118
|
+
getExpiresAt(ttlMs) {
|
|
119
|
+
const effectiveTtlMs = ttlMs ?? this.ttlMs;
|
|
120
|
+
return effectiveTtlMs > 0 ? Date.now() + effectiveTtlMs : null;
|
|
121
|
+
}
|
|
122
|
+
async callUntilSettled(request) {
|
|
123
|
+
for (let batch = 0; batch < MAX_CACHE_OPERATION_BATCHES; batch += 1) {
|
|
124
|
+
const response = await this.client.callCacheRaw({
|
|
125
|
+
...request()
|
|
126
|
+
});
|
|
127
|
+
if (!response.hasMore) return response.result;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`ConvexServerCache operation exceeded ${MAX_CACHE_OPERATION_BATCHES} batches.`);
|
|
130
|
+
}
|
|
131
|
+
async get(key) {
|
|
132
|
+
return this.callUntilSettled(() => ({
|
|
133
|
+
op: "get",
|
|
134
|
+
key: this.getKey(key)
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
async set(key, value, ttlMs) {
|
|
138
|
+
await this.callUntilSettled(() => ({
|
|
139
|
+
op: "set",
|
|
140
|
+
key: this.getKey(key),
|
|
141
|
+
keyPrefix: this.keyPrefix,
|
|
142
|
+
value,
|
|
143
|
+
expiresAt: this.getExpiresAt(ttlMs)
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
async listLength(key) {
|
|
147
|
+
return this.callUntilSettled(() => ({
|
|
148
|
+
op: "listLength",
|
|
149
|
+
key: this.getKey(key)
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
async listPush(key, value) {
|
|
153
|
+
await this.callUntilSettled(() => ({
|
|
154
|
+
op: "listPush",
|
|
155
|
+
key: this.getKey(key),
|
|
156
|
+
keyPrefix: this.keyPrefix,
|
|
157
|
+
value,
|
|
158
|
+
expiresAt: this.getExpiresAt()
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
async listFromTo(key, from, to = -1) {
|
|
162
|
+
return this.callUntilSettled(() => ({
|
|
163
|
+
op: "listFromTo",
|
|
164
|
+
key: this.getKey(key),
|
|
165
|
+
from,
|
|
166
|
+
to
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
async delete(key) {
|
|
170
|
+
await this.callUntilSettled(() => ({
|
|
171
|
+
op: "delete",
|
|
172
|
+
key: this.getKey(key)
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
async clear() {
|
|
176
|
+
await this.callUntilSettled(() => ({
|
|
177
|
+
op: "clear",
|
|
178
|
+
keyPrefix: this.keyPrefix
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
async increment(key) {
|
|
182
|
+
return this.callUntilSettled(() => ({
|
|
183
|
+
op: "increment",
|
|
184
|
+
key: this.getKey(key),
|
|
185
|
+
keyPrefix: this.keyPrefix,
|
|
186
|
+
expiresAt: this.getExpiresAt()
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
10
191
|
// src/storage/client.ts
|
|
11
192
|
var DEFAULT_STORAGE_FUNCTION = "mastra/storage:handle";
|
|
12
193
|
var ConvexAdminClient = class {
|
|
@@ -29,7 +210,39 @@ var ConvexAdminClient = class {
|
|
|
29
210
|
* Use this for operations that may need multiple calls (e.g., clearTable).
|
|
30
211
|
*/
|
|
31
212
|
async callStorageRaw(request) {
|
|
32
|
-
const
|
|
213
|
+
const result = await this.callConvexFunction("mutation", this.storageFunction, request);
|
|
214
|
+
const storageResponse = result.value;
|
|
215
|
+
if (!storageResponse?.ok) {
|
|
216
|
+
const errResponse = storageResponse;
|
|
217
|
+
const error = new Error(errResponse?.error || "Unknown Convex storage error");
|
|
218
|
+
error.code = errResponse?.code;
|
|
219
|
+
error.details = errResponse?.details;
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
result: storageResponse.result,
|
|
224
|
+
hasMore: storageResponse.hasMore
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async callStorage(request) {
|
|
228
|
+
const { result } = await this.callStorageRaw(request);
|
|
229
|
+
return result;
|
|
230
|
+
}
|
|
231
|
+
async callAction(path, args) {
|
|
232
|
+
return this.callFunction("action", path, args);
|
|
233
|
+
}
|
|
234
|
+
async callMutation(path, args) {
|
|
235
|
+
return this.callFunction("mutation", path, args);
|
|
236
|
+
}
|
|
237
|
+
async callQuery(path, args) {
|
|
238
|
+
return this.callFunction("query", path, args);
|
|
239
|
+
}
|
|
240
|
+
async callFunction(kind, path, args) {
|
|
241
|
+
const result = await this.callConvexFunction(kind, path, args);
|
|
242
|
+
return result.value;
|
|
243
|
+
}
|
|
244
|
+
async callConvexFunction(kind, path, args) {
|
|
245
|
+
const url = `${this.deploymentUrl}/api/${kind}`;
|
|
33
246
|
const response = await fetch(url, {
|
|
34
247
|
method: "POST",
|
|
35
248
|
headers: {
|
|
@@ -37,8 +250,8 @@ var ConvexAdminClient = class {
|
|
|
37
250
|
Authorization: `Convex ${this.adminAuthToken}`
|
|
38
251
|
},
|
|
39
252
|
body: JSON.stringify({
|
|
40
|
-
path
|
|
41
|
-
args
|
|
253
|
+
path,
|
|
254
|
+
args,
|
|
42
255
|
format: "json"
|
|
43
256
|
})
|
|
44
257
|
});
|
|
@@ -49,24 +262,15 @@ var ConvexAdminClient = class {
|
|
|
49
262
|
const result = await response.json();
|
|
50
263
|
if (result.status === "error") {
|
|
51
264
|
const error = new Error(result.errorMessage || "Unknown Convex error");
|
|
52
|
-
error.
|
|
265
|
+
error.details = result.errorData;
|
|
53
266
|
throw error;
|
|
54
267
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
error.details = errResponse?.details;
|
|
61
|
-
throw error;
|
|
268
|
+
if (result.status !== "success") {
|
|
269
|
+
throw new Error(`Convex ${kind} ${path} returned an invalid response`);
|
|
270
|
+
}
|
|
271
|
+
if (result.value === void 0) {
|
|
272
|
+
throw new Error(`Convex ${kind} ${path} returned no value`);
|
|
62
273
|
}
|
|
63
|
-
return {
|
|
64
|
-
result: storageResponse.result,
|
|
65
|
-
hasMore: storageResponse.hasMore
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
async callStorage(request) {
|
|
69
|
-
const { result } = await this.callStorageRaw(request);
|
|
70
274
|
return result;
|
|
71
275
|
}
|
|
72
276
|
};
|
|
@@ -81,6 +285,7 @@ var ConvexDB = class extends MastraBase {
|
|
|
81
285
|
super({ name: "convex-db" });
|
|
82
286
|
this.client = client;
|
|
83
287
|
}
|
|
288
|
+
client;
|
|
84
289
|
async hasColumn(_table, _column) {
|
|
85
290
|
return true;
|
|
86
291
|
}
|
|
@@ -1060,13 +1265,13 @@ var WorkflowsConvex = class extends WorkflowsStorage {
|
|
|
1060
1265
|
};
|
|
1061
1266
|
|
|
1062
1267
|
// src/storage/index.ts
|
|
1063
|
-
var
|
|
1268
|
+
var isClientConfig2 = (config) => {
|
|
1064
1269
|
return "client" in config;
|
|
1065
1270
|
};
|
|
1066
1271
|
var ConvexStore = class extends MastraCompositeStore {
|
|
1067
1272
|
constructor(config) {
|
|
1068
1273
|
super({ id: config.id, name: config.name ?? "ConvexStore", disableInit: config.disableInit });
|
|
1069
|
-
const client =
|
|
1274
|
+
const client = isClientConfig2(config) ? config.client : new ConvexAdminClient(config);
|
|
1070
1275
|
const domainConfig = { client };
|
|
1071
1276
|
const memory = new MemoryConvex(domainConfig);
|
|
1072
1277
|
const workflows = new WorkflowsConvex(domainConfig);
|
|
@@ -1390,7 +1595,250 @@ function cosineSimilarity(a, b) {
|
|
|
1390
1595
|
}
|
|
1391
1596
|
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
1392
1597
|
}
|
|
1598
|
+
var DEFAULT_VECTOR_INDEX = "by_embedding";
|
|
1599
|
+
var DEFAULT_ID_FIELD = "id";
|
|
1600
|
+
var DEFAULT_ID_INDEX = "by_record_id";
|
|
1601
|
+
var DEFAULT_VECTOR_FIELD = "embedding";
|
|
1602
|
+
var DEFAULT_METADATA_FIELD = "metadata";
|
|
1603
|
+
var DEFAULT_NATIVE_ACTION = "mastra/nativeVector:query";
|
|
1604
|
+
var DEFAULT_NATIVE_QUERY = "mastra/nativeVector:read";
|
|
1605
|
+
var DEFAULT_NATIVE_MUTATION = "mastra/nativeVector:write";
|
|
1606
|
+
var MAX_CONVEX_VECTOR_RESULTS = 256;
|
|
1607
|
+
var NATIVE_VECTOR_UPSERT_BATCH_SIZE = 100;
|
|
1608
|
+
function isMetadataRecord(value) {
|
|
1609
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1610
|
+
}
|
|
1611
|
+
var ConvexNativeVector = class extends MastraVector {
|
|
1612
|
+
client;
|
|
1613
|
+
indexes;
|
|
1614
|
+
nativeVectorAction;
|
|
1615
|
+
nativeVectorQuery;
|
|
1616
|
+
nativeVectorMutation;
|
|
1617
|
+
describeCountLimit;
|
|
1618
|
+
constructor(config) {
|
|
1619
|
+
super({ id: config.id });
|
|
1620
|
+
this.client = new ConvexAdminClient(config);
|
|
1621
|
+
this.indexes = Object.fromEntries(
|
|
1622
|
+
Object.entries(config.indexes).map(([indexName, index]) => [
|
|
1623
|
+
indexName,
|
|
1624
|
+
{
|
|
1625
|
+
tableName: index.tableName,
|
|
1626
|
+
vectorIndexName: index.vectorIndexName ?? DEFAULT_VECTOR_INDEX,
|
|
1627
|
+
dimension: index.dimension,
|
|
1628
|
+
idField: index.idField ?? DEFAULT_ID_FIELD,
|
|
1629
|
+
idIndexName: index.idIndexName ?? DEFAULT_ID_INDEX,
|
|
1630
|
+
vectorField: index.vectorField ?? DEFAULT_VECTOR_FIELD,
|
|
1631
|
+
metadataField: index.metadataField ?? DEFAULT_METADATA_FIELD,
|
|
1632
|
+
filterFields: index.filterFields ?? []
|
|
1633
|
+
}
|
|
1634
|
+
])
|
|
1635
|
+
);
|
|
1636
|
+
this.nativeVectorAction = config.nativeVectorAction ?? DEFAULT_NATIVE_ACTION;
|
|
1637
|
+
this.nativeVectorQuery = config.nativeVectorQuery ?? DEFAULT_NATIVE_QUERY;
|
|
1638
|
+
this.nativeVectorMutation = config.nativeVectorMutation ?? DEFAULT_NATIVE_MUTATION;
|
|
1639
|
+
this.describeCountLimit = config.describeCountLimit ?? 1e4;
|
|
1640
|
+
}
|
|
1641
|
+
async createIndex({ indexName, dimension, metric = "cosine" }) {
|
|
1642
|
+
const index = this.getIndex(indexName);
|
|
1643
|
+
if (index.dimension !== dimension) {
|
|
1644
|
+
throw new Error(
|
|
1645
|
+
`ConvexNativeVector.createIndex: deployed Convex index "${indexName}" has ${index.dimension} dimensions, but ${dimension} were requested`
|
|
1646
|
+
);
|
|
1647
|
+
}
|
|
1648
|
+
if (metric !== "cosine") {
|
|
1649
|
+
throw new Error("ConvexNativeVector.createIndex: Convex native vector search currently supports cosine only");
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
async listIndexes() {
|
|
1653
|
+
return Object.keys(this.indexes);
|
|
1654
|
+
}
|
|
1655
|
+
async describeIndex({ indexName }) {
|
|
1656
|
+
const index = this.getIndex(indexName);
|
|
1657
|
+
const result = await this.client.callQuery(this.nativeVectorQuery, {
|
|
1658
|
+
op: "describe",
|
|
1659
|
+
config: index,
|
|
1660
|
+
countLimit: this.describeCountLimit
|
|
1661
|
+
});
|
|
1662
|
+
if (result.countIsLimited) {
|
|
1663
|
+
this.logger.warn(
|
|
1664
|
+
`ConvexNativeVector.describeIndex: count for "${indexName}" reached ${this.describeCountLimit}; reported count is capped.`
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
return {
|
|
1668
|
+
dimension: index.dimension,
|
|
1669
|
+
count: result.count,
|
|
1670
|
+
metric: "cosine"
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
async upsert({ indexName, vectors, ids, metadata, deleteFilter }) {
|
|
1674
|
+
if (deleteFilter) {
|
|
1675
|
+
throw new Error("ConvexNativeVector.upsert: deleteFilter is not supported. Delete by IDs before upserting.");
|
|
1676
|
+
}
|
|
1677
|
+
const index = this.getIndex(indexName);
|
|
1678
|
+
if (ids && ids.length !== vectors.length) {
|
|
1679
|
+
throw new Error(
|
|
1680
|
+
`ConvexNativeVector.upsert: ids length (${ids.length}) must match vectors length (${vectors.length})`
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
if (metadata && metadata.length !== vectors.length) {
|
|
1684
|
+
throw new Error(
|
|
1685
|
+
`ConvexNativeVector.upsert: metadata length (${metadata.length}) must match vectors length (${vectors.length})`
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
if (metadata && !metadata.every(isMetadataRecord)) {
|
|
1689
|
+
throw new Error("ConvexNativeVector.upsert: metadata entries must be objects when provided");
|
|
1690
|
+
}
|
|
1691
|
+
const vectorIds = ids ?? vectors.map(() => crypto.randomUUID());
|
|
1692
|
+
if (new Set(vectorIds).size !== vectorIds.length) {
|
|
1693
|
+
throw new Error("ConvexNativeVector.upsert: ids must be unique");
|
|
1694
|
+
}
|
|
1695
|
+
for (let start = 0; start < vectors.length; start += NATIVE_VECTOR_UPSERT_BATCH_SIZE) {
|
|
1696
|
+
const end = start + NATIVE_VECTOR_UPSERT_BATCH_SIZE;
|
|
1697
|
+
await this.client.callMutation(this.nativeVectorMutation, {
|
|
1698
|
+
op: "upsert",
|
|
1699
|
+
config: index,
|
|
1700
|
+
ids: vectorIds.slice(start, end),
|
|
1701
|
+
vectors: vectors.slice(start, end),
|
|
1702
|
+
...metadata ? { metadata: metadata.slice(start, end) } : {}
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
return vectorIds;
|
|
1706
|
+
}
|
|
1707
|
+
async query({
|
|
1708
|
+
indexName,
|
|
1709
|
+
queryVector,
|
|
1710
|
+
topK = 10,
|
|
1711
|
+
includeVector = false,
|
|
1712
|
+
filter
|
|
1713
|
+
}) {
|
|
1714
|
+
if (!queryVector) {
|
|
1715
|
+
throw new MastraError({
|
|
1716
|
+
id: createVectorErrorId("CONVEX_NATIVE", "QUERY", "MISSING_VECTOR"),
|
|
1717
|
+
text: "queryVector is required for Convex native vector queries.",
|
|
1718
|
+
domain: ErrorDomain.STORAGE,
|
|
1719
|
+
category: ErrorCategory.USER,
|
|
1720
|
+
details: { indexName }
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
if (!Number.isFinite(topK) || !Number.isInteger(topK) || topK < 1 || topK > MAX_CONVEX_VECTOR_RESULTS) {
|
|
1724
|
+
throw new Error(`ConvexNativeVector.query: topK must be an integer between 1 and ${MAX_CONVEX_VECTOR_RESULTS}`);
|
|
1725
|
+
}
|
|
1726
|
+
const index = this.getIndex(indexName);
|
|
1727
|
+
const nativeFilter = this.toNativeFilter(filter, index);
|
|
1728
|
+
const searchResults = await this.client.callAction(this.nativeVectorAction, {
|
|
1729
|
+
config: index,
|
|
1730
|
+
vector: queryVector,
|
|
1731
|
+
limit: topK,
|
|
1732
|
+
...nativeFilter ? { filter: nativeFilter } : {}
|
|
1733
|
+
});
|
|
1734
|
+
if (searchResults.length === 0) return [];
|
|
1735
|
+
const docs = await this.client.callQuery(this.nativeVectorQuery, {
|
|
1736
|
+
op: "getByConvexIds",
|
|
1737
|
+
config: index,
|
|
1738
|
+
ids: searchResults.map((result) => result.id),
|
|
1739
|
+
includeVector
|
|
1740
|
+
});
|
|
1741
|
+
const scoresByConvexId = new Map(searchResults.map((result) => [result.id, result.score]));
|
|
1742
|
+
return docs.flatMap((doc) => {
|
|
1743
|
+
if (!doc?._id) return [];
|
|
1744
|
+
return [
|
|
1745
|
+
{
|
|
1746
|
+
id: String(doc[index.idField]),
|
|
1747
|
+
score: scoresByConvexId.get(String(doc._id)) ?? 0,
|
|
1748
|
+
metadata: doc[index.metadataField],
|
|
1749
|
+
...includeVector ? { vector: doc[index.vectorField] } : {}
|
|
1750
|
+
}
|
|
1751
|
+
];
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
async updateVector(params) {
|
|
1755
|
+
if ("filter" in params && params.filter !== void 0) {
|
|
1756
|
+
throw new Error("ConvexNativeVector.updateVector: filter-based updates are not supported. Update by ID instead.");
|
|
1757
|
+
}
|
|
1758
|
+
if (params.update.metadata !== void 0 && !isMetadataRecord(params.update.metadata)) {
|
|
1759
|
+
throw new Error("ConvexNativeVector.updateVector: metadata must be an object when provided");
|
|
1760
|
+
}
|
|
1761
|
+
const index = this.getIndex(params.indexName);
|
|
1762
|
+
await this.client.callMutation(this.nativeVectorMutation, {
|
|
1763
|
+
op: "updateById",
|
|
1764
|
+
config: index,
|
|
1765
|
+
id: params.id,
|
|
1766
|
+
vector: params.update.vector,
|
|
1767
|
+
metadata: params.update.metadata
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
async deleteVector({ indexName, id }) {
|
|
1771
|
+
const index = this.getIndex(indexName);
|
|
1772
|
+
await this.client.callMutation(this.nativeVectorMutation, {
|
|
1773
|
+
op: "deleteByIds",
|
|
1774
|
+
config: index,
|
|
1775
|
+
ids: [id]
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
async deleteVectors(params) {
|
|
1779
|
+
if (params.filter !== void 0) {
|
|
1780
|
+
throw new Error(
|
|
1781
|
+
"ConvexNativeVector.deleteVectors: filter-based deletes are not supported. Delete by IDs instead."
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1784
|
+
if (!params.ids || params.ids.length === 0) {
|
|
1785
|
+
throw new Error("ConvexNativeVector.deleteVectors: ids are required");
|
|
1786
|
+
}
|
|
1787
|
+
const index = this.getIndex(params.indexName);
|
|
1788
|
+
await this.client.callMutation(this.nativeVectorMutation, {
|
|
1789
|
+
op: "deleteByIds",
|
|
1790
|
+
config: index,
|
|
1791
|
+
ids: params.ids
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
async deleteIndex({ indexName }) {
|
|
1795
|
+
this.getIndex(indexName);
|
|
1796
|
+
throw new Error("ConvexNativeVector.deleteIndex: Convex native vector indexes are managed in convex/schema.ts.");
|
|
1797
|
+
}
|
|
1798
|
+
getIndex(indexName) {
|
|
1799
|
+
const index = this.indexes[indexName];
|
|
1800
|
+
if (!index) {
|
|
1801
|
+
throw new Error(`ConvexNativeVector: index "${indexName}" is not configured`);
|
|
1802
|
+
}
|
|
1803
|
+
return index;
|
|
1804
|
+
}
|
|
1805
|
+
toNativeFilter(filter, index) {
|
|
1806
|
+
if (!filter || Object.keys(filter).length === 0) return void 0;
|
|
1807
|
+
if (this.isOrFilter(filter)) {
|
|
1808
|
+
const clauses = filter.$or.map((branch) => this.toSingleClause(branch, index));
|
|
1809
|
+
return { $or: clauses };
|
|
1810
|
+
}
|
|
1811
|
+
const fieldFilter = this.isMetadataFilter(filter) ? filter.metadata : filter;
|
|
1812
|
+
return this.toSingleClause(fieldFilter, index);
|
|
1813
|
+
}
|
|
1814
|
+
toSingleClause(filter, index) {
|
|
1815
|
+
const entries = Object.entries(filter).filter(([, value2]) => value2 !== void 0);
|
|
1816
|
+
if (entries.length !== 1) {
|
|
1817
|
+
throw new Error(
|
|
1818
|
+
"ConvexNativeVector.query: native Convex filters support one equality field or $or of equality fields"
|
|
1819
|
+
);
|
|
1820
|
+
}
|
|
1821
|
+
const [field, rawValue] = entries[0];
|
|
1822
|
+
if (!index.filterFields.includes(field)) {
|
|
1823
|
+
throw new Error(`ConvexNativeVector.query: field "${field}" is not configured as a Convex vector filter field`);
|
|
1824
|
+
}
|
|
1825
|
+
const value = typeof rawValue === "object" && rawValue !== null && "$eq" in rawValue ? rawValue.$eq : rawValue;
|
|
1826
|
+
if (!["string", "number", "boolean"].includes(typeof value) && value !== null) {
|
|
1827
|
+
throw new Error(
|
|
1828
|
+
"ConvexNativeVector.query: native Convex filters support string, number, boolean, and null values"
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
return { field, value };
|
|
1832
|
+
}
|
|
1833
|
+
isOrFilter(filter) {
|
|
1834
|
+
return Array.isArray(filter.$or);
|
|
1835
|
+
}
|
|
1836
|
+
isMetadataFilter(filter) {
|
|
1837
|
+
const metadata = filter.metadata;
|
|
1838
|
+
return typeof metadata === "object" && metadata !== null && !Array.isArray(metadata);
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1393
1841
|
|
|
1394
|
-
export { ConvexStore, ConvexVector };
|
|
1842
|
+
export { ConvexCacheClient, ConvexNativeVector, ConvexServerCache, ConvexStore, ConvexVector };
|
|
1395
1843
|
//# sourceMappingURL=index.js.map
|
|
1396
1844
|
//# sourceMappingURL=index.js.map
|