@mastra/mongodb 0.0.0-vnext-inngest-20250508122351 → 0.0.0-vnext-20251104230439
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 +1150 -2
- package/LICENSE.md +11 -42
- package/README.md +50 -0
- package/dist/index.cjs +2504 -139
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2500 -136
- package/dist/index.js.map +1 -0
- package/dist/storage/connectors/MongoDBConnector.d.ts +23 -0
- package/dist/storage/connectors/MongoDBConnector.d.ts.map +1 -0
- package/dist/storage/connectors/base.d.ts +6 -0
- package/dist/storage/connectors/base.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +66 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/observability/index.d.ts +43 -0
- package/dist/storage/domains/observability/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +50 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +50 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +8 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +45 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +201 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/types.d.ts +11 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/vector/filter.d.ts +21 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +93 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/prompt.d.ts +6 -0
- package/dist/vector/prompt.d.ts.map +1 -0
- package/package.json +34 -16
- package/dist/_tsup-dts-rollup.d.cts +0 -96
- package/dist/_tsup-dts-rollup.d.ts +0 -96
- package/dist/index.d.cts +0 -7
- package/docker-compose.yml +0 -8
- package/eslint.config.js +0 -6
- package/src/index.ts +0 -2
- package/src/vector/filter.test.ts +0 -410
- package/src/vector/filter.ts +0 -122
- package/src/vector/index.test.ts +0 -459
- package/src/vector/index.ts +0 -380
- package/src/vector/prompt.ts +0 -97
- package/tsconfig.json +0 -5
- package/vitest.config.ts +0 -11
package/dist/index.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
1
2
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
3
|
import { MongoClient } from 'mongodb';
|
|
3
4
|
import { v4 } from 'uuid';
|
|
4
5
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
6
|
+
import { MastraStorage, StoreOperations, TABLE_SCHEMAS, safelyParseJSON, MemoryStorage, TABLE_MESSAGES, resolveMessageLimit, normalizePerPage, calculatePagination, TABLE_THREADS, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ObservabilityStorage, TABLE_AI_SPANS } from '@mastra/core/storage';
|
|
7
|
+
import { MessageList } from '@mastra/core/agent';
|
|
8
|
+
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
5
9
|
|
|
6
10
|
// src/vector/index.ts
|
|
11
|
+
|
|
12
|
+
// package.json
|
|
13
|
+
var package_default = {
|
|
14
|
+
version: "0.14.6"};
|
|
7
15
|
var MongoDBFilterTranslator = class extends BaseFilterTranslator {
|
|
8
16
|
getSupportedOperators() {
|
|
9
17
|
return {
|
|
@@ -108,35 +116,81 @@ var MongoDBVector = class extends MastraVector {
|
|
|
108
116
|
};
|
|
109
117
|
constructor({ uri, dbName, options }) {
|
|
110
118
|
super();
|
|
111
|
-
|
|
119
|
+
const client = new MongoClient(uri, {
|
|
120
|
+
...options,
|
|
121
|
+
driverInfo: {
|
|
122
|
+
name: "mastra-vector",
|
|
123
|
+
version: package_default.version
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
this.client = client;
|
|
112
127
|
this.db = this.client.db(dbName);
|
|
113
128
|
this.collections = /* @__PURE__ */ new Map();
|
|
114
129
|
}
|
|
115
130
|
// Public methods
|
|
116
131
|
async connect() {
|
|
117
|
-
|
|
132
|
+
try {
|
|
133
|
+
await this.client.connect();
|
|
134
|
+
} catch (error) {
|
|
135
|
+
throw new MastraError(
|
|
136
|
+
{
|
|
137
|
+
id: "STORAGE_MONGODB_VECTOR_CONNECT_FAILED",
|
|
138
|
+
domain: ErrorDomain.STORAGE,
|
|
139
|
+
category: ErrorCategory.THIRD_PARTY
|
|
140
|
+
},
|
|
141
|
+
error
|
|
142
|
+
);
|
|
143
|
+
}
|
|
118
144
|
}
|
|
119
145
|
async disconnect() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
146
|
+
try {
|
|
147
|
+
await this.client.close();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new MastraError(
|
|
150
|
+
{
|
|
151
|
+
id: "STORAGE_MONGODB_VECTOR_DISCONNECT_FAILED",
|
|
152
|
+
domain: ErrorDomain.STORAGE,
|
|
153
|
+
category: ErrorCategory.THIRD_PARTY
|
|
154
|
+
},
|
|
155
|
+
error
|
|
156
|
+
);
|
|
130
157
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
158
|
+
}
|
|
159
|
+
async createIndex({ indexName, dimension, metric = "cosine" }) {
|
|
160
|
+
let mongoMetric;
|
|
161
|
+
try {
|
|
162
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
163
|
+
throw new Error("Dimension must be a positive integer");
|
|
164
|
+
}
|
|
165
|
+
mongoMetric = this.mongoMetricMap[metric];
|
|
166
|
+
if (!mongoMetric) {
|
|
167
|
+
throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new MastraError(
|
|
171
|
+
{
|
|
172
|
+
id: "STORAGE_MONGODB_VECTOR_CREATE_INDEX_INVALID_ARGS",
|
|
173
|
+
domain: ErrorDomain.STORAGE,
|
|
174
|
+
category: ErrorCategory.USER,
|
|
175
|
+
details: {
|
|
176
|
+
indexName,
|
|
177
|
+
dimension,
|
|
178
|
+
metric
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
error
|
|
182
|
+
);
|
|
134
183
|
}
|
|
135
|
-
|
|
136
|
-
const indexNameInternal = `${indexName}_vector_index`;
|
|
137
|
-
const embeddingField = this.embeddingFieldName;
|
|
138
|
-
const numDimensions = dimension;
|
|
184
|
+
let collection;
|
|
139
185
|
try {
|
|
186
|
+
const collectionExists = await this.db.listCollections({ name: indexName }).hasNext();
|
|
187
|
+
if (!collectionExists) {
|
|
188
|
+
await this.db.createCollection(indexName);
|
|
189
|
+
}
|
|
190
|
+
collection = await this.getCollection(indexName);
|
|
191
|
+
const indexNameInternal = `${indexName}_vector_index`;
|
|
192
|
+
const embeddingField = this.embeddingFieldName;
|
|
193
|
+
const numDimensions = dimension;
|
|
140
194
|
await collection.createSearchIndex({
|
|
141
195
|
definition: {
|
|
142
196
|
fields: [
|
|
@@ -145,20 +199,66 @@ var MongoDBVector = class extends MastraVector {
|
|
|
145
199
|
path: embeddingField,
|
|
146
200
|
numDimensions,
|
|
147
201
|
similarity: mongoMetric
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: "filter",
|
|
205
|
+
path: "_id"
|
|
148
206
|
}
|
|
149
207
|
]
|
|
150
208
|
},
|
|
151
209
|
name: indexNameInternal,
|
|
152
210
|
type: "vectorSearch"
|
|
153
211
|
});
|
|
212
|
+
await collection.createSearchIndex({
|
|
213
|
+
definition: {
|
|
214
|
+
mappings: {
|
|
215
|
+
dynamic: true
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
name: `${indexName}_search_index`,
|
|
219
|
+
type: "search"
|
|
220
|
+
});
|
|
154
221
|
} catch (error) {
|
|
155
222
|
if (error.codeName !== "IndexAlreadyExists") {
|
|
156
|
-
throw
|
|
223
|
+
throw new MastraError(
|
|
224
|
+
{
|
|
225
|
+
id: "STORAGE_MONGODB_VECTOR_CREATE_INDEX_FAILED",
|
|
226
|
+
domain: ErrorDomain.STORAGE,
|
|
227
|
+
category: ErrorCategory.THIRD_PARTY
|
|
228
|
+
},
|
|
229
|
+
error
|
|
230
|
+
);
|
|
157
231
|
}
|
|
158
232
|
}
|
|
159
|
-
|
|
233
|
+
try {
|
|
234
|
+
await collection?.updateOne({ _id: "__index_metadata__" }, { $set: { dimension, metric } }, { upsert: true });
|
|
235
|
+
} catch (error) {
|
|
236
|
+
throw new MastraError(
|
|
237
|
+
{
|
|
238
|
+
id: "STORAGE_MONGODB_VECTOR_CREATE_INDEX_FAILED_STORE_METADATA",
|
|
239
|
+
domain: ErrorDomain.STORAGE,
|
|
240
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
241
|
+
details: {
|
|
242
|
+
indexName
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
error
|
|
246
|
+
);
|
|
247
|
+
}
|
|
160
248
|
}
|
|
161
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Waits for the index to be ready.
|
|
251
|
+
*
|
|
252
|
+
* @param {string} indexName - The name of the index to wait for
|
|
253
|
+
* @param {number} timeoutMs - The maximum time in milliseconds to wait for the index to be ready (default: 60000)
|
|
254
|
+
* @param {number} checkIntervalMs - The interval in milliseconds at which to check if the index is ready (default: 2000)
|
|
255
|
+
* @returns A promise that resolves when the index is ready
|
|
256
|
+
*/
|
|
257
|
+
async waitForIndexReady({
|
|
258
|
+
indexName,
|
|
259
|
+
timeoutMs = 6e4,
|
|
260
|
+
checkIntervalMs = 2e3
|
|
261
|
+
}) {
|
|
162
262
|
const collection = await this.getCollection(indexName, true);
|
|
163
263
|
const indexNameInternal = `${indexName}_vector_index`;
|
|
164
264
|
const startTime = Date.now();
|
|
@@ -173,83 +273,110 @@ var MongoDBVector = class extends MastraVector {
|
|
|
173
273
|
}
|
|
174
274
|
throw new Error(`Index "${indexNameInternal}" did not become ready within timeout`);
|
|
175
275
|
}
|
|
176
|
-
async upsert(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
updateOne: {
|
|
203
|
-
filter: { _id: id },
|
|
204
|
-
// '_id' is a string as per MongoDBDocument interface
|
|
205
|
-
update: { $set: updateDoc },
|
|
206
|
-
upsert: true
|
|
276
|
+
async upsert({ indexName, vectors, metadata, ids, documents }) {
|
|
277
|
+
try {
|
|
278
|
+
const collection = await this.getCollection(indexName);
|
|
279
|
+
this.collectionForValidation = collection;
|
|
280
|
+
const stats = await this.describeIndex({ indexName });
|
|
281
|
+
await this.validateVectorDimensions(vectors, stats.dimension);
|
|
282
|
+
const generatedIds = ids || vectors.map(() => v4());
|
|
283
|
+
const operations = vectors.map((vector, idx) => {
|
|
284
|
+
const id = generatedIds[idx];
|
|
285
|
+
const meta = metadata?.[idx] || {};
|
|
286
|
+
const doc = documents?.[idx];
|
|
287
|
+
const normalizedMeta = Object.keys(meta).reduce(
|
|
288
|
+
(acc, key) => {
|
|
289
|
+
acc[key] = meta[key] instanceof Date ? meta[key].toISOString() : meta[key];
|
|
290
|
+
return acc;
|
|
291
|
+
},
|
|
292
|
+
{}
|
|
293
|
+
);
|
|
294
|
+
const updateDoc = {
|
|
295
|
+
[this.embeddingFieldName]: vector,
|
|
296
|
+
[this.metadataFieldName]: normalizedMeta
|
|
297
|
+
};
|
|
298
|
+
if (doc !== void 0) {
|
|
299
|
+
updateDoc[this.documentFieldName] = doc;
|
|
207
300
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
301
|
+
return {
|
|
302
|
+
updateOne: {
|
|
303
|
+
filter: { _id: id },
|
|
304
|
+
// '_id' is a string as per MongoDBDocument interface
|
|
305
|
+
update: { $set: updateDoc },
|
|
306
|
+
upsert: true
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
await collection.bulkWrite(operations);
|
|
311
|
+
return generatedIds;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
throw new MastraError(
|
|
314
|
+
{
|
|
315
|
+
id: "STORAGE_MONGODB_VECTOR_UPSERT_FAILED",
|
|
316
|
+
domain: ErrorDomain.STORAGE,
|
|
317
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
318
|
+
details: {
|
|
319
|
+
indexName
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
error
|
|
323
|
+
);
|
|
324
|
+
}
|
|
212
325
|
}
|
|
213
|
-
async query(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
$
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
{
|
|
243
|
-
$project: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
...includeVector && { vector: `$${this.embeddingFieldName}` }
|
|
326
|
+
async query({
|
|
327
|
+
indexName,
|
|
328
|
+
queryVector,
|
|
329
|
+
topK = 10,
|
|
330
|
+
filter,
|
|
331
|
+
includeVector = false,
|
|
332
|
+
documentFilter
|
|
333
|
+
}) {
|
|
334
|
+
try {
|
|
335
|
+
const collection = await this.getCollection(indexName, true);
|
|
336
|
+
const indexNameInternal = `${indexName}_vector_index`;
|
|
337
|
+
const mongoFilter = this.transformFilter(filter);
|
|
338
|
+
const documentMongoFilter = documentFilter ? { [this.documentFieldName]: documentFilter } : {};
|
|
339
|
+
const transformedMongoFilter = this.transformMetadataFilter(mongoFilter);
|
|
340
|
+
let combinedFilter = {};
|
|
341
|
+
if (Object.keys(transformedMongoFilter).length > 0 && Object.keys(documentMongoFilter).length > 0) {
|
|
342
|
+
combinedFilter = { $and: [transformedMongoFilter, documentMongoFilter] };
|
|
343
|
+
} else if (Object.keys(transformedMongoFilter).length > 0) {
|
|
344
|
+
combinedFilter = transformedMongoFilter;
|
|
345
|
+
} else if (Object.keys(documentMongoFilter).length > 0) {
|
|
346
|
+
combinedFilter = documentMongoFilter;
|
|
347
|
+
}
|
|
348
|
+
const vectorSearch = {
|
|
349
|
+
index: indexNameInternal,
|
|
350
|
+
queryVector,
|
|
351
|
+
path: this.embeddingFieldName,
|
|
352
|
+
numCandidates: 100,
|
|
353
|
+
limit: topK
|
|
354
|
+
};
|
|
355
|
+
if (Object.keys(combinedFilter).length > 0) {
|
|
356
|
+
const candidateIds = await collection.aggregate([{ $match: combinedFilter }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
|
|
357
|
+
if (candidateIds.length > 0) {
|
|
358
|
+
vectorSearch.filter = { _id: { $in: candidateIds } };
|
|
359
|
+
} else {
|
|
360
|
+
return [];
|
|
249
361
|
}
|
|
250
362
|
}
|
|
251
|
-
|
|
252
|
-
|
|
363
|
+
const pipeline = [
|
|
364
|
+
{
|
|
365
|
+
$vectorSearch: vectorSearch
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
$set: { score: { $meta: "vectorSearchScore" } }
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
$project: {
|
|
372
|
+
_id: 1,
|
|
373
|
+
score: 1,
|
|
374
|
+
metadata: `$${this.metadataFieldName}`,
|
|
375
|
+
document: `$${this.documentFieldName}`,
|
|
376
|
+
...includeVector && { vector: `$${this.embeddingFieldName}` }
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
];
|
|
253
380
|
const results = await collection.aggregate(pipeline).toArray();
|
|
254
381
|
return results.map((result) => ({
|
|
255
382
|
id: result._id,
|
|
@@ -259,62 +386,161 @@ var MongoDBVector = class extends MastraVector {
|
|
|
259
386
|
document: result.document
|
|
260
387
|
}));
|
|
261
388
|
} catch (error) {
|
|
262
|
-
|
|
263
|
-
|
|
389
|
+
throw new MastraError(
|
|
390
|
+
{
|
|
391
|
+
id: "STORAGE_MONGODB_VECTOR_QUERY_FAILED",
|
|
392
|
+
domain: ErrorDomain.STORAGE,
|
|
393
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
394
|
+
details: {
|
|
395
|
+
indexName
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
error
|
|
399
|
+
);
|
|
264
400
|
}
|
|
265
401
|
}
|
|
266
402
|
async listIndexes() {
|
|
267
|
-
|
|
268
|
-
|
|
403
|
+
try {
|
|
404
|
+
const collections = await this.db.listCollections().toArray();
|
|
405
|
+
return collections.map((col) => col.name);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
throw new MastraError(
|
|
408
|
+
{
|
|
409
|
+
id: "STORAGE_MONGODB_VECTOR_LIST_INDEXES_FAILED",
|
|
410
|
+
domain: ErrorDomain.STORAGE,
|
|
411
|
+
category: ErrorCategory.THIRD_PARTY
|
|
412
|
+
},
|
|
413
|
+
error
|
|
414
|
+
);
|
|
415
|
+
}
|
|
269
416
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Retrieves statistics about a vector index.
|
|
419
|
+
*
|
|
420
|
+
* @param {string} indexName - The name of the index to describe
|
|
421
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
422
|
+
*/
|
|
423
|
+
async describeIndex({ indexName }) {
|
|
424
|
+
try {
|
|
425
|
+
const collection = await this.getCollection(indexName, true);
|
|
426
|
+
const count = await collection.countDocuments({ _id: { $ne: "__index_metadata__" } });
|
|
427
|
+
const metadataDoc = await collection.findOne({ _id: "__index_metadata__" });
|
|
428
|
+
const dimension = metadataDoc?.dimension || 0;
|
|
429
|
+
const metric = metadataDoc?.metric || "cosine";
|
|
430
|
+
return {
|
|
431
|
+
dimension,
|
|
432
|
+
count,
|
|
433
|
+
metric
|
|
434
|
+
};
|
|
435
|
+
} catch (error) {
|
|
436
|
+
throw new MastraError(
|
|
437
|
+
{
|
|
438
|
+
id: "STORAGE_MONGODB_VECTOR_DESCRIBE_INDEX_FAILED",
|
|
439
|
+
domain: ErrorDomain.STORAGE,
|
|
440
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
441
|
+
details: {
|
|
442
|
+
indexName
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
error
|
|
446
|
+
);
|
|
447
|
+
}
|
|
281
448
|
}
|
|
282
|
-
async deleteIndex(indexName) {
|
|
449
|
+
async deleteIndex({ indexName }) {
|
|
283
450
|
const collection = await this.getCollection(indexName, false);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
451
|
+
try {
|
|
452
|
+
if (collection) {
|
|
453
|
+
await collection.drop();
|
|
454
|
+
this.collections.delete(indexName);
|
|
455
|
+
} else {
|
|
456
|
+
throw new Error(`Index (Collection) "${indexName}" does not exist`);
|
|
457
|
+
}
|
|
458
|
+
} catch (error) {
|
|
459
|
+
throw new MastraError(
|
|
460
|
+
{
|
|
461
|
+
id: "STORAGE_MONGODB_VECTOR_DELETE_INDEX_FAILED",
|
|
462
|
+
domain: ErrorDomain.STORAGE,
|
|
463
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
464
|
+
details: {
|
|
465
|
+
indexName
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
error
|
|
469
|
+
);
|
|
289
470
|
}
|
|
290
471
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
472
|
+
/**
|
|
473
|
+
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
474
|
+
* @param indexName - The name of the index containing the vector.
|
|
475
|
+
* @param id - The ID of the vector to update.
|
|
476
|
+
* @param update - An object containing the vector and/or metadata to update.
|
|
477
|
+
* @param update.vector - An optional array of numbers representing the new vector.
|
|
478
|
+
* @param update.metadata - An optional record containing the new metadata.
|
|
479
|
+
* @returns A promise that resolves when the update is complete.
|
|
480
|
+
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
481
|
+
*/
|
|
482
|
+
async updateVector({ indexName, id, update }) {
|
|
483
|
+
try {
|
|
484
|
+
if (!update.vector && !update.metadata) {
|
|
485
|
+
throw new Error("No updates provided");
|
|
486
|
+
}
|
|
487
|
+
const collection = await this.getCollection(indexName, true);
|
|
488
|
+
const updateDoc = {};
|
|
489
|
+
if (update.vector) {
|
|
490
|
+
const stats = await this.describeIndex({ indexName });
|
|
491
|
+
await this.validateVectorDimensions([update.vector], stats.dimension);
|
|
492
|
+
updateDoc[this.embeddingFieldName] = update.vector;
|
|
493
|
+
}
|
|
494
|
+
if (update.metadata) {
|
|
495
|
+
const normalizedMeta = Object.keys(update.metadata).reduce(
|
|
496
|
+
(acc, key) => {
|
|
497
|
+
acc[key] = update.metadata[key] instanceof Date ? update.metadata[key].toISOString() : update.metadata[key];
|
|
498
|
+
return acc;
|
|
499
|
+
},
|
|
500
|
+
{}
|
|
501
|
+
);
|
|
502
|
+
updateDoc[this.metadataFieldName] = normalizedMeta;
|
|
503
|
+
}
|
|
504
|
+
await collection.findOneAndUpdate({ _id: id }, { $set: updateDoc });
|
|
505
|
+
} catch (error) {
|
|
506
|
+
throw new MastraError(
|
|
507
|
+
{
|
|
508
|
+
id: "STORAGE_MONGODB_VECTOR_UPDATE_VECTOR_FAILED",
|
|
509
|
+
domain: ErrorDomain.STORAGE,
|
|
510
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
511
|
+
details: {
|
|
512
|
+
indexName,
|
|
513
|
+
id
|
|
514
|
+
}
|
|
305
515
|
},
|
|
306
|
-
|
|
516
|
+
error
|
|
307
517
|
);
|
|
308
|
-
updateDoc[this.metadataFieldName] = normalizedMeta;
|
|
309
518
|
}
|
|
310
|
-
await collection.findOneAndUpdate({ _id: id }, { $set: updateDoc });
|
|
311
519
|
}
|
|
312
|
-
|
|
520
|
+
/**
|
|
521
|
+
* Deletes a vector by its ID.
|
|
522
|
+
* @param indexName - The name of the index containing the vector.
|
|
523
|
+
* @param id - The ID of the vector to delete.
|
|
524
|
+
* @returns A promise that resolves when the deletion is complete.
|
|
525
|
+
* @throws Will throw an error if the deletion operation fails.
|
|
526
|
+
*/
|
|
527
|
+
async deleteVector({ indexName, id }) {
|
|
313
528
|
try {
|
|
314
529
|
const collection = await this.getCollection(indexName, true);
|
|
315
530
|
await collection.deleteOne({ _id: id });
|
|
316
531
|
} catch (error) {
|
|
317
|
-
throw new
|
|
532
|
+
throw new MastraError(
|
|
533
|
+
{
|
|
534
|
+
id: "STORAGE_MONGODB_VECTOR_DELETE_VECTOR_FAILED",
|
|
535
|
+
domain: ErrorDomain.STORAGE,
|
|
536
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
537
|
+
details: {
|
|
538
|
+
indexName,
|
|
539
|
+
id
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
error
|
|
543
|
+
);
|
|
318
544
|
}
|
|
319
545
|
}
|
|
320
546
|
// Private methods
|
|
@@ -354,6 +580,2142 @@ var MongoDBVector = class extends MastraVector {
|
|
|
354
580
|
if (!filter) return {};
|
|
355
581
|
return translator.translate(filter);
|
|
356
582
|
}
|
|
583
|
+
/**
|
|
584
|
+
* Transform metadata field filters to use MongoDB dot notation.
|
|
585
|
+
* Fields that are stored in the metadata subdocument need to be prefixed with 'metadata.'
|
|
586
|
+
* This handles filters from the Memory system which expects direct field access.
|
|
587
|
+
*
|
|
588
|
+
* @param filter - The filter object to transform
|
|
589
|
+
* @returns Transformed filter with metadata fields properly prefixed
|
|
590
|
+
*/
|
|
591
|
+
transformMetadataFilter(filter) {
|
|
592
|
+
if (!filter || typeof filter !== "object") return filter;
|
|
593
|
+
const transformed = {};
|
|
594
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
595
|
+
if (key.startsWith("$")) {
|
|
596
|
+
if (Array.isArray(value)) {
|
|
597
|
+
transformed[key] = value.map((item) => this.transformMetadataFilter(item));
|
|
598
|
+
} else {
|
|
599
|
+
transformed[key] = this.transformMetadataFilter(value);
|
|
600
|
+
}
|
|
601
|
+
} else if (key.startsWith("metadata.")) {
|
|
602
|
+
transformed[key] = value;
|
|
603
|
+
} else if (this.isMetadataField(key)) {
|
|
604
|
+
transformed[`metadata.${key}`] = value;
|
|
605
|
+
} else {
|
|
606
|
+
transformed[key] = value;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return transformed;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Determine if a field should be treated as a metadata field.
|
|
613
|
+
* Common metadata fields include thread_id, resource_id, message_id, and any field
|
|
614
|
+
* that doesn't start with underscore (MongoDB system fields).
|
|
615
|
+
*/
|
|
616
|
+
isMetadataField(key) {
|
|
617
|
+
if (key.startsWith("_")) return false;
|
|
618
|
+
const documentFields = ["_id", this.embeddingFieldName, this.documentFieldName];
|
|
619
|
+
if (documentFields.includes(key)) return false;
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
var MongoDBConnector = class _MongoDBConnector {
|
|
624
|
+
#client;
|
|
625
|
+
#dbName;
|
|
626
|
+
#handler;
|
|
627
|
+
#isConnected;
|
|
628
|
+
#db;
|
|
629
|
+
constructor(options) {
|
|
630
|
+
this.#client = options.client;
|
|
631
|
+
this.#dbName = options.dbName;
|
|
632
|
+
this.#handler = options.handler;
|
|
633
|
+
this.#isConnected = false;
|
|
634
|
+
}
|
|
635
|
+
static fromDatabaseConfig(config) {
|
|
636
|
+
if (!config.url?.trim().length) {
|
|
637
|
+
throw new Error(
|
|
638
|
+
"MongoDBStore: url must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
if (!config.dbName?.trim().length) {
|
|
642
|
+
throw new Error(
|
|
643
|
+
"MongoDBStore: dbName must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
const client = new MongoClient(config.url, {
|
|
647
|
+
...config.options,
|
|
648
|
+
driverInfo: {
|
|
649
|
+
name: "mastra-storage",
|
|
650
|
+
version: package_default.version
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
return new _MongoDBConnector({
|
|
654
|
+
client,
|
|
655
|
+
dbName: config.dbName,
|
|
656
|
+
handler: void 0
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
static fromConnectionHandler(handler) {
|
|
660
|
+
return new _MongoDBConnector({
|
|
661
|
+
client: void 0,
|
|
662
|
+
dbName: void 0,
|
|
663
|
+
handler
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
async getConnection() {
|
|
667
|
+
if (this.#client) {
|
|
668
|
+
if (this.#isConnected && this.#db) {
|
|
669
|
+
return this.#db;
|
|
670
|
+
}
|
|
671
|
+
await this.#client.connect();
|
|
672
|
+
this.#db = this.#client.db(this.#dbName);
|
|
673
|
+
this.#isConnected = true;
|
|
674
|
+
return this.#db;
|
|
675
|
+
}
|
|
676
|
+
throw new Error("MongoDBStore: client cannot be empty. Check your MongoDBConnector configuration.");
|
|
677
|
+
}
|
|
678
|
+
async getCollection(collectionName) {
|
|
679
|
+
if (this.#handler) {
|
|
680
|
+
return this.#handler.getCollection(collectionName);
|
|
681
|
+
}
|
|
682
|
+
const db = await this.getConnection();
|
|
683
|
+
return db.collection(collectionName);
|
|
684
|
+
}
|
|
685
|
+
async close() {
|
|
686
|
+
if (this.#client) {
|
|
687
|
+
await this.#client.close();
|
|
688
|
+
this.#isConnected = false;
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (this.#handler) {
|
|
692
|
+
await this.#handler.close();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
// src/storage/domains/utils.ts
|
|
698
|
+
function formatDateForMongoDB(date) {
|
|
699
|
+
return typeof date === "string" ? new Date(date) : date;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/storage/domains/memory/index.ts
|
|
703
|
+
var MemoryStorageMongoDB = class extends MemoryStorage {
|
|
704
|
+
operations;
|
|
705
|
+
constructor({ operations }) {
|
|
706
|
+
super();
|
|
707
|
+
this.operations = operations;
|
|
708
|
+
}
|
|
709
|
+
parseRow(row) {
|
|
710
|
+
let content = row.content;
|
|
711
|
+
if (typeof content === "string") {
|
|
712
|
+
try {
|
|
713
|
+
content = JSON.parse(content);
|
|
714
|
+
} catch {
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const result = {
|
|
718
|
+
id: row.id,
|
|
719
|
+
content,
|
|
720
|
+
role: row.role,
|
|
721
|
+
createdAt: formatDateForMongoDB(row.createdAt),
|
|
722
|
+
threadId: row.thread_id,
|
|
723
|
+
resourceId: row.resourceId
|
|
724
|
+
};
|
|
725
|
+
if (row.type && row.type !== "v2") result.type = row.type;
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
async _getIncludedMessages({
|
|
729
|
+
threadId,
|
|
730
|
+
selectBy
|
|
731
|
+
}) {
|
|
732
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
733
|
+
const include = selectBy?.include;
|
|
734
|
+
if (!include) return null;
|
|
735
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
736
|
+
const includedMessages = [];
|
|
737
|
+
for (const inc of include) {
|
|
738
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
739
|
+
const searchThreadId = inc.threadId || threadId;
|
|
740
|
+
const allMessages = await collection.find({ thread_id: searchThreadId }).sort({ createdAt: 1 }).toArray();
|
|
741
|
+
const targetIndex = allMessages.findIndex((msg) => msg.id === id);
|
|
742
|
+
if (targetIndex === -1) continue;
|
|
743
|
+
const startIndex = Math.max(0, targetIndex - withPreviousMessages);
|
|
744
|
+
const endIndex = Math.min(allMessages.length - 1, targetIndex + withNextMessages);
|
|
745
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
746
|
+
includedMessages.push(allMessages[i]);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
const seen = /* @__PURE__ */ new Set();
|
|
750
|
+
const dedupedMessages = includedMessages.filter((msg) => {
|
|
751
|
+
if (seen.has(msg.id)) return false;
|
|
752
|
+
seen.add(msg.id);
|
|
753
|
+
return true;
|
|
754
|
+
});
|
|
755
|
+
return dedupedMessages.map((row) => this.parseRow(row));
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* @deprecated use listMessages instead for paginated results.
|
|
759
|
+
*/
|
|
760
|
+
async getMessages({
|
|
761
|
+
threadId,
|
|
762
|
+
resourceId,
|
|
763
|
+
selectBy
|
|
764
|
+
}) {
|
|
765
|
+
try {
|
|
766
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
767
|
+
const messages = [];
|
|
768
|
+
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
769
|
+
if (selectBy?.include?.length) {
|
|
770
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
771
|
+
if (includeMessages) {
|
|
772
|
+
messages.push(...includeMessages);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
const excludeIds = messages.map((m) => m.id);
|
|
776
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
777
|
+
const query = { thread_id: threadId };
|
|
778
|
+
if (resourceId) {
|
|
779
|
+
query.resourceId = resourceId;
|
|
780
|
+
}
|
|
781
|
+
if (excludeIds.length > 0) {
|
|
782
|
+
query.id = { $nin: excludeIds };
|
|
783
|
+
}
|
|
784
|
+
if (limit > 0) {
|
|
785
|
+
const remainingMessages = await collection.find(query).sort({ createdAt: -1 }).limit(limit).toArray();
|
|
786
|
+
messages.push(...remainingMessages.map((row) => this.parseRow(row)));
|
|
787
|
+
}
|
|
788
|
+
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
789
|
+
const list = new MessageList().add(messages, "memory");
|
|
790
|
+
return { messages: list.get.all.db() };
|
|
791
|
+
} catch (error) {
|
|
792
|
+
throw new MastraError(
|
|
793
|
+
{
|
|
794
|
+
id: "MONGODB_STORE_GET_MESSAGES_FAILED",
|
|
795
|
+
domain: ErrorDomain.STORAGE,
|
|
796
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
797
|
+
details: { threadId, resourceId: resourceId ?? "" }
|
|
798
|
+
},
|
|
799
|
+
error
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
async listMessagesById({ messageIds }) {
|
|
804
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
805
|
+
try {
|
|
806
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
807
|
+
const rawMessages = await collection.find({ id: { $in: messageIds } }).sort({ createdAt: -1 }).toArray();
|
|
808
|
+
const list = new MessageList().add(
|
|
809
|
+
rawMessages.map(this.parseRow),
|
|
810
|
+
"memory"
|
|
811
|
+
);
|
|
812
|
+
return { messages: list.get.all.db() };
|
|
813
|
+
} catch (error) {
|
|
814
|
+
throw new MastraError(
|
|
815
|
+
{
|
|
816
|
+
id: "MONGODB_STORE_LIST_MESSAGES_BY_ID_FAILED",
|
|
817
|
+
domain: ErrorDomain.STORAGE,
|
|
818
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
819
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
820
|
+
},
|
|
821
|
+
error
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async listMessages(args) {
|
|
826
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
827
|
+
if (!threadId.trim()) {
|
|
828
|
+
throw new MastraError(
|
|
829
|
+
{
|
|
830
|
+
id: "STORAGE_MONGODB_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
831
|
+
domain: ErrorDomain.STORAGE,
|
|
832
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
833
|
+
details: { threadId }
|
|
834
|
+
},
|
|
835
|
+
new Error("threadId must be a non-empty string")
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
if (page < 0) {
|
|
839
|
+
throw new MastraError(
|
|
840
|
+
{
|
|
841
|
+
id: "STORAGE_MONGODB_LIST_MESSAGES_INVALID_PAGE",
|
|
842
|
+
domain: ErrorDomain.STORAGE,
|
|
843
|
+
category: ErrorCategory.USER,
|
|
844
|
+
details: { page }
|
|
845
|
+
},
|
|
846
|
+
new Error("page must be >= 0")
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
const perPage = normalizePerPage(perPageInput, 40);
|
|
850
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
851
|
+
try {
|
|
852
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
853
|
+
const sortOrder = direction === "ASC" ? 1 : -1;
|
|
854
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
855
|
+
const query = { thread_id: threadId };
|
|
856
|
+
if (resourceId) {
|
|
857
|
+
query.resourceId = resourceId;
|
|
858
|
+
}
|
|
859
|
+
if (filter?.dateRange?.start) {
|
|
860
|
+
query.createdAt = { ...query.createdAt, $gte: filter.dateRange.start };
|
|
861
|
+
}
|
|
862
|
+
if (filter?.dateRange?.end) {
|
|
863
|
+
query.createdAt = { ...query.createdAt, $lte: filter.dateRange.end };
|
|
864
|
+
}
|
|
865
|
+
const total = await collection.countDocuments(query);
|
|
866
|
+
const messages = [];
|
|
867
|
+
if (perPage !== 0) {
|
|
868
|
+
const sortObj = { [field]: sortOrder };
|
|
869
|
+
let cursor = collection.find(query).sort(sortObj).skip(offset);
|
|
870
|
+
if (perPageInput !== false) {
|
|
871
|
+
cursor = cursor.limit(perPage);
|
|
872
|
+
}
|
|
873
|
+
const dataResult = await cursor.toArray();
|
|
874
|
+
messages.push(...dataResult.map((row) => this.parseRow(row)));
|
|
875
|
+
}
|
|
876
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
877
|
+
return {
|
|
878
|
+
messages: [],
|
|
879
|
+
total: 0,
|
|
880
|
+
page,
|
|
881
|
+
perPage: perPageForResponse,
|
|
882
|
+
hasMore: false
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
886
|
+
if (include && include.length > 0) {
|
|
887
|
+
const selectBy = { include };
|
|
888
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
889
|
+
if (includeMessages) {
|
|
890
|
+
for (const includeMsg of includeMessages) {
|
|
891
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
892
|
+
messages.push(includeMsg);
|
|
893
|
+
messageIds.add(includeMsg.id);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
const list = new MessageList().add(messages, "memory");
|
|
899
|
+
let finalMessages = list.get.all.db();
|
|
900
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
901
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
902
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
903
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
904
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
905
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
906
|
+
}
|
|
907
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
908
|
+
});
|
|
909
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
910
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
911
|
+
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
|
|
912
|
+
return {
|
|
913
|
+
messages: finalMessages,
|
|
914
|
+
total,
|
|
915
|
+
page,
|
|
916
|
+
perPage: perPageForResponse,
|
|
917
|
+
hasMore
|
|
918
|
+
};
|
|
919
|
+
} catch (error) {
|
|
920
|
+
const mastraError = new MastraError(
|
|
921
|
+
{
|
|
922
|
+
id: "MONGODB_STORE_LIST_MESSAGES_FAILED",
|
|
923
|
+
domain: ErrorDomain.STORAGE,
|
|
924
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
925
|
+
details: {
|
|
926
|
+
threadId,
|
|
927
|
+
resourceId: resourceId ?? ""
|
|
928
|
+
}
|
|
929
|
+
},
|
|
930
|
+
error
|
|
931
|
+
);
|
|
932
|
+
this.logger?.error?.(mastraError.toString());
|
|
933
|
+
this.logger?.trackException?.(mastraError);
|
|
934
|
+
return {
|
|
935
|
+
messages: [],
|
|
936
|
+
total: 0,
|
|
937
|
+
page,
|
|
938
|
+
perPage: perPageForResponse,
|
|
939
|
+
hasMore: false
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
async saveMessages({ messages }) {
|
|
944
|
+
if (messages.length === 0) return { messages: [] };
|
|
945
|
+
try {
|
|
946
|
+
const threadId = messages[0]?.threadId;
|
|
947
|
+
if (!threadId) {
|
|
948
|
+
throw new Error("Thread ID is required");
|
|
949
|
+
}
|
|
950
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
951
|
+
const threadsCollection = await this.operations.getCollection(TABLE_THREADS);
|
|
952
|
+
const messagesToInsert = messages.map((message) => {
|
|
953
|
+
const time = message.createdAt || /* @__PURE__ */ new Date();
|
|
954
|
+
if (!message.threadId) {
|
|
955
|
+
throw new Error(
|
|
956
|
+
"Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred."
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
if (!message.resourceId) {
|
|
960
|
+
throw new Error(
|
|
961
|
+
"Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred."
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return {
|
|
965
|
+
updateOne: {
|
|
966
|
+
filter: { id: message.id },
|
|
967
|
+
update: {
|
|
968
|
+
$set: {
|
|
969
|
+
id: message.id,
|
|
970
|
+
thread_id: message.threadId,
|
|
971
|
+
content: typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
|
|
972
|
+
role: message.role,
|
|
973
|
+
type: message.type || "v2",
|
|
974
|
+
createdAt: formatDateForMongoDB(time),
|
|
975
|
+
resourceId: message.resourceId
|
|
976
|
+
}
|
|
977
|
+
},
|
|
978
|
+
upsert: true
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
});
|
|
982
|
+
await Promise.all([
|
|
983
|
+
collection.bulkWrite(messagesToInsert),
|
|
984
|
+
threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
|
|
985
|
+
]);
|
|
986
|
+
const list = new MessageList().add(messages, "memory");
|
|
987
|
+
return { messages: list.get.all.db() };
|
|
988
|
+
} catch (error) {
|
|
989
|
+
throw new MastraError(
|
|
990
|
+
{
|
|
991
|
+
id: "MONGODB_STORE_SAVE_MESSAGES_FAILED",
|
|
992
|
+
domain: ErrorDomain.STORAGE,
|
|
993
|
+
category: ErrorCategory.THIRD_PARTY
|
|
994
|
+
},
|
|
995
|
+
error
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
async updateMessages({
|
|
1000
|
+
messages
|
|
1001
|
+
}) {
|
|
1002
|
+
if (messages.length === 0) {
|
|
1003
|
+
return [];
|
|
1004
|
+
}
|
|
1005
|
+
const messageIds = messages.map((m) => m.id);
|
|
1006
|
+
const collection = await this.operations.getCollection(TABLE_MESSAGES);
|
|
1007
|
+
const existingMessages = await collection.find({ id: { $in: messageIds } }).toArray();
|
|
1008
|
+
const existingMessagesParsed = existingMessages.map((msg) => this.parseRow(msg));
|
|
1009
|
+
if (existingMessagesParsed.length === 0) {
|
|
1010
|
+
return [];
|
|
1011
|
+
}
|
|
1012
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1013
|
+
const bulkOps = [];
|
|
1014
|
+
for (const existingMessage of existingMessagesParsed) {
|
|
1015
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1016
|
+
if (!updatePayload) continue;
|
|
1017
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1018
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1019
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1020
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1021
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1022
|
+
}
|
|
1023
|
+
const updateDoc = {};
|
|
1024
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1025
|
+
if (updatableFields.content) {
|
|
1026
|
+
const newContent = {
|
|
1027
|
+
...existingMessage.content,
|
|
1028
|
+
...updatableFields.content,
|
|
1029
|
+
// Deep merge metadata if it exists on both
|
|
1030
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1031
|
+
metadata: {
|
|
1032
|
+
...existingMessage.content.metadata,
|
|
1033
|
+
...updatableFields.content.metadata
|
|
1034
|
+
}
|
|
1035
|
+
} : {}
|
|
1036
|
+
};
|
|
1037
|
+
updateDoc.content = JSON.stringify(newContent);
|
|
1038
|
+
delete updatableFields.content;
|
|
1039
|
+
}
|
|
1040
|
+
for (const key in updatableFields) {
|
|
1041
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1042
|
+
const dbKey = key === "threadId" ? "thread_id" : key;
|
|
1043
|
+
let value = updatableFields[key];
|
|
1044
|
+
if (typeof value === "object" && value !== null) {
|
|
1045
|
+
value = JSON.stringify(value);
|
|
1046
|
+
}
|
|
1047
|
+
updateDoc[dbKey] = value;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (Object.keys(updateDoc).length > 0) {
|
|
1051
|
+
bulkOps.push({
|
|
1052
|
+
updateOne: {
|
|
1053
|
+
filter: { id },
|
|
1054
|
+
update: { $set: updateDoc }
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (bulkOps.length > 0) {
|
|
1060
|
+
await collection.bulkWrite(bulkOps);
|
|
1061
|
+
}
|
|
1062
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1063
|
+
const threadsCollection = await this.operations.getCollection(TABLE_THREADS);
|
|
1064
|
+
await threadsCollection.updateMany(
|
|
1065
|
+
{ id: { $in: Array.from(threadIdsToUpdate) } },
|
|
1066
|
+
{ $set: { updatedAt: /* @__PURE__ */ new Date() } }
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
const updatedMessages = await collection.find({ id: { $in: messageIds } }).toArray();
|
|
1070
|
+
return updatedMessages.map((row) => this.parseRow(row));
|
|
1071
|
+
}
|
|
1072
|
+
async getResourceById({ resourceId }) {
|
|
1073
|
+
try {
|
|
1074
|
+
const collection = await this.operations.getCollection(TABLE_RESOURCES);
|
|
1075
|
+
const result = await collection.findOne({ id: resourceId });
|
|
1076
|
+
if (!result) {
|
|
1077
|
+
return null;
|
|
1078
|
+
}
|
|
1079
|
+
return {
|
|
1080
|
+
id: result.id,
|
|
1081
|
+
workingMemory: result.workingMemory || "",
|
|
1082
|
+
metadata: typeof result.metadata === "string" ? safelyParseJSON(result.metadata) : result.metadata,
|
|
1083
|
+
createdAt: formatDateForMongoDB(result.createdAt),
|
|
1084
|
+
updatedAt: formatDateForMongoDB(result.updatedAt)
|
|
1085
|
+
};
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
throw new MastraError(
|
|
1088
|
+
{
|
|
1089
|
+
id: "STORAGE_MONGODB_STORE_GET_RESOURCE_BY_ID_FAILED",
|
|
1090
|
+
domain: ErrorDomain.STORAGE,
|
|
1091
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1092
|
+
details: { resourceId }
|
|
1093
|
+
},
|
|
1094
|
+
error
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
async saveResource({ resource }) {
|
|
1099
|
+
try {
|
|
1100
|
+
const collection = await this.operations.getCollection(TABLE_RESOURCES);
|
|
1101
|
+
await collection.updateOne(
|
|
1102
|
+
{ id: resource.id },
|
|
1103
|
+
{
|
|
1104
|
+
$set: {
|
|
1105
|
+
...resource,
|
|
1106
|
+
metadata: JSON.stringify(resource.metadata)
|
|
1107
|
+
}
|
|
1108
|
+
},
|
|
1109
|
+
{ upsert: true }
|
|
1110
|
+
);
|
|
1111
|
+
return resource;
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
throw new MastraError(
|
|
1114
|
+
{
|
|
1115
|
+
id: "STORAGE_MONGODB_STORE_SAVE_RESOURCE_FAILED",
|
|
1116
|
+
domain: ErrorDomain.STORAGE,
|
|
1117
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1118
|
+
details: { resourceId: resource.id }
|
|
1119
|
+
},
|
|
1120
|
+
error
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
async updateResource({
|
|
1125
|
+
resourceId,
|
|
1126
|
+
workingMemory,
|
|
1127
|
+
metadata
|
|
1128
|
+
}) {
|
|
1129
|
+
try {
|
|
1130
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1131
|
+
if (!existingResource) {
|
|
1132
|
+
const newResource = {
|
|
1133
|
+
id: resourceId,
|
|
1134
|
+
workingMemory: workingMemory || "",
|
|
1135
|
+
metadata: metadata || {},
|
|
1136
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1137
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1138
|
+
};
|
|
1139
|
+
return this.saveResource({ resource: newResource });
|
|
1140
|
+
}
|
|
1141
|
+
const updatedResource = {
|
|
1142
|
+
...existingResource,
|
|
1143
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1144
|
+
metadata: metadata ? { ...existingResource.metadata, ...metadata } : existingResource.metadata,
|
|
1145
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1146
|
+
};
|
|
1147
|
+
const collection = await this.operations.getCollection(TABLE_RESOURCES);
|
|
1148
|
+
const updateDoc = { updatedAt: updatedResource.updatedAt };
|
|
1149
|
+
if (workingMemory !== void 0) {
|
|
1150
|
+
updateDoc.workingMemory = workingMemory;
|
|
1151
|
+
}
|
|
1152
|
+
if (metadata) {
|
|
1153
|
+
updateDoc.metadata = JSON.stringify(updatedResource.metadata);
|
|
1154
|
+
}
|
|
1155
|
+
await collection.updateOne({ id: resourceId }, { $set: updateDoc });
|
|
1156
|
+
return updatedResource;
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
throw new MastraError(
|
|
1159
|
+
{
|
|
1160
|
+
id: "STORAGE_MONGODB_STORE_UPDATE_RESOURCE_FAILED",
|
|
1161
|
+
domain: ErrorDomain.STORAGE,
|
|
1162
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1163
|
+
details: { resourceId }
|
|
1164
|
+
},
|
|
1165
|
+
error
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
async getThreadById({ threadId }) {
|
|
1170
|
+
try {
|
|
1171
|
+
const collection = await this.operations.getCollection(TABLE_THREADS);
|
|
1172
|
+
const result = await collection.findOne({ id: threadId });
|
|
1173
|
+
if (!result) {
|
|
1174
|
+
return null;
|
|
1175
|
+
}
|
|
1176
|
+
return {
|
|
1177
|
+
...result,
|
|
1178
|
+
metadata: typeof result.metadata === "string" ? safelyParseJSON(result.metadata) : result.metadata
|
|
1179
|
+
};
|
|
1180
|
+
} catch (error) {
|
|
1181
|
+
throw new MastraError(
|
|
1182
|
+
{
|
|
1183
|
+
id: "STORAGE_MONGODB_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1184
|
+
domain: ErrorDomain.STORAGE,
|
|
1185
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1186
|
+
details: { threadId }
|
|
1187
|
+
},
|
|
1188
|
+
error
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
async listThreadsByResourceId(args) {
|
|
1193
|
+
try {
|
|
1194
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
1195
|
+
if (page < 0) {
|
|
1196
|
+
throw new MastraError(
|
|
1197
|
+
{
|
|
1198
|
+
id: "STORAGE_MONGODB_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
1199
|
+
domain: ErrorDomain.STORAGE,
|
|
1200
|
+
category: ErrorCategory.USER,
|
|
1201
|
+
details: { page }
|
|
1202
|
+
},
|
|
1203
|
+
new Error("page must be >= 0")
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
1207
|
+
const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
1208
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
1209
|
+
const collection = await this.operations.getCollection(TABLE_THREADS);
|
|
1210
|
+
const query = { resourceId };
|
|
1211
|
+
const total = await collection.countDocuments(query);
|
|
1212
|
+
if (perPage === 0) {
|
|
1213
|
+
return {
|
|
1214
|
+
threads: [],
|
|
1215
|
+
total,
|
|
1216
|
+
page,
|
|
1217
|
+
perPage: perPageForResponse,
|
|
1218
|
+
hasMore: offset < total
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
const sortOrder = direction === "ASC" ? 1 : -1;
|
|
1222
|
+
let cursor = collection.find(query).sort({ [field]: sortOrder }).skip(offset);
|
|
1223
|
+
if (perPageInput !== false) {
|
|
1224
|
+
cursor = cursor.limit(perPage);
|
|
1225
|
+
}
|
|
1226
|
+
const threads = await cursor.toArray();
|
|
1227
|
+
return {
|
|
1228
|
+
threads: threads.map((thread) => ({
|
|
1229
|
+
id: thread.id,
|
|
1230
|
+
title: thread.title,
|
|
1231
|
+
resourceId: thread.resourceId,
|
|
1232
|
+
createdAt: formatDateForMongoDB(thread.createdAt),
|
|
1233
|
+
updatedAt: formatDateForMongoDB(thread.updatedAt),
|
|
1234
|
+
metadata: thread.metadata || {}
|
|
1235
|
+
})),
|
|
1236
|
+
total,
|
|
1237
|
+
page,
|
|
1238
|
+
perPage: perPageForResponse,
|
|
1239
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
1240
|
+
};
|
|
1241
|
+
} catch (error) {
|
|
1242
|
+
throw new MastraError(
|
|
1243
|
+
{
|
|
1244
|
+
id: "MONGODB_STORE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1245
|
+
domain: ErrorDomain.STORAGE,
|
|
1246
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1247
|
+
details: { resourceId: args.resourceId }
|
|
1248
|
+
},
|
|
1249
|
+
error
|
|
1250
|
+
);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
async saveThread({ thread }) {
|
|
1254
|
+
try {
|
|
1255
|
+
const collection = await this.operations.getCollection(TABLE_THREADS);
|
|
1256
|
+
await collection.updateOne(
|
|
1257
|
+
{ id: thread.id },
|
|
1258
|
+
{
|
|
1259
|
+
$set: {
|
|
1260
|
+
...thread,
|
|
1261
|
+
metadata: thread.metadata
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
{ upsert: true }
|
|
1265
|
+
);
|
|
1266
|
+
return thread;
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
throw new MastraError(
|
|
1269
|
+
{
|
|
1270
|
+
id: "STORAGE_MONGODB_STORE_SAVE_THREAD_FAILED",
|
|
1271
|
+
domain: ErrorDomain.STORAGE,
|
|
1272
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1273
|
+
details: { threadId: thread.id }
|
|
1274
|
+
},
|
|
1275
|
+
error
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
async updateThread({
|
|
1280
|
+
id,
|
|
1281
|
+
title,
|
|
1282
|
+
metadata
|
|
1283
|
+
}) {
|
|
1284
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
1285
|
+
if (!thread) {
|
|
1286
|
+
throw new MastraError({
|
|
1287
|
+
id: "STORAGE_MONGODB_STORE_UPDATE_THREAD_NOT_FOUND",
|
|
1288
|
+
domain: ErrorDomain.STORAGE,
|
|
1289
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1290
|
+
details: { threadId: id, status: 404 },
|
|
1291
|
+
text: `Thread ${id} not found`
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
const updatedThread = {
|
|
1295
|
+
...thread,
|
|
1296
|
+
title,
|
|
1297
|
+
metadata: {
|
|
1298
|
+
...thread.metadata,
|
|
1299
|
+
...metadata
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
try {
|
|
1303
|
+
const collection = await this.operations.getCollection(TABLE_THREADS);
|
|
1304
|
+
await collection.updateOne(
|
|
1305
|
+
{ id },
|
|
1306
|
+
{
|
|
1307
|
+
$set: {
|
|
1308
|
+
title,
|
|
1309
|
+
metadata: updatedThread.metadata
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
);
|
|
1313
|
+
} catch (error) {
|
|
1314
|
+
throw new MastraError(
|
|
1315
|
+
{
|
|
1316
|
+
id: "STORAGE_MONGODB_STORE_UPDATE_THREAD_FAILED",
|
|
1317
|
+
domain: ErrorDomain.STORAGE,
|
|
1318
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1319
|
+
details: { threadId: id }
|
|
1320
|
+
},
|
|
1321
|
+
error
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
return updatedThread;
|
|
1325
|
+
}
|
|
1326
|
+
async deleteThread({ threadId }) {
|
|
1327
|
+
try {
|
|
1328
|
+
const collectionMessages = await this.operations.getCollection(TABLE_MESSAGES);
|
|
1329
|
+
await collectionMessages.deleteMany({ thread_id: threadId });
|
|
1330
|
+
const collectionThreads = await this.operations.getCollection(TABLE_THREADS);
|
|
1331
|
+
await collectionThreads.deleteOne({ id: threadId });
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
throw new MastraError(
|
|
1334
|
+
{
|
|
1335
|
+
id: "STORAGE_MONGODB_STORE_DELETE_THREAD_FAILED",
|
|
1336
|
+
domain: ErrorDomain.STORAGE,
|
|
1337
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1338
|
+
details: { threadId }
|
|
1339
|
+
},
|
|
1340
|
+
error
|
|
1341
|
+
);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
var ObservabilityMongoDB = class extends ObservabilityStorage {
|
|
1346
|
+
operations;
|
|
1347
|
+
constructor({ operations }) {
|
|
1348
|
+
super();
|
|
1349
|
+
this.operations = operations;
|
|
1350
|
+
}
|
|
1351
|
+
get aiTracingStrategy() {
|
|
1352
|
+
return {
|
|
1353
|
+
preferred: "batch-with-updates",
|
|
1354
|
+
supported: ["batch-with-updates", "insert-only"]
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
async createAISpan(span) {
|
|
1358
|
+
try {
|
|
1359
|
+
const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
|
|
1360
|
+
const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
|
|
1361
|
+
const record = {
|
|
1362
|
+
...span,
|
|
1363
|
+
startedAt,
|
|
1364
|
+
endedAt,
|
|
1365
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1366
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1367
|
+
};
|
|
1368
|
+
return this.operations.insert({ tableName: TABLE_AI_SPANS, record });
|
|
1369
|
+
} catch (error) {
|
|
1370
|
+
throw new MastraError(
|
|
1371
|
+
{
|
|
1372
|
+
id: "MONGODB_STORE_CREATE_AI_SPAN_FAILED",
|
|
1373
|
+
domain: ErrorDomain.STORAGE,
|
|
1374
|
+
category: ErrorCategory.USER,
|
|
1375
|
+
details: {
|
|
1376
|
+
spanId: span.spanId,
|
|
1377
|
+
traceId: span.traceId,
|
|
1378
|
+
spanType: span.spanType,
|
|
1379
|
+
spanName: span.name
|
|
1380
|
+
}
|
|
1381
|
+
},
|
|
1382
|
+
error
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
async getAITrace(traceId) {
|
|
1387
|
+
try {
|
|
1388
|
+
const collection = await this.operations.getCollection(TABLE_AI_SPANS);
|
|
1389
|
+
const spans = await collection.find({ traceId }).sort({ startedAt: -1 }).toArray();
|
|
1390
|
+
if (!spans || spans.length === 0) {
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
return {
|
|
1394
|
+
traceId,
|
|
1395
|
+
spans: spans.map((span) => this.transformSpanFromMongo(span))
|
|
1396
|
+
};
|
|
1397
|
+
} catch (error) {
|
|
1398
|
+
throw new MastraError(
|
|
1399
|
+
{
|
|
1400
|
+
id: "MONGODB_STORE_GET_AI_TRACE_FAILED",
|
|
1401
|
+
domain: ErrorDomain.STORAGE,
|
|
1402
|
+
category: ErrorCategory.USER,
|
|
1403
|
+
details: {
|
|
1404
|
+
traceId
|
|
1405
|
+
}
|
|
1406
|
+
},
|
|
1407
|
+
error
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
async updateAISpan({
|
|
1412
|
+
spanId,
|
|
1413
|
+
traceId,
|
|
1414
|
+
updates
|
|
1415
|
+
}) {
|
|
1416
|
+
try {
|
|
1417
|
+
const data = { ...updates };
|
|
1418
|
+
if (data.endedAt instanceof Date) {
|
|
1419
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1420
|
+
}
|
|
1421
|
+
if (data.startedAt instanceof Date) {
|
|
1422
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1423
|
+
}
|
|
1424
|
+
const updateData = {
|
|
1425
|
+
...data,
|
|
1426
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1427
|
+
};
|
|
1428
|
+
await this.operations.update({
|
|
1429
|
+
tableName: TABLE_AI_SPANS,
|
|
1430
|
+
keys: { spanId, traceId },
|
|
1431
|
+
data: updateData
|
|
1432
|
+
});
|
|
1433
|
+
} catch (error) {
|
|
1434
|
+
throw new MastraError(
|
|
1435
|
+
{
|
|
1436
|
+
id: "MONGODB_STORE_UPDATE_AI_SPAN_FAILED",
|
|
1437
|
+
domain: ErrorDomain.STORAGE,
|
|
1438
|
+
category: ErrorCategory.USER,
|
|
1439
|
+
details: {
|
|
1440
|
+
spanId,
|
|
1441
|
+
traceId
|
|
1442
|
+
}
|
|
1443
|
+
},
|
|
1444
|
+
error
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
async getAITracesPaginated({
|
|
1449
|
+
filters,
|
|
1450
|
+
pagination
|
|
1451
|
+
}) {
|
|
1452
|
+
const page = pagination?.page ?? 0;
|
|
1453
|
+
const perPage = pagination?.perPage ?? 10;
|
|
1454
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
1455
|
+
try {
|
|
1456
|
+
const collection = await this.operations.getCollection(TABLE_AI_SPANS);
|
|
1457
|
+
const mongoFilter = {
|
|
1458
|
+
parentSpanId: null,
|
|
1459
|
+
// Only get root spans for traces
|
|
1460
|
+
...actualFilters
|
|
1461
|
+
};
|
|
1462
|
+
if (pagination?.dateRange) {
|
|
1463
|
+
const dateFilter = {};
|
|
1464
|
+
if (pagination.dateRange.start) {
|
|
1465
|
+
dateFilter.$gte = pagination.dateRange.start instanceof Date ? pagination.dateRange.start.toISOString() : pagination.dateRange.start;
|
|
1466
|
+
}
|
|
1467
|
+
if (pagination.dateRange.end) {
|
|
1468
|
+
dateFilter.$lte = pagination.dateRange.end instanceof Date ? pagination.dateRange.end.toISOString() : pagination.dateRange.end;
|
|
1469
|
+
}
|
|
1470
|
+
if (Object.keys(dateFilter).length > 0) {
|
|
1471
|
+
mongoFilter.startedAt = dateFilter;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
if (entityId && entityType) {
|
|
1475
|
+
let name = "";
|
|
1476
|
+
if (entityType === "workflow") {
|
|
1477
|
+
name = `workflow run: '${entityId}'`;
|
|
1478
|
+
} else if (entityType === "agent") {
|
|
1479
|
+
name = `agent run: '${entityId}'`;
|
|
1480
|
+
} else {
|
|
1481
|
+
const error = new MastraError({
|
|
1482
|
+
id: "MONGODB_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1483
|
+
domain: ErrorDomain.STORAGE,
|
|
1484
|
+
category: ErrorCategory.USER,
|
|
1485
|
+
details: {
|
|
1486
|
+
entityType
|
|
1487
|
+
},
|
|
1488
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
1489
|
+
});
|
|
1490
|
+
throw error;
|
|
1491
|
+
}
|
|
1492
|
+
mongoFilter.name = name;
|
|
1493
|
+
}
|
|
1494
|
+
const count = await collection.countDocuments(mongoFilter);
|
|
1495
|
+
if (count === 0) {
|
|
1496
|
+
return {
|
|
1497
|
+
pagination: {
|
|
1498
|
+
total: 0,
|
|
1499
|
+
page,
|
|
1500
|
+
perPage,
|
|
1501
|
+
hasMore: false
|
|
1502
|
+
},
|
|
1503
|
+
spans: []
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
const spans = await collection.find(mongoFilter).sort({ startedAt: -1 }).skip(page * perPage).limit(perPage).toArray();
|
|
1507
|
+
return {
|
|
1508
|
+
pagination: {
|
|
1509
|
+
total: count,
|
|
1510
|
+
page,
|
|
1511
|
+
perPage,
|
|
1512
|
+
hasMore: spans.length === perPage
|
|
1513
|
+
},
|
|
1514
|
+
spans: spans.map((span) => this.transformSpanFromMongo(span))
|
|
1515
|
+
};
|
|
1516
|
+
} catch (error) {
|
|
1517
|
+
throw new MastraError(
|
|
1518
|
+
{
|
|
1519
|
+
id: "MONGODB_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
1520
|
+
domain: ErrorDomain.STORAGE,
|
|
1521
|
+
category: ErrorCategory.USER
|
|
1522
|
+
},
|
|
1523
|
+
error
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
async batchCreateAISpans(args) {
|
|
1528
|
+
try {
|
|
1529
|
+
const records = args.records.map((record) => {
|
|
1530
|
+
const startedAt = record.startedAt instanceof Date ? record.startedAt.toISOString() : record.startedAt;
|
|
1531
|
+
const endedAt = record.endedAt instanceof Date ? record.endedAt.toISOString() : record.endedAt;
|
|
1532
|
+
return {
|
|
1533
|
+
...record,
|
|
1534
|
+
startedAt,
|
|
1535
|
+
endedAt,
|
|
1536
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1537
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1538
|
+
};
|
|
1539
|
+
});
|
|
1540
|
+
return this.operations.batchInsert({
|
|
1541
|
+
tableName: TABLE_AI_SPANS,
|
|
1542
|
+
records
|
|
1543
|
+
});
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
throw new MastraError(
|
|
1546
|
+
{
|
|
1547
|
+
id: "MONGODB_STORE_BATCH_CREATE_AI_SPANS_FAILED",
|
|
1548
|
+
domain: ErrorDomain.STORAGE,
|
|
1549
|
+
category: ErrorCategory.USER
|
|
1550
|
+
},
|
|
1551
|
+
error
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
async batchUpdateAISpans(args) {
|
|
1556
|
+
try {
|
|
1557
|
+
return this.operations.batchUpdate({
|
|
1558
|
+
tableName: TABLE_AI_SPANS,
|
|
1559
|
+
updates: args.records.map((record) => {
|
|
1560
|
+
const data = { ...record.updates };
|
|
1561
|
+
if (data.endedAt instanceof Date) {
|
|
1562
|
+
data.endedAt = data.endedAt.toISOString();
|
|
1563
|
+
}
|
|
1564
|
+
if (data.startedAt instanceof Date) {
|
|
1565
|
+
data.startedAt = data.startedAt.toISOString();
|
|
1566
|
+
}
|
|
1567
|
+
const updateData = {
|
|
1568
|
+
...data,
|
|
1569
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1570
|
+
};
|
|
1571
|
+
return {
|
|
1572
|
+
keys: { spanId: record.spanId, traceId: record.traceId },
|
|
1573
|
+
data: updateData
|
|
1574
|
+
};
|
|
1575
|
+
})
|
|
1576
|
+
});
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
throw new MastraError(
|
|
1579
|
+
{
|
|
1580
|
+
id: "MONGODB_STORE_BATCH_UPDATE_AI_SPANS_FAILED",
|
|
1581
|
+
domain: ErrorDomain.STORAGE,
|
|
1582
|
+
category: ErrorCategory.USER
|
|
1583
|
+
},
|
|
1584
|
+
error
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
async batchDeleteAITraces(args) {
|
|
1589
|
+
try {
|
|
1590
|
+
const collection = await this.operations.getCollection(TABLE_AI_SPANS);
|
|
1591
|
+
await collection.deleteMany({
|
|
1592
|
+
traceId: { $in: args.traceIds }
|
|
1593
|
+
});
|
|
1594
|
+
} catch (error) {
|
|
1595
|
+
throw new MastraError(
|
|
1596
|
+
{
|
|
1597
|
+
id: "MONGODB_STORE_BATCH_DELETE_AI_TRACES_FAILED",
|
|
1598
|
+
domain: ErrorDomain.STORAGE,
|
|
1599
|
+
category: ErrorCategory.USER
|
|
1600
|
+
},
|
|
1601
|
+
error
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Transform MongoDB document to AISpanRecord format
|
|
1607
|
+
*/
|
|
1608
|
+
transformSpanFromMongo(doc) {
|
|
1609
|
+
const { _id, ...span } = doc;
|
|
1610
|
+
if (span.startedAt && typeof span.startedAt === "string") {
|
|
1611
|
+
span.startedAt = span.startedAt;
|
|
1612
|
+
}
|
|
1613
|
+
if (span.endedAt && typeof span.endedAt === "string") {
|
|
1614
|
+
span.endedAt = span.endedAt;
|
|
1615
|
+
}
|
|
1616
|
+
if (span.createdAt && typeof span.createdAt === "string") {
|
|
1617
|
+
span.createdAt = new Date(span.createdAt);
|
|
1618
|
+
}
|
|
1619
|
+
if (span.updatedAt && typeof span.updatedAt === "string") {
|
|
1620
|
+
span.updatedAt = new Date(span.updatedAt);
|
|
1621
|
+
}
|
|
1622
|
+
return span;
|
|
1623
|
+
}
|
|
1624
|
+
};
|
|
1625
|
+
var StoreOperationsMongoDB = class extends StoreOperations {
|
|
1626
|
+
#connector;
|
|
1627
|
+
constructor(config) {
|
|
1628
|
+
super();
|
|
1629
|
+
this.#connector = config.connector;
|
|
1630
|
+
}
|
|
1631
|
+
async getCollection(collectionName) {
|
|
1632
|
+
return this.#connector.getCollection(collectionName);
|
|
1633
|
+
}
|
|
1634
|
+
async hasColumn(_table, _column) {
|
|
1635
|
+
return true;
|
|
1636
|
+
}
|
|
1637
|
+
async createTable() {
|
|
1638
|
+
}
|
|
1639
|
+
async alterTable(_args) {
|
|
1640
|
+
}
|
|
1641
|
+
async clearTable({ tableName }) {
|
|
1642
|
+
try {
|
|
1643
|
+
const collection = await this.getCollection(tableName);
|
|
1644
|
+
await collection.deleteMany({});
|
|
1645
|
+
} catch (error) {
|
|
1646
|
+
const mastraError = new MastraError(
|
|
1647
|
+
{
|
|
1648
|
+
id: "STORAGE_MONGODB_STORE_CLEAR_TABLE_FAILED",
|
|
1649
|
+
domain: ErrorDomain.STORAGE,
|
|
1650
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1651
|
+
details: { tableName }
|
|
1652
|
+
},
|
|
1653
|
+
error
|
|
1654
|
+
);
|
|
1655
|
+
this.logger.error(mastraError.message);
|
|
1656
|
+
this.logger?.trackException(mastraError);
|
|
1657
|
+
throw mastraError;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
async dropTable({ tableName }) {
|
|
1661
|
+
try {
|
|
1662
|
+
const collection = await this.getCollection(tableName);
|
|
1663
|
+
await collection.drop();
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
if (error instanceof Error && error.message.includes("ns not found")) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
throw new MastraError(
|
|
1669
|
+
{
|
|
1670
|
+
id: "MONGODB_STORE_DROP_TABLE_FAILED",
|
|
1671
|
+
domain: ErrorDomain.STORAGE,
|
|
1672
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1673
|
+
details: { tableName }
|
|
1674
|
+
},
|
|
1675
|
+
error
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
processJsonbFields(tableName, record) {
|
|
1680
|
+
const schema = TABLE_SCHEMAS[tableName];
|
|
1681
|
+
if (!schema) {
|
|
1682
|
+
return record;
|
|
1683
|
+
}
|
|
1684
|
+
return Object.fromEntries(
|
|
1685
|
+
Object.entries(schema).map(([key, value]) => {
|
|
1686
|
+
if (value.type === "jsonb" && record[key] && typeof record[key] === "string") {
|
|
1687
|
+
return [key, safelyParseJSON(record[key])];
|
|
1688
|
+
}
|
|
1689
|
+
return [key, record[key]];
|
|
1690
|
+
})
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
async insert({ tableName, record }) {
|
|
1694
|
+
try {
|
|
1695
|
+
const collection = await this.getCollection(tableName);
|
|
1696
|
+
const recordToInsert = this.processJsonbFields(tableName, record);
|
|
1697
|
+
await collection.insertOne(recordToInsert);
|
|
1698
|
+
} catch (error) {
|
|
1699
|
+
const mastraError = new MastraError(
|
|
1700
|
+
{
|
|
1701
|
+
id: "STORAGE_MONGODB_STORE_INSERT_FAILED",
|
|
1702
|
+
domain: ErrorDomain.STORAGE,
|
|
1703
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1704
|
+
details: { tableName }
|
|
1705
|
+
},
|
|
1706
|
+
error
|
|
1707
|
+
);
|
|
1708
|
+
this.logger.error(mastraError.message);
|
|
1709
|
+
this.logger?.trackException(mastraError);
|
|
1710
|
+
throw mastraError;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
async batchInsert({ tableName, records }) {
|
|
1714
|
+
if (!records.length) {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
try {
|
|
1718
|
+
const collection = await this.getCollection(tableName);
|
|
1719
|
+
const processedRecords = records.map((record) => this.processJsonbFields(tableName, record));
|
|
1720
|
+
await collection.insertMany(processedRecords);
|
|
1721
|
+
} catch (error) {
|
|
1722
|
+
throw new MastraError(
|
|
1723
|
+
{
|
|
1724
|
+
id: "STORAGE_MONGODB_STORE_BATCH_INSERT_FAILED",
|
|
1725
|
+
domain: ErrorDomain.STORAGE,
|
|
1726
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1727
|
+
details: { tableName }
|
|
1728
|
+
},
|
|
1729
|
+
error
|
|
1730
|
+
);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
async load({ tableName, keys }) {
|
|
1734
|
+
this.logger.info(`Loading ${tableName} with keys ${JSON.stringify(keys)}`);
|
|
1735
|
+
try {
|
|
1736
|
+
const collection = await this.getCollection(tableName);
|
|
1737
|
+
return await collection.find(keys).toArray();
|
|
1738
|
+
} catch (error) {
|
|
1739
|
+
throw new MastraError(
|
|
1740
|
+
{
|
|
1741
|
+
id: "STORAGE_MONGODB_STORE_LOAD_FAILED",
|
|
1742
|
+
domain: ErrorDomain.STORAGE,
|
|
1743
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1744
|
+
details: { tableName }
|
|
1745
|
+
},
|
|
1746
|
+
error
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
async update({
|
|
1751
|
+
tableName,
|
|
1752
|
+
keys,
|
|
1753
|
+
data
|
|
1754
|
+
}) {
|
|
1755
|
+
try {
|
|
1756
|
+
const collection = await this.getCollection(tableName);
|
|
1757
|
+
const processedData = this.processJsonbFields(tableName, data);
|
|
1758
|
+
const cleanData = Object.fromEntries(Object.entries(processedData).filter(([_, value]) => value !== void 0));
|
|
1759
|
+
await collection.updateOne(keys, { $set: cleanData });
|
|
1760
|
+
} catch (error) {
|
|
1761
|
+
throw new MastraError(
|
|
1762
|
+
{
|
|
1763
|
+
id: "STORAGE_MONGODB_STORE_UPDATE_FAILED",
|
|
1764
|
+
domain: ErrorDomain.STORAGE,
|
|
1765
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1766
|
+
details: { tableName }
|
|
1767
|
+
},
|
|
1768
|
+
error
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
async batchUpdate({
|
|
1773
|
+
tableName,
|
|
1774
|
+
updates
|
|
1775
|
+
}) {
|
|
1776
|
+
if (!updates.length) {
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
try {
|
|
1780
|
+
const collection = await this.getCollection(tableName);
|
|
1781
|
+
const bulkOps = updates.map(({ keys, data }) => {
|
|
1782
|
+
const processedData = this.processJsonbFields(tableName, data);
|
|
1783
|
+
const cleanData = Object.fromEntries(Object.entries(processedData).filter(([_, value]) => value !== void 0));
|
|
1784
|
+
return {
|
|
1785
|
+
updateOne: {
|
|
1786
|
+
filter: keys,
|
|
1787
|
+
update: { $set: cleanData }
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
});
|
|
1791
|
+
await collection.bulkWrite(bulkOps);
|
|
1792
|
+
} catch (error) {
|
|
1793
|
+
throw new MastraError(
|
|
1794
|
+
{
|
|
1795
|
+
id: "STORAGE_MONGODB_STORE_BATCH_UPDATE_FAILED",
|
|
1796
|
+
domain: ErrorDomain.STORAGE,
|
|
1797
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1798
|
+
details: { tableName }
|
|
1799
|
+
},
|
|
1800
|
+
error
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
function transformScoreRow(row) {
|
|
1806
|
+
let scorerValue = null;
|
|
1807
|
+
if (row.scorer) {
|
|
1808
|
+
try {
|
|
1809
|
+
scorerValue = typeof row.scorer === "string" ? safelyParseJSON(row.scorer) : row.scorer;
|
|
1810
|
+
} catch (e) {
|
|
1811
|
+
console.warn("Failed to parse scorer:", e);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
let preprocessStepResultValue = null;
|
|
1815
|
+
if (row.preprocessStepResult) {
|
|
1816
|
+
try {
|
|
1817
|
+
preprocessStepResultValue = typeof row.preprocessStepResult === "string" ? safelyParseJSON(row.preprocessStepResult) : row.preprocessStepResult;
|
|
1818
|
+
} catch (e) {
|
|
1819
|
+
console.warn("Failed to parse preprocessStepResult:", e);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
let analyzeStepResultValue = null;
|
|
1823
|
+
if (row.analyzeStepResult) {
|
|
1824
|
+
try {
|
|
1825
|
+
analyzeStepResultValue = typeof row.analyzeStepResult === "string" ? safelyParseJSON(row.analyzeStepResult) : row.analyzeStepResult;
|
|
1826
|
+
} catch (e) {
|
|
1827
|
+
console.warn("Failed to parse analyzeStepResult:", e);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
let inputValue = null;
|
|
1831
|
+
if (row.input) {
|
|
1832
|
+
try {
|
|
1833
|
+
inputValue = typeof row.input === "string" ? safelyParseJSON(row.input) : row.input;
|
|
1834
|
+
} catch (e) {
|
|
1835
|
+
console.warn("Failed to parse input:", e);
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
let outputValue = null;
|
|
1839
|
+
if (row.output) {
|
|
1840
|
+
try {
|
|
1841
|
+
outputValue = typeof row.output === "string" ? safelyParseJSON(row.output) : row.output;
|
|
1842
|
+
} catch (e) {
|
|
1843
|
+
console.warn("Failed to parse output:", e);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
let entityValue = null;
|
|
1847
|
+
if (row.entity) {
|
|
1848
|
+
try {
|
|
1849
|
+
entityValue = typeof row.entity === "string" ? safelyParseJSON(row.entity) : row.entity;
|
|
1850
|
+
} catch (e) {
|
|
1851
|
+
console.warn("Failed to parse entity:", e);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
let requestContextValue = null;
|
|
1855
|
+
if (row.requestContext) {
|
|
1856
|
+
try {
|
|
1857
|
+
requestContextValue = typeof row.requestContext === "string" ? safelyParseJSON(row.requestContext) : row.requestContext;
|
|
1858
|
+
} catch (e) {
|
|
1859
|
+
console.warn("Failed to parse requestContext:", e);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
let metadataValue = null;
|
|
1863
|
+
if (row.metadata) {
|
|
1864
|
+
try {
|
|
1865
|
+
metadataValue = typeof row.metadata === "string" ? safelyParseJSON(row.metadata) : row.metadata;
|
|
1866
|
+
} catch (e) {
|
|
1867
|
+
console.warn("Failed to parse metadata:", e);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
return {
|
|
1871
|
+
id: row.id,
|
|
1872
|
+
entityId: row.entityId,
|
|
1873
|
+
entityType: row.entityType,
|
|
1874
|
+
scorerId: row.scorerId,
|
|
1875
|
+
traceId: row.traceId,
|
|
1876
|
+
spanId: row.spanId,
|
|
1877
|
+
runId: row.runId,
|
|
1878
|
+
scorer: scorerValue,
|
|
1879
|
+
preprocessStepResult: preprocessStepResultValue,
|
|
1880
|
+
preprocessPrompt: row.preprocessPrompt,
|
|
1881
|
+
analyzeStepResult: analyzeStepResultValue,
|
|
1882
|
+
generateScorePrompt: row.generateScorePrompt,
|
|
1883
|
+
score: row.score,
|
|
1884
|
+
analyzePrompt: row.analyzePrompt,
|
|
1885
|
+
reasonPrompt: row.reasonPrompt,
|
|
1886
|
+
metadata: metadataValue,
|
|
1887
|
+
input: inputValue,
|
|
1888
|
+
output: outputValue,
|
|
1889
|
+
additionalContext: row.additionalContext,
|
|
1890
|
+
requestContext: requestContextValue,
|
|
1891
|
+
entity: entityValue,
|
|
1892
|
+
source: row.source,
|
|
1893
|
+
resourceId: row.resourceId,
|
|
1894
|
+
threadId: row.threadId,
|
|
1895
|
+
createdAt: new Date(row.createdAt),
|
|
1896
|
+
updatedAt: new Date(row.updatedAt)
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
var ScoresStorageMongoDB = class extends ScoresStorage {
|
|
1900
|
+
operations;
|
|
1901
|
+
constructor({ operations }) {
|
|
1902
|
+
super();
|
|
1903
|
+
this.operations = operations;
|
|
1904
|
+
}
|
|
1905
|
+
async getScoreById({ id }) {
|
|
1906
|
+
try {
|
|
1907
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
1908
|
+
const document = await collection.findOne({ id });
|
|
1909
|
+
if (!document) {
|
|
1910
|
+
return null;
|
|
1911
|
+
}
|
|
1912
|
+
return transformScoreRow(document);
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
throw new MastraError(
|
|
1915
|
+
{
|
|
1916
|
+
id: "STORAGE_MONGODB_STORE_GET_SCORE_BY_ID_FAILED",
|
|
1917
|
+
domain: ErrorDomain.STORAGE,
|
|
1918
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1919
|
+
details: { id }
|
|
1920
|
+
},
|
|
1921
|
+
error
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
async saveScore(score) {
|
|
1926
|
+
let validatedScore;
|
|
1927
|
+
try {
|
|
1928
|
+
validatedScore = saveScorePayloadSchema.parse(score);
|
|
1929
|
+
} catch (error) {
|
|
1930
|
+
throw new MastraError(
|
|
1931
|
+
{
|
|
1932
|
+
id: "STORAGE_MONGODB_STORE_SAVE_SCORE_VALIDATION_FAILED",
|
|
1933
|
+
domain: ErrorDomain.STORAGE,
|
|
1934
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1935
|
+
},
|
|
1936
|
+
error
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
try {
|
|
1940
|
+
const now = /* @__PURE__ */ new Date();
|
|
1941
|
+
const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1942
|
+
const scoreData = {
|
|
1943
|
+
id: scoreId,
|
|
1944
|
+
entityId: validatedScore.entityId,
|
|
1945
|
+
entityType: validatedScore.entityType,
|
|
1946
|
+
scorerId: validatedScore.scorerId,
|
|
1947
|
+
traceId: validatedScore.traceId || "",
|
|
1948
|
+
spanId: validatedScore.spanId || "",
|
|
1949
|
+
runId: validatedScore.runId,
|
|
1950
|
+
scorer: typeof validatedScore.scorer === "string" ? safelyParseJSON(validatedScore.scorer) : validatedScore.scorer,
|
|
1951
|
+
preprocessStepResult: typeof validatedScore.preprocessStepResult === "string" ? safelyParseJSON(validatedScore.preprocessStepResult) : validatedScore.preprocessStepResult,
|
|
1952
|
+
analyzeStepResult: typeof validatedScore.analyzeStepResult === "string" ? safelyParseJSON(validatedScore.analyzeStepResult) : validatedScore.analyzeStepResult,
|
|
1953
|
+
score: validatedScore.score,
|
|
1954
|
+
reason: validatedScore.reason,
|
|
1955
|
+
preprocessPrompt: validatedScore.preprocessPrompt,
|
|
1956
|
+
generateScorePrompt: validatedScore.generateScorePrompt,
|
|
1957
|
+
generateReasonPrompt: validatedScore.generateReasonPrompt,
|
|
1958
|
+
analyzePrompt: validatedScore.analyzePrompt,
|
|
1959
|
+
input: typeof validatedScore.input === "string" ? safelyParseJSON(validatedScore.input) : validatedScore.input,
|
|
1960
|
+
output: typeof validatedScore.output === "string" ? safelyParseJSON(validatedScore.output) : validatedScore.output,
|
|
1961
|
+
additionalContext: validatedScore.additionalContext,
|
|
1962
|
+
requestContext: typeof validatedScore.requestContext === "string" ? safelyParseJSON(validatedScore.requestContext) : validatedScore.requestContext,
|
|
1963
|
+
entity: typeof validatedScore.entity === "string" ? safelyParseJSON(validatedScore.entity) : validatedScore.entity,
|
|
1964
|
+
source: validatedScore.source,
|
|
1965
|
+
resourceId: validatedScore.resourceId || "",
|
|
1966
|
+
threadId: validatedScore.threadId || "",
|
|
1967
|
+
createdAt: now,
|
|
1968
|
+
updatedAt: now
|
|
1969
|
+
};
|
|
1970
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
1971
|
+
await collection.insertOne(scoreData);
|
|
1972
|
+
const savedScore = {
|
|
1973
|
+
...score,
|
|
1974
|
+
id: scoreId,
|
|
1975
|
+
createdAt: now,
|
|
1976
|
+
updatedAt: now
|
|
1977
|
+
};
|
|
1978
|
+
return { score: savedScore };
|
|
1979
|
+
} catch (error) {
|
|
1980
|
+
throw new MastraError(
|
|
1981
|
+
{
|
|
1982
|
+
id: "STORAGE_MONGODB_STORE_SAVE_SCORE_FAILED",
|
|
1983
|
+
domain: ErrorDomain.STORAGE,
|
|
1984
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1985
|
+
details: { scorerId: score.scorerId, runId: score.runId }
|
|
1986
|
+
},
|
|
1987
|
+
error
|
|
1988
|
+
);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
async listScoresByScorerId({
|
|
1992
|
+
scorerId,
|
|
1993
|
+
pagination,
|
|
1994
|
+
entityId,
|
|
1995
|
+
entityType,
|
|
1996
|
+
source
|
|
1997
|
+
}) {
|
|
1998
|
+
try {
|
|
1999
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2000
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2001
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2002
|
+
const query = { scorerId };
|
|
2003
|
+
if (entityId) {
|
|
2004
|
+
query.entityId = entityId;
|
|
2005
|
+
}
|
|
2006
|
+
if (entityType) {
|
|
2007
|
+
query.entityType = entityType;
|
|
2008
|
+
}
|
|
2009
|
+
if (source) {
|
|
2010
|
+
query.source = source;
|
|
2011
|
+
}
|
|
2012
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
2013
|
+
const total = await collection.countDocuments(query);
|
|
2014
|
+
if (total === 0) {
|
|
2015
|
+
return {
|
|
2016
|
+
scores: [],
|
|
2017
|
+
pagination: {
|
|
2018
|
+
total: 0,
|
|
2019
|
+
page,
|
|
2020
|
+
perPage: perPageInput,
|
|
2021
|
+
hasMore: false
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2026
|
+
let cursor = collection.find(query).sort({ createdAt: "desc" }).skip(start);
|
|
2027
|
+
if (perPageInput !== false) {
|
|
2028
|
+
cursor = cursor.limit(perPage);
|
|
2029
|
+
}
|
|
2030
|
+
const documents = await cursor.toArray();
|
|
2031
|
+
const scores = documents.map((row) => transformScoreRow(row));
|
|
2032
|
+
return {
|
|
2033
|
+
scores,
|
|
2034
|
+
pagination: {
|
|
2035
|
+
total,
|
|
2036
|
+
page,
|
|
2037
|
+
perPage: perPageForResponse,
|
|
2038
|
+
hasMore: end < total
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
} catch (error) {
|
|
2042
|
+
throw new MastraError(
|
|
2043
|
+
{
|
|
2044
|
+
id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
2045
|
+
domain: ErrorDomain.STORAGE,
|
|
2046
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2047
|
+
details: { scorerId, page: pagination.page, perPage: pagination.perPage }
|
|
2048
|
+
},
|
|
2049
|
+
error
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
async listScoresByRunId({
|
|
2054
|
+
runId,
|
|
2055
|
+
pagination
|
|
2056
|
+
}) {
|
|
2057
|
+
try {
|
|
2058
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2059
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2060
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2061
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
2062
|
+
const total = await collection.countDocuments({ runId });
|
|
2063
|
+
if (total === 0) {
|
|
2064
|
+
return {
|
|
2065
|
+
scores: [],
|
|
2066
|
+
pagination: {
|
|
2067
|
+
total: 0,
|
|
2068
|
+
page,
|
|
2069
|
+
perPage: perPageInput,
|
|
2070
|
+
hasMore: false
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2075
|
+
let cursor = collection.find({ runId }).sort({ createdAt: "desc" }).skip(start);
|
|
2076
|
+
if (perPageInput !== false) {
|
|
2077
|
+
cursor = cursor.limit(perPage);
|
|
2078
|
+
}
|
|
2079
|
+
const documents = await cursor.toArray();
|
|
2080
|
+
const scores = documents.map((row) => transformScoreRow(row));
|
|
2081
|
+
return {
|
|
2082
|
+
scores,
|
|
2083
|
+
pagination: {
|
|
2084
|
+
total,
|
|
2085
|
+
page,
|
|
2086
|
+
perPage: perPageForResponse,
|
|
2087
|
+
hasMore: end < total
|
|
2088
|
+
}
|
|
2089
|
+
};
|
|
2090
|
+
} catch (error) {
|
|
2091
|
+
throw new MastraError(
|
|
2092
|
+
{
|
|
2093
|
+
id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
2094
|
+
domain: ErrorDomain.STORAGE,
|
|
2095
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2096
|
+
details: { runId, page: pagination.page, perPage: pagination.perPage }
|
|
2097
|
+
},
|
|
2098
|
+
error
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
async listScoresByEntityId({
|
|
2103
|
+
entityId,
|
|
2104
|
+
entityType,
|
|
2105
|
+
pagination
|
|
2106
|
+
}) {
|
|
2107
|
+
try {
|
|
2108
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2109
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2110
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2111
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
2112
|
+
const total = await collection.countDocuments({ entityId, entityType });
|
|
2113
|
+
if (total === 0) {
|
|
2114
|
+
return {
|
|
2115
|
+
scores: [],
|
|
2116
|
+
pagination: {
|
|
2117
|
+
total: 0,
|
|
2118
|
+
page,
|
|
2119
|
+
perPage: perPageInput,
|
|
2120
|
+
hasMore: false
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2125
|
+
let cursor = collection.find({ entityId, entityType }).sort({ createdAt: "desc" }).skip(start);
|
|
2126
|
+
if (perPageInput !== false) {
|
|
2127
|
+
cursor = cursor.limit(perPage);
|
|
2128
|
+
}
|
|
2129
|
+
const documents = await cursor.toArray();
|
|
2130
|
+
const scores = documents.map((row) => transformScoreRow(row));
|
|
2131
|
+
return {
|
|
2132
|
+
scores,
|
|
2133
|
+
pagination: {
|
|
2134
|
+
total,
|
|
2135
|
+
page,
|
|
2136
|
+
perPage: perPageForResponse,
|
|
2137
|
+
hasMore: end < total
|
|
2138
|
+
}
|
|
2139
|
+
};
|
|
2140
|
+
} catch (error) {
|
|
2141
|
+
throw new MastraError(
|
|
2142
|
+
{
|
|
2143
|
+
id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
2144
|
+
domain: ErrorDomain.STORAGE,
|
|
2145
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2146
|
+
details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage }
|
|
2147
|
+
},
|
|
2148
|
+
error
|
|
2149
|
+
);
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
async listScoresBySpan({
|
|
2153
|
+
traceId,
|
|
2154
|
+
spanId,
|
|
2155
|
+
pagination
|
|
2156
|
+
}) {
|
|
2157
|
+
try {
|
|
2158
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2159
|
+
const perPage = normalizePerPage(perPageInput, 100);
|
|
2160
|
+
const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
|
|
2161
|
+
const query = { traceId, spanId };
|
|
2162
|
+
const collection = await this.operations.getCollection(TABLE_SCORERS);
|
|
2163
|
+
const total = await collection.countDocuments(query);
|
|
2164
|
+
if (total === 0) {
|
|
2165
|
+
return {
|
|
2166
|
+
scores: [],
|
|
2167
|
+
pagination: {
|
|
2168
|
+
total: 0,
|
|
2169
|
+
page,
|
|
2170
|
+
perPage: perPageInput,
|
|
2171
|
+
hasMore: false
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2176
|
+
let cursor = collection.find(query).sort({ createdAt: "desc" }).skip(start);
|
|
2177
|
+
if (perPageInput !== false) {
|
|
2178
|
+
cursor = cursor.limit(perPage);
|
|
2179
|
+
}
|
|
2180
|
+
const documents = await cursor.toArray();
|
|
2181
|
+
const scores = documents.map((row) => transformScoreRow(row));
|
|
2182
|
+
return {
|
|
2183
|
+
scores,
|
|
2184
|
+
pagination: {
|
|
2185
|
+
total,
|
|
2186
|
+
page,
|
|
2187
|
+
perPage: perPageForResponse,
|
|
2188
|
+
hasMore: end < total
|
|
2189
|
+
}
|
|
2190
|
+
};
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
throw new MastraError(
|
|
2193
|
+
{
|
|
2194
|
+
id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
2195
|
+
domain: ErrorDomain.STORAGE,
|
|
2196
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2197
|
+
details: { traceId, spanId, page: pagination.page, perPage: pagination.perPage }
|
|
2198
|
+
},
|
|
2199
|
+
error
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
var WorkflowsStorageMongoDB = class extends WorkflowsStorage {
|
|
2205
|
+
operations;
|
|
2206
|
+
constructor({ operations }) {
|
|
2207
|
+
super();
|
|
2208
|
+
this.operations = operations;
|
|
2209
|
+
}
|
|
2210
|
+
updateWorkflowResults({
|
|
2211
|
+
// workflowName,
|
|
2212
|
+
// runId,
|
|
2213
|
+
// stepId,
|
|
2214
|
+
// result,
|
|
2215
|
+
// requestContext,
|
|
2216
|
+
}) {
|
|
2217
|
+
throw new Error("Method not implemented.");
|
|
2218
|
+
}
|
|
2219
|
+
updateWorkflowState({
|
|
2220
|
+
// workflowName,
|
|
2221
|
+
// runId,
|
|
2222
|
+
// opts,
|
|
2223
|
+
}) {
|
|
2224
|
+
throw new Error("Method not implemented.");
|
|
2225
|
+
}
|
|
2226
|
+
async persistWorkflowSnapshot({
|
|
2227
|
+
workflowName,
|
|
2228
|
+
runId,
|
|
2229
|
+
resourceId,
|
|
2230
|
+
snapshot
|
|
2231
|
+
}) {
|
|
2232
|
+
try {
|
|
2233
|
+
const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
|
|
2234
|
+
await collection.updateOne(
|
|
2235
|
+
{ workflow_name: workflowName, run_id: runId },
|
|
2236
|
+
{
|
|
2237
|
+
$set: {
|
|
2238
|
+
workflow_name: workflowName,
|
|
2239
|
+
run_id: runId,
|
|
2240
|
+
resourceId,
|
|
2241
|
+
snapshot,
|
|
2242
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2243
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2244
|
+
}
|
|
2245
|
+
},
|
|
2246
|
+
{ upsert: true }
|
|
2247
|
+
);
|
|
2248
|
+
} catch (error) {
|
|
2249
|
+
throw new MastraError(
|
|
2250
|
+
{
|
|
2251
|
+
id: "STORAGE_MONGODB_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
2252
|
+
domain: ErrorDomain.STORAGE,
|
|
2253
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2254
|
+
details: { workflowName, runId }
|
|
2255
|
+
},
|
|
2256
|
+
error
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
async loadWorkflowSnapshot({
|
|
2261
|
+
workflowName,
|
|
2262
|
+
runId
|
|
2263
|
+
}) {
|
|
2264
|
+
try {
|
|
2265
|
+
const result = await this.operations.load({
|
|
2266
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
2267
|
+
keys: {
|
|
2268
|
+
workflow_name: workflowName,
|
|
2269
|
+
run_id: runId
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
if (!result?.length) {
|
|
2273
|
+
return null;
|
|
2274
|
+
}
|
|
2275
|
+
return typeof result[0].snapshot === "string" ? safelyParseJSON(result[0].snapshot) : result[0].snapshot;
|
|
2276
|
+
} catch (error) {
|
|
2277
|
+
throw new MastraError(
|
|
2278
|
+
{
|
|
2279
|
+
id: "STORAGE_MONGODB_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
2280
|
+
domain: ErrorDomain.STORAGE,
|
|
2281
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2282
|
+
details: { workflowName, runId }
|
|
2283
|
+
},
|
|
2284
|
+
error
|
|
2285
|
+
);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
async listWorkflowRuns(args) {
|
|
2289
|
+
const options = args || {};
|
|
2290
|
+
try {
|
|
2291
|
+
const query = {};
|
|
2292
|
+
if (options.workflowName) {
|
|
2293
|
+
query["workflow_name"] = options.workflowName;
|
|
2294
|
+
}
|
|
2295
|
+
if (options.fromDate) {
|
|
2296
|
+
query["createdAt"] = { $gte: options.fromDate };
|
|
2297
|
+
}
|
|
2298
|
+
if (options.toDate) {
|
|
2299
|
+
if (query["createdAt"]) {
|
|
2300
|
+
query["createdAt"].$lte = options.toDate;
|
|
2301
|
+
} else {
|
|
2302
|
+
query["createdAt"] = { $lte: options.toDate };
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
if (options.resourceId) {
|
|
2306
|
+
query["resourceId"] = options.resourceId;
|
|
2307
|
+
}
|
|
2308
|
+
const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
|
|
2309
|
+
let total = 0;
|
|
2310
|
+
let cursor = collection.find(query).sort({ createdAt: -1 });
|
|
2311
|
+
if (options.page !== void 0 && typeof options.perPage === "number") {
|
|
2312
|
+
if (options.page < 0) {
|
|
2313
|
+
throw new MastraError(
|
|
2314
|
+
{
|
|
2315
|
+
id: "STORAGE_MONGODB_INVALID_PAGE",
|
|
2316
|
+
domain: ErrorDomain.STORAGE,
|
|
2317
|
+
category: ErrorCategory.USER,
|
|
2318
|
+
details: { page: options.page }
|
|
2319
|
+
},
|
|
2320
|
+
new Error("page must be >= 0")
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
total = await collection.countDocuments(query);
|
|
2324
|
+
const normalizedPerPage = normalizePerPage(options.perPage, Number.MAX_SAFE_INTEGER);
|
|
2325
|
+
if (normalizedPerPage === 0) {
|
|
2326
|
+
return { runs: [], total };
|
|
2327
|
+
}
|
|
2328
|
+
const offset = options.page * normalizedPerPage;
|
|
2329
|
+
cursor = cursor.skip(offset);
|
|
2330
|
+
cursor = cursor.limit(Math.min(normalizedPerPage, 2147483647));
|
|
2331
|
+
}
|
|
2332
|
+
const results = await cursor.toArray();
|
|
2333
|
+
const runs = results.map((row) => this.parseWorkflowRun(row));
|
|
2334
|
+
return {
|
|
2335
|
+
runs,
|
|
2336
|
+
total: total || runs.length
|
|
2337
|
+
};
|
|
2338
|
+
} catch (error) {
|
|
2339
|
+
throw new MastraError(
|
|
2340
|
+
{
|
|
2341
|
+
id: "STORAGE_MONGODB_STORE_LIST_WORKFLOW_RUNS_FAILED",
|
|
2342
|
+
domain: ErrorDomain.STORAGE,
|
|
2343
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2344
|
+
details: { workflowName: options.workflowName || "unknown" }
|
|
2345
|
+
},
|
|
2346
|
+
error
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
async getWorkflowRunById(args) {
|
|
2351
|
+
try {
|
|
2352
|
+
const query = {};
|
|
2353
|
+
if (args.runId) {
|
|
2354
|
+
query["run_id"] = args.runId;
|
|
2355
|
+
}
|
|
2356
|
+
if (args.workflowName) {
|
|
2357
|
+
query["workflow_name"] = args.workflowName;
|
|
2358
|
+
}
|
|
2359
|
+
const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
|
|
2360
|
+
const result = await collection.findOne(query);
|
|
2361
|
+
if (!result) {
|
|
2362
|
+
return null;
|
|
2363
|
+
}
|
|
2364
|
+
return this.parseWorkflowRun(result);
|
|
2365
|
+
} catch (error) {
|
|
2366
|
+
throw new MastraError(
|
|
2367
|
+
{
|
|
2368
|
+
id: "STORAGE_MONGODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2369
|
+
domain: ErrorDomain.STORAGE,
|
|
2370
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2371
|
+
details: { runId: args.runId }
|
|
2372
|
+
},
|
|
2373
|
+
error
|
|
2374
|
+
);
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
parseWorkflowRun(row) {
|
|
2378
|
+
let parsedSnapshot = row.snapshot;
|
|
2379
|
+
if (typeof parsedSnapshot === "string") {
|
|
2380
|
+
try {
|
|
2381
|
+
parsedSnapshot = typeof row.snapshot === "string" ? safelyParseJSON(row.snapshot) : row.snapshot;
|
|
2382
|
+
} catch (e) {
|
|
2383
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
return {
|
|
2387
|
+
workflowName: row.workflow_name,
|
|
2388
|
+
runId: row.run_id,
|
|
2389
|
+
snapshot: parsedSnapshot,
|
|
2390
|
+
createdAt: new Date(row.createdAt),
|
|
2391
|
+
updatedAt: new Date(row.updatedAt),
|
|
2392
|
+
resourceId: row.resourceId
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
|
|
2397
|
+
// src/storage/index.ts
|
|
2398
|
+
var loadConnector = (config) => {
|
|
2399
|
+
try {
|
|
2400
|
+
if ("connectorHandler" in config) {
|
|
2401
|
+
return MongoDBConnector.fromConnectionHandler(config.connectorHandler);
|
|
2402
|
+
}
|
|
2403
|
+
} catch (error) {
|
|
2404
|
+
throw new MastraError(
|
|
2405
|
+
{
|
|
2406
|
+
id: "STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED",
|
|
2407
|
+
domain: ErrorDomain.STORAGE,
|
|
2408
|
+
category: ErrorCategory.USER,
|
|
2409
|
+
details: { connectionHandler: true }
|
|
2410
|
+
},
|
|
2411
|
+
error
|
|
2412
|
+
);
|
|
2413
|
+
}
|
|
2414
|
+
try {
|
|
2415
|
+
return MongoDBConnector.fromDatabaseConfig({
|
|
2416
|
+
options: config.options,
|
|
2417
|
+
url: config.url,
|
|
2418
|
+
dbName: config.dbName
|
|
2419
|
+
});
|
|
2420
|
+
} catch (error) {
|
|
2421
|
+
throw new MastraError(
|
|
2422
|
+
{
|
|
2423
|
+
id: "STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED",
|
|
2424
|
+
domain: ErrorDomain.STORAGE,
|
|
2425
|
+
category: ErrorCategory.USER,
|
|
2426
|
+
details: { url: config?.url, dbName: config?.dbName }
|
|
2427
|
+
},
|
|
2428
|
+
error
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
var MongoDBStore = class extends MastraStorage {
|
|
2433
|
+
#connector;
|
|
2434
|
+
stores;
|
|
2435
|
+
get supports() {
|
|
2436
|
+
return {
|
|
2437
|
+
selectByIncludeResourceScope: true,
|
|
2438
|
+
resourceWorkingMemory: true,
|
|
2439
|
+
hasColumn: false,
|
|
2440
|
+
createTable: false,
|
|
2441
|
+
deleteMessages: false,
|
|
2442
|
+
listScoresBySpan: true
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
constructor(config) {
|
|
2446
|
+
super({ name: "MongoDBStore" });
|
|
2447
|
+
this.stores = {};
|
|
2448
|
+
this.#connector = loadConnector(config);
|
|
2449
|
+
const operations = new StoreOperationsMongoDB({
|
|
2450
|
+
connector: this.#connector
|
|
2451
|
+
});
|
|
2452
|
+
const memory = new MemoryStorageMongoDB({
|
|
2453
|
+
operations
|
|
2454
|
+
});
|
|
2455
|
+
const scores = new ScoresStorageMongoDB({
|
|
2456
|
+
operations
|
|
2457
|
+
});
|
|
2458
|
+
const workflows = new WorkflowsStorageMongoDB({
|
|
2459
|
+
operations
|
|
2460
|
+
});
|
|
2461
|
+
const observability = new ObservabilityMongoDB({
|
|
2462
|
+
operations
|
|
2463
|
+
});
|
|
2464
|
+
this.stores = {
|
|
2465
|
+
operations,
|
|
2466
|
+
memory,
|
|
2467
|
+
scores,
|
|
2468
|
+
workflows,
|
|
2469
|
+
observability
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
async createTable({
|
|
2473
|
+
tableName,
|
|
2474
|
+
schema
|
|
2475
|
+
}) {
|
|
2476
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2477
|
+
}
|
|
2478
|
+
async alterTable(_args) {
|
|
2479
|
+
return this.stores.operations.alterTable(_args);
|
|
2480
|
+
}
|
|
2481
|
+
async dropTable({ tableName }) {
|
|
2482
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2483
|
+
}
|
|
2484
|
+
async clearTable({ tableName }) {
|
|
2485
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2486
|
+
}
|
|
2487
|
+
async insert({ tableName, record }) {
|
|
2488
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2489
|
+
}
|
|
2490
|
+
async batchInsert({ tableName, records }) {
|
|
2491
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
2492
|
+
}
|
|
2493
|
+
async load({ tableName, keys }) {
|
|
2494
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2495
|
+
}
|
|
2496
|
+
async getThreadById({ threadId }) {
|
|
2497
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2498
|
+
}
|
|
2499
|
+
async saveThread({ thread }) {
|
|
2500
|
+
return this.stores.memory.saveThread({ thread });
|
|
2501
|
+
}
|
|
2502
|
+
async updateThread({
|
|
2503
|
+
id,
|
|
2504
|
+
title,
|
|
2505
|
+
metadata
|
|
2506
|
+
}) {
|
|
2507
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2508
|
+
}
|
|
2509
|
+
async deleteThread({ threadId }) {
|
|
2510
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2511
|
+
}
|
|
2512
|
+
async getMessages(args) {
|
|
2513
|
+
return this.stores.memory.getMessages(args);
|
|
2514
|
+
}
|
|
2515
|
+
async listMessagesById({ messageIds }) {
|
|
2516
|
+
return this.stores.memory.listMessagesById({ messageIds });
|
|
2517
|
+
}
|
|
2518
|
+
async saveMessages(args) {
|
|
2519
|
+
return this.stores.memory.saveMessages(args);
|
|
2520
|
+
}
|
|
2521
|
+
async updateMessages(_args) {
|
|
2522
|
+
return this.stores.memory.updateMessages(_args);
|
|
2523
|
+
}
|
|
2524
|
+
async listWorkflowRuns(args) {
|
|
2525
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
2526
|
+
}
|
|
2527
|
+
async updateWorkflowResults({
|
|
2528
|
+
workflowName,
|
|
2529
|
+
runId,
|
|
2530
|
+
stepId,
|
|
2531
|
+
result,
|
|
2532
|
+
requestContext
|
|
2533
|
+
}) {
|
|
2534
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2535
|
+
}
|
|
2536
|
+
async updateWorkflowState({
|
|
2537
|
+
workflowName,
|
|
2538
|
+
runId,
|
|
2539
|
+
opts
|
|
2540
|
+
}) {
|
|
2541
|
+
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2542
|
+
}
|
|
2543
|
+
async persistWorkflowSnapshot({
|
|
2544
|
+
workflowName,
|
|
2545
|
+
runId,
|
|
2546
|
+
resourceId,
|
|
2547
|
+
snapshot
|
|
2548
|
+
}) {
|
|
2549
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2550
|
+
}
|
|
2551
|
+
async loadWorkflowSnapshot({
|
|
2552
|
+
workflowName,
|
|
2553
|
+
runId
|
|
2554
|
+
}) {
|
|
2555
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2556
|
+
}
|
|
2557
|
+
async getWorkflowRunById({
|
|
2558
|
+
runId,
|
|
2559
|
+
workflowName
|
|
2560
|
+
}) {
|
|
2561
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2562
|
+
}
|
|
2563
|
+
async close() {
|
|
2564
|
+
try {
|
|
2565
|
+
await this.#connector.close();
|
|
2566
|
+
} catch (error) {
|
|
2567
|
+
throw new MastraError(
|
|
2568
|
+
{
|
|
2569
|
+
id: "STORAGE_MONGODB_STORE_CLOSE_FAILED",
|
|
2570
|
+
domain: ErrorDomain.STORAGE,
|
|
2571
|
+
category: ErrorCategory.USER
|
|
2572
|
+
},
|
|
2573
|
+
error
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* SCORERS
|
|
2579
|
+
*/
|
|
2580
|
+
async getScoreById({ id }) {
|
|
2581
|
+
return this.stores.scores.getScoreById({ id });
|
|
2582
|
+
}
|
|
2583
|
+
async saveScore(score) {
|
|
2584
|
+
return this.stores.scores.saveScore(score);
|
|
2585
|
+
}
|
|
2586
|
+
async listScoresByRunId({
|
|
2587
|
+
runId,
|
|
2588
|
+
pagination
|
|
2589
|
+
}) {
|
|
2590
|
+
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
2591
|
+
}
|
|
2592
|
+
async listScoresByEntityId({
|
|
2593
|
+
entityId,
|
|
2594
|
+
entityType,
|
|
2595
|
+
pagination
|
|
2596
|
+
}) {
|
|
2597
|
+
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
2598
|
+
}
|
|
2599
|
+
async listScoresByScorerId({
|
|
2600
|
+
scorerId,
|
|
2601
|
+
pagination,
|
|
2602
|
+
entityId,
|
|
2603
|
+
entityType,
|
|
2604
|
+
source
|
|
2605
|
+
}) {
|
|
2606
|
+
return this.stores.scores.listScoresByScorerId({ scorerId, pagination, entityId, entityType, source });
|
|
2607
|
+
}
|
|
2608
|
+
async listScoresBySpan({
|
|
2609
|
+
traceId,
|
|
2610
|
+
spanId,
|
|
2611
|
+
pagination
|
|
2612
|
+
}) {
|
|
2613
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2614
|
+
}
|
|
2615
|
+
/**
|
|
2616
|
+
* RESOURCES
|
|
2617
|
+
*/
|
|
2618
|
+
async getResourceById({ resourceId }) {
|
|
2619
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2620
|
+
}
|
|
2621
|
+
async saveResource({ resource }) {
|
|
2622
|
+
return this.stores.memory.saveResource({ resource });
|
|
2623
|
+
}
|
|
2624
|
+
async updateResource({
|
|
2625
|
+
resourceId,
|
|
2626
|
+
workingMemory,
|
|
2627
|
+
metadata
|
|
2628
|
+
}) {
|
|
2629
|
+
return this.stores.memory.updateResource({
|
|
2630
|
+
resourceId,
|
|
2631
|
+
workingMemory,
|
|
2632
|
+
metadata
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* AI Tracing/Observability
|
|
2637
|
+
*/
|
|
2638
|
+
async createAISpan(span) {
|
|
2639
|
+
if (!this.stores.observability) {
|
|
2640
|
+
throw new MastraError({
|
|
2641
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2642
|
+
domain: ErrorDomain.STORAGE,
|
|
2643
|
+
category: ErrorCategory.SYSTEM,
|
|
2644
|
+
text: "Observability storage is not initialized"
|
|
2645
|
+
});
|
|
2646
|
+
}
|
|
2647
|
+
return this.stores.observability.createAISpan(span);
|
|
2648
|
+
}
|
|
2649
|
+
async updateAISpan({
|
|
2650
|
+
spanId,
|
|
2651
|
+
traceId,
|
|
2652
|
+
updates
|
|
2653
|
+
}) {
|
|
2654
|
+
if (!this.stores.observability) {
|
|
2655
|
+
throw new MastraError({
|
|
2656
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2657
|
+
domain: ErrorDomain.STORAGE,
|
|
2658
|
+
category: ErrorCategory.SYSTEM,
|
|
2659
|
+
text: "Observability storage is not initialized"
|
|
2660
|
+
});
|
|
2661
|
+
}
|
|
2662
|
+
return this.stores.observability.updateAISpan({ spanId, traceId, updates });
|
|
2663
|
+
}
|
|
2664
|
+
async getAITrace(traceId) {
|
|
2665
|
+
if (!this.stores.observability) {
|
|
2666
|
+
throw new MastraError({
|
|
2667
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2668
|
+
domain: ErrorDomain.STORAGE,
|
|
2669
|
+
category: ErrorCategory.SYSTEM,
|
|
2670
|
+
text: "Observability storage is not initialized"
|
|
2671
|
+
});
|
|
2672
|
+
}
|
|
2673
|
+
return this.stores.observability.getAITrace(traceId);
|
|
2674
|
+
}
|
|
2675
|
+
async getAITracesPaginated(args) {
|
|
2676
|
+
if (!this.stores.observability) {
|
|
2677
|
+
throw new MastraError({
|
|
2678
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2679
|
+
domain: ErrorDomain.STORAGE,
|
|
2680
|
+
category: ErrorCategory.SYSTEM,
|
|
2681
|
+
text: "Observability storage is not initialized"
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2684
|
+
return this.stores.observability.getAITracesPaginated(args);
|
|
2685
|
+
}
|
|
2686
|
+
async batchCreateAISpans(args) {
|
|
2687
|
+
if (!this.stores.observability) {
|
|
2688
|
+
throw new MastraError({
|
|
2689
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2690
|
+
domain: ErrorDomain.STORAGE,
|
|
2691
|
+
category: ErrorCategory.SYSTEM,
|
|
2692
|
+
text: "Observability storage is not initialized"
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
return this.stores.observability.batchCreateAISpans(args);
|
|
2696
|
+
}
|
|
2697
|
+
async batchUpdateAISpans(args) {
|
|
2698
|
+
if (!this.stores.observability) {
|
|
2699
|
+
throw new MastraError({
|
|
2700
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2701
|
+
domain: ErrorDomain.STORAGE,
|
|
2702
|
+
category: ErrorCategory.SYSTEM,
|
|
2703
|
+
text: "Observability storage is not initialized"
|
|
2704
|
+
});
|
|
2705
|
+
}
|
|
2706
|
+
return this.stores.observability.batchUpdateAISpans(args);
|
|
2707
|
+
}
|
|
2708
|
+
async batchDeleteAITraces(args) {
|
|
2709
|
+
if (!this.stores.observability) {
|
|
2710
|
+
throw new MastraError({
|
|
2711
|
+
id: "MONGODB_STORE_OBSERVABILITY_NOT_INITIALIZED",
|
|
2712
|
+
domain: ErrorDomain.STORAGE,
|
|
2713
|
+
category: ErrorCategory.SYSTEM,
|
|
2714
|
+
text: "Observability storage is not initialized"
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
return this.stores.observability.batchDeleteAITraces(args);
|
|
2718
|
+
}
|
|
357
2719
|
};
|
|
358
2720
|
|
|
359
2721
|
// src/vector/prompt.ts
|
|
@@ -451,4 +2813,6 @@ Example Complex Query:
|
|
|
451
2813
|
]
|
|
452
2814
|
}`;
|
|
453
2815
|
|
|
454
|
-
export { MONGODB_PROMPT, MongoDBVector };
|
|
2816
|
+
export { MONGODB_PROMPT, MongoDBStore, MongoDBVector };
|
|
2817
|
+
//# sourceMappingURL=index.js.map
|
|
2818
|
+
//# sourceMappingURL=index.js.map
|