@mastra/mongodb 0.10.2 → 0.10.3-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +20 -0
- package/dist/_tsup-dts-rollup.d.cts +34 -1
- package/dist/_tsup-dts-rollup.d.ts +34 -1
- package/dist/index.cjs +27 -3
- package/dist/index.js +27 -3
- package/package.json +9 -8
- package/src/storage/index.test.ts +235 -17
- package/src/storage/index.ts +55 -3
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/mongodb@0.10.
|
|
2
|
+
> @mastra/mongodb@0.10.3-alpha.1 build /home/runner/work/mastra/mastra/stores/mongodb
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v8.
|
|
7
|
+
[34mCLI[39m tsup v8.5.0
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 8770ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/mongodb/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
14
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
15
15
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/mongodb/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 11972ms
|
|
17
17
|
[34mCLI[39m Cleaning output folder
|
|
18
18
|
[34mESM[39m Build start
|
|
19
19
|
[34mCJS[39m Build start
|
|
20
|
-
[
|
|
21
|
-
[
|
|
22
|
-
[
|
|
23
|
-
[
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m33.85 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 1239ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m33.73 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 1239ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @mastra/mongodb
|
|
2
2
|
|
|
3
|
+
## 0.10.3-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 925ab94: added paginated functions to base class and added boilerplate and updated imports
|
|
8
|
+
- Updated dependencies [925ab94]
|
|
9
|
+
- @mastra/core@0.10.4-alpha.3
|
|
10
|
+
|
|
11
|
+
## 0.10.3-alpha.0
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- dffb67b: updated stores to add alter table and change tests
|
|
16
|
+
- e030ea3: Added missing format compatibility to MongoDB getMessages() method
|
|
17
|
+
- Updated dependencies [f6fd25f]
|
|
18
|
+
- Updated dependencies [dffb67b]
|
|
19
|
+
- Updated dependencies [f1309d3]
|
|
20
|
+
- Updated dependencies [f7f8293]
|
|
21
|
+
- @mastra/core@0.10.4-alpha.1
|
|
22
|
+
|
|
3
23
|
## 0.10.2
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -11,11 +11,15 @@ import { MastraStorage } from '@mastra/core/storage';
|
|
|
11
11
|
import { MastraVector } from '@mastra/core/vector';
|
|
12
12
|
import type { MongoClientOptions } from 'mongodb';
|
|
13
13
|
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
14
|
+
import type { PaginationInfo } from '@mastra/core/storage';
|
|
14
15
|
import type { QueryResult } from '@mastra/core/vector';
|
|
15
16
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
17
|
+
import type { StorageColumn } from '@mastra/core/storage';
|
|
16
18
|
import type { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
19
|
+
import type { StorageGetTracesArg } from '@mastra/core/storage';
|
|
17
20
|
import type { StorageThreadType } from '@mastra/core/memory';
|
|
18
21
|
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
22
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
19
23
|
import type { UpdateVectorParams } from '@mastra/core/vector';
|
|
20
24
|
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
21
25
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
@@ -71,6 +75,17 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
71
75
|
private getConnection;
|
|
72
76
|
private getCollection;
|
|
73
77
|
createTable(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
80
|
+
* @param tableName Name of the table
|
|
81
|
+
* @param schema Schema of the table
|
|
82
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
83
|
+
*/
|
|
84
|
+
alterTable(_args: {
|
|
85
|
+
tableName: TABLE_NAMES;
|
|
86
|
+
schema: Record<string, StorageColumn>;
|
|
87
|
+
ifNotExists: string[];
|
|
88
|
+
}): Promise<void>;
|
|
74
89
|
clearTable({ tableName }: {
|
|
75
90
|
tableName: TABLE_NAMES;
|
|
76
91
|
}): Promise<void>;
|
|
@@ -103,7 +118,12 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
103
118
|
deleteThread({ threadId }: {
|
|
104
119
|
threadId: string;
|
|
105
120
|
}): Promise<void>;
|
|
106
|
-
getMessages
|
|
121
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
122
|
+
format?: 'v1';
|
|
123
|
+
}): Promise<MastraMessageV1[]>;
|
|
124
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
125
|
+
format: 'v2';
|
|
126
|
+
}): Promise<MastraMessageV2[]>;
|
|
107
127
|
saveMessages(args: {
|
|
108
128
|
messages: MastraMessageV1[];
|
|
109
129
|
format?: undefined | 'v1';
|
|
@@ -153,6 +173,19 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
153
173
|
private parseWorkflowRun;
|
|
154
174
|
private parseRow;
|
|
155
175
|
private transformEvalRow;
|
|
176
|
+
getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & {
|
|
177
|
+
traces: Trace[];
|
|
178
|
+
}>;
|
|
179
|
+
getThreadsByResourceIdPaginated(_args: {
|
|
180
|
+
resourceId: string;
|
|
181
|
+
page?: number;
|
|
182
|
+
perPage?: number;
|
|
183
|
+
}): Promise<PaginationInfo & {
|
|
184
|
+
threads: StorageThreadType[];
|
|
185
|
+
}>;
|
|
186
|
+
getMessagesPaginated(_args: StorageGetMessagesArg): Promise<PaginationInfo & {
|
|
187
|
+
messages: MastraMessageV1[] | MastraMessageV2[];
|
|
188
|
+
}>;
|
|
156
189
|
close(): Promise<void>;
|
|
157
190
|
}
|
|
158
191
|
export { MongoDBStore }
|
|
@@ -11,11 +11,15 @@ import { MastraStorage } from '@mastra/core/storage';
|
|
|
11
11
|
import { MastraVector } from '@mastra/core/vector';
|
|
12
12
|
import type { MongoClientOptions } from 'mongodb';
|
|
13
13
|
import type { OperatorSupport } from '@mastra/core/vector/filter';
|
|
14
|
+
import type { PaginationInfo } from '@mastra/core/storage';
|
|
14
15
|
import type { QueryResult } from '@mastra/core/vector';
|
|
15
16
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
17
|
+
import type { StorageColumn } from '@mastra/core/storage';
|
|
16
18
|
import type { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
19
|
+
import type { StorageGetTracesArg } from '@mastra/core/storage';
|
|
17
20
|
import type { StorageThreadType } from '@mastra/core/memory';
|
|
18
21
|
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
22
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
19
23
|
import type { UpdateVectorParams } from '@mastra/core/vector';
|
|
20
24
|
import type { UpsertVectorParams } from '@mastra/core/vector';
|
|
21
25
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
@@ -71,6 +75,17 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
71
75
|
private getConnection;
|
|
72
76
|
private getCollection;
|
|
73
77
|
createTable(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
80
|
+
* @param tableName Name of the table
|
|
81
|
+
* @param schema Schema of the table
|
|
82
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
83
|
+
*/
|
|
84
|
+
alterTable(_args: {
|
|
85
|
+
tableName: TABLE_NAMES;
|
|
86
|
+
schema: Record<string, StorageColumn>;
|
|
87
|
+
ifNotExists: string[];
|
|
88
|
+
}): Promise<void>;
|
|
74
89
|
clearTable({ tableName }: {
|
|
75
90
|
tableName: TABLE_NAMES;
|
|
76
91
|
}): Promise<void>;
|
|
@@ -103,7 +118,12 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
103
118
|
deleteThread({ threadId }: {
|
|
104
119
|
threadId: string;
|
|
105
120
|
}): Promise<void>;
|
|
106
|
-
getMessages
|
|
121
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
122
|
+
format?: 'v1';
|
|
123
|
+
}): Promise<MastraMessageV1[]>;
|
|
124
|
+
getMessages(args: StorageGetMessagesArg & {
|
|
125
|
+
format: 'v2';
|
|
126
|
+
}): Promise<MastraMessageV2[]>;
|
|
107
127
|
saveMessages(args: {
|
|
108
128
|
messages: MastraMessageV1[];
|
|
109
129
|
format?: undefined | 'v1';
|
|
@@ -153,6 +173,19 @@ declare class MongoDBStore extends MastraStorage {
|
|
|
153
173
|
private parseWorkflowRun;
|
|
154
174
|
private parseRow;
|
|
155
175
|
private transformEvalRow;
|
|
176
|
+
getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & {
|
|
177
|
+
traces: Trace[];
|
|
178
|
+
}>;
|
|
179
|
+
getThreadsByResourceIdPaginated(_args: {
|
|
180
|
+
resourceId: string;
|
|
181
|
+
page?: number;
|
|
182
|
+
perPage?: number;
|
|
183
|
+
}): Promise<PaginationInfo & {
|
|
184
|
+
threads: StorageThreadType[];
|
|
185
|
+
}>;
|
|
186
|
+
getMessagesPaginated(_args: StorageGetMessagesArg): Promise<PaginationInfo & {
|
|
187
|
+
messages: MastraMessageV1[] | MastraMessageV2[];
|
|
188
|
+
}>;
|
|
156
189
|
close(): Promise<void>;
|
|
157
190
|
}
|
|
158
191
|
export { MongoDBStore }
|
package/dist/index.cjs
CHANGED
|
@@ -447,6 +447,14 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
447
447
|
}
|
|
448
448
|
async createTable() {
|
|
449
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
452
|
+
* @param tableName Name of the table
|
|
453
|
+
* @param schema Schema of the table
|
|
454
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
455
|
+
*/
|
|
456
|
+
async alterTable(_args) {
|
|
457
|
+
}
|
|
450
458
|
async clearTable({ tableName }) {
|
|
451
459
|
try {
|
|
452
460
|
const collection = await this.getCollection(tableName);
|
|
@@ -584,7 +592,11 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
584
592
|
throw error;
|
|
585
593
|
}
|
|
586
594
|
}
|
|
587
|
-
async getMessages({
|
|
595
|
+
async getMessages({
|
|
596
|
+
threadId,
|
|
597
|
+
selectBy,
|
|
598
|
+
format
|
|
599
|
+
}) {
|
|
588
600
|
try {
|
|
589
601
|
const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
|
|
590
602
|
const include = selectBy?.include || [];
|
|
@@ -623,7 +635,9 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
623
635
|
}
|
|
624
636
|
}
|
|
625
637
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
626
|
-
|
|
638
|
+
const list = new agent.MessageList().add(messages.slice(0, limit), "memory");
|
|
639
|
+
if (format === `v2`) return list.get.all.v2();
|
|
640
|
+
return list.get.all.v1();
|
|
627
641
|
} catch (error) {
|
|
628
642
|
this.logger.error("Error getting messages:", error);
|
|
629
643
|
throw error;
|
|
@@ -898,7 +912,8 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
898
912
|
role: row.role,
|
|
899
913
|
type: row.type,
|
|
900
914
|
createdAt: new Date(row.createdAt),
|
|
901
|
-
threadId: row.thread_id
|
|
915
|
+
threadId: row.thread_id,
|
|
916
|
+
resourceId: row.resourceId
|
|
902
917
|
};
|
|
903
918
|
}
|
|
904
919
|
transformEvalRow(row) {
|
|
@@ -923,6 +938,15 @@ var MongoDBStore = class extends storage.MastraStorage {
|
|
|
923
938
|
createdAt: row.created_at
|
|
924
939
|
};
|
|
925
940
|
}
|
|
941
|
+
async getTracesPaginated(_args) {
|
|
942
|
+
throw new Error("Method not implemented.");
|
|
943
|
+
}
|
|
944
|
+
async getThreadsByResourceIdPaginated(_args) {
|
|
945
|
+
throw new Error("Method not implemented.");
|
|
946
|
+
}
|
|
947
|
+
async getMessagesPaginated(_args) {
|
|
948
|
+
throw new Error("Method not implemented.");
|
|
949
|
+
}
|
|
926
950
|
async close() {
|
|
927
951
|
await this.#client.close();
|
|
928
952
|
}
|
package/dist/index.js
CHANGED
|
@@ -445,6 +445,14 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
445
445
|
}
|
|
446
446
|
async createTable() {
|
|
447
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
450
|
+
* @param tableName Name of the table
|
|
451
|
+
* @param schema Schema of the table
|
|
452
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
453
|
+
*/
|
|
454
|
+
async alterTable(_args) {
|
|
455
|
+
}
|
|
448
456
|
async clearTable({ tableName }) {
|
|
449
457
|
try {
|
|
450
458
|
const collection = await this.getCollection(tableName);
|
|
@@ -582,7 +590,11 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
582
590
|
throw error;
|
|
583
591
|
}
|
|
584
592
|
}
|
|
585
|
-
async getMessages({
|
|
593
|
+
async getMessages({
|
|
594
|
+
threadId,
|
|
595
|
+
selectBy,
|
|
596
|
+
format
|
|
597
|
+
}) {
|
|
586
598
|
try {
|
|
587
599
|
const limit = typeof selectBy?.last === "number" ? selectBy.last : 40;
|
|
588
600
|
const include = selectBy?.include || [];
|
|
@@ -621,7 +633,9 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
621
633
|
}
|
|
622
634
|
}
|
|
623
635
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
624
|
-
|
|
636
|
+
const list = new MessageList().add(messages.slice(0, limit), "memory");
|
|
637
|
+
if (format === `v2`) return list.get.all.v2();
|
|
638
|
+
return list.get.all.v1();
|
|
625
639
|
} catch (error) {
|
|
626
640
|
this.logger.error("Error getting messages:", error);
|
|
627
641
|
throw error;
|
|
@@ -896,7 +910,8 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
896
910
|
role: row.role,
|
|
897
911
|
type: row.type,
|
|
898
912
|
createdAt: new Date(row.createdAt),
|
|
899
|
-
threadId: row.thread_id
|
|
913
|
+
threadId: row.thread_id,
|
|
914
|
+
resourceId: row.resourceId
|
|
900
915
|
};
|
|
901
916
|
}
|
|
902
917
|
transformEvalRow(row) {
|
|
@@ -921,6 +936,15 @@ var MongoDBStore = class extends MastraStorage {
|
|
|
921
936
|
createdAt: row.created_at
|
|
922
937
|
};
|
|
923
938
|
}
|
|
939
|
+
async getTracesPaginated(_args) {
|
|
940
|
+
throw new Error("Method not implemented.");
|
|
941
|
+
}
|
|
942
|
+
async getThreadsByResourceIdPaginated(_args) {
|
|
943
|
+
throw new Error("Method not implemented.");
|
|
944
|
+
}
|
|
945
|
+
async getMessagesPaginated(_args) {
|
|
946
|
+
throw new Error("Method not implemented.");
|
|
947
|
+
}
|
|
924
948
|
async close() {
|
|
925
949
|
await this.#client.close();
|
|
926
950
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mongodb",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.3-alpha.1",
|
|
4
4
|
"description": "MongoDB provider for Mastra - includes vector store capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,14 +25,15 @@
|
|
|
25
25
|
"uuid": "^11.1.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@microsoft/api-extractor": "^7.52.
|
|
29
|
-
"@types/node": "^20.17.
|
|
30
|
-
"eslint": "^9.
|
|
31
|
-
"tsup": "^8.
|
|
28
|
+
"@microsoft/api-extractor": "^7.52.8",
|
|
29
|
+
"@types/node": "^20.17.57",
|
|
30
|
+
"eslint": "^9.28.0",
|
|
31
|
+
"tsup": "^8.5.0",
|
|
32
32
|
"typescript": "^5.8.2",
|
|
33
|
-
"vitest": "^3.
|
|
34
|
-
"@internal/lint": "0.0.
|
|
35
|
-
"@mastra/core": "0.10.
|
|
33
|
+
"vitest": "^3.2.2",
|
|
34
|
+
"@internal/lint": "0.0.10",
|
|
35
|
+
"@mastra/core": "0.10.4-alpha.3",
|
|
36
|
+
"@internal/storage-test-utils": "0.0.6"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
39
|
"@mastra/core": "^0.10.2-alpha.0"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import type { MastraMessageV1, MetricResult, WorkflowRunState } from '@mastra/core';
|
|
2
|
+
import type { MastraMessageV1, MastraMessageV2, MetricResult, WorkflowRunState } from '@mastra/core';
|
|
3
|
+
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
3
4
|
import { TABLE_EVALS, TABLE_MESSAGES, TABLE_THREADS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
|
|
4
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
5
|
+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
5
6
|
import type { MongoDBConfig } from './index';
|
|
6
7
|
import { MongoDBStore } from './index';
|
|
7
8
|
|
|
@@ -40,15 +41,46 @@ class Test {
|
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
generateSampleMessageV1({
|
|
45
|
+
threadId,
|
|
46
|
+
resourceId = randomUUID(),
|
|
47
|
+
content = 'Hello',
|
|
48
|
+
}: {
|
|
49
|
+
threadId: string;
|
|
50
|
+
resourceId?: string;
|
|
51
|
+
content?: string;
|
|
52
|
+
}): MastraMessageV1 {
|
|
44
53
|
return {
|
|
45
54
|
id: `msg-${randomUUID()}`,
|
|
46
55
|
role: 'user',
|
|
47
56
|
type: 'text',
|
|
48
57
|
threadId,
|
|
49
|
-
content: [{ type: 'text', text:
|
|
58
|
+
content: [{ type: 'text', text: content }],
|
|
50
59
|
createdAt: new Date(),
|
|
51
|
-
resourceId
|
|
60
|
+
resourceId,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
generateSampleMessageV2({
|
|
65
|
+
threadId,
|
|
66
|
+
resourceId = randomUUID(),
|
|
67
|
+
content = 'Hello',
|
|
68
|
+
}: {
|
|
69
|
+
threadId: string;
|
|
70
|
+
resourceId?: string;
|
|
71
|
+
content?: string;
|
|
72
|
+
}): MastraMessageV2 {
|
|
73
|
+
return {
|
|
74
|
+
id: `msg-${randomUUID()}`,
|
|
75
|
+
role: 'user',
|
|
76
|
+
type: 'text',
|
|
77
|
+
threadId,
|
|
78
|
+
content: {
|
|
79
|
+
format: 2,
|
|
80
|
+
parts: [{ type: 'text', text: content }],
|
|
81
|
+
},
|
|
82
|
+
createdAt: new Date(),
|
|
83
|
+
resourceId,
|
|
52
84
|
};
|
|
53
85
|
}
|
|
54
86
|
|
|
@@ -201,7 +233,10 @@ describe('MongoDBStore', () => {
|
|
|
201
233
|
await store.saveThread({ thread });
|
|
202
234
|
|
|
203
235
|
// Add some messages
|
|
204
|
-
const messages = [
|
|
236
|
+
const messages = [
|
|
237
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
238
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
239
|
+
];
|
|
205
240
|
await store.saveMessages({ messages });
|
|
206
241
|
|
|
207
242
|
await store.deleteThread({ threadId: thread.id });
|
|
@@ -246,8 +281,8 @@ describe('MongoDBStore', () => {
|
|
|
246
281
|
await store.saveThread({ thread });
|
|
247
282
|
|
|
248
283
|
const messages = [
|
|
249
|
-
test.
|
|
250
|
-
{ ...test.
|
|
284
|
+
test.generateSampleMessageV1({ threadId: thread.id }),
|
|
285
|
+
{ ...test.generateSampleMessageV1({ threadId: thread.id }), role: 'assistant' as const },
|
|
251
286
|
];
|
|
252
287
|
|
|
253
288
|
// Save messages
|
|
@@ -277,29 +312,129 @@ describe('MongoDBStore', () => {
|
|
|
277
312
|
|
|
278
313
|
const messages = [
|
|
279
314
|
{
|
|
280
|
-
...test.
|
|
281
|
-
content: [{ type: 'text', text: 'First' }] as MastraMessageV1['content'],
|
|
315
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'First' }),
|
|
282
316
|
},
|
|
283
317
|
{
|
|
284
|
-
...test.
|
|
285
|
-
content: [{ type: 'text', text: 'Second' }] as MastraMessageV1['content'],
|
|
318
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'Second' }),
|
|
286
319
|
},
|
|
287
320
|
{
|
|
288
|
-
...test.
|
|
289
|
-
content: [{ type: 'text', text: 'Third' }] as MastraMessageV1['content'],
|
|
321
|
+
...test.generateSampleMessageV2({ threadId: thread.id, content: 'Third' }),
|
|
290
322
|
},
|
|
291
323
|
];
|
|
292
324
|
|
|
293
|
-
await store.saveMessages({ messages });
|
|
325
|
+
await store.saveMessages({ messages, format: 'v2' });
|
|
294
326
|
|
|
295
|
-
const retrievedMessages = await store.getMessages({ threadId: thread.id });
|
|
327
|
+
const retrievedMessages = await store.getMessages({ threadId: thread.id, format: 'v2' });
|
|
296
328
|
expect(retrievedMessages).toHaveLength(3);
|
|
297
329
|
|
|
298
330
|
// Verify order is maintained
|
|
299
331
|
retrievedMessages.forEach((msg, idx) => {
|
|
300
|
-
expect((
|
|
332
|
+
expect((msg as any).content.parts).toEqual(messages[idx]!.content.parts);
|
|
301
333
|
});
|
|
302
334
|
});
|
|
335
|
+
|
|
336
|
+
// it('should retrieve messages w/ next/prev messages by message id + resource id', async () => {
|
|
337
|
+
// const test = new Test(store).build();
|
|
338
|
+
// const messages: MastraMessageV2[] = [
|
|
339
|
+
// test.generateSampleMessageV2({ threadId: 'thread-one', content: 'First', resourceId: 'cross-thread-resource' }),
|
|
340
|
+
// test.generateSampleMessageV2({
|
|
341
|
+
// threadId: 'thread-one',
|
|
342
|
+
// content: 'Second',
|
|
343
|
+
// resourceId: 'cross-thread-resource',
|
|
344
|
+
// }),
|
|
345
|
+
// test.generateSampleMessageV2({ threadId: 'thread-one', content: 'Third', resourceId: 'cross-thread-resource' }),
|
|
346
|
+
|
|
347
|
+
// test.generateSampleMessageV2({
|
|
348
|
+
// threadId: 'thread-two',
|
|
349
|
+
// content: 'Fourth',
|
|
350
|
+
// resourceId: 'cross-thread-resource',
|
|
351
|
+
// }),
|
|
352
|
+
// test.generateSampleMessageV2({ threadId: 'thread-two', content: 'Fifth', resourceId: 'cross-thread-resource' }),
|
|
353
|
+
// test.generateSampleMessageV2({ threadId: 'thread-two', content: 'Sixth', resourceId: 'cross-thread-resource' }),
|
|
354
|
+
|
|
355
|
+
// test.generateSampleMessageV2({ threadId: 'thread-three', content: 'Seventh', resourceId: 'other-resource' }),
|
|
356
|
+
// test.generateSampleMessageV2({ threadId: 'thread-three', content: 'Eighth', resourceId: 'other-resource' }),
|
|
357
|
+
// ];
|
|
358
|
+
|
|
359
|
+
// await store.saveMessages({ messages: messages, format: 'v2' });
|
|
360
|
+
|
|
361
|
+
// const retrievedMessages: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-one', format: 'v2' });
|
|
362
|
+
// expect(retrievedMessages).toHaveLength(3);
|
|
363
|
+
// expect(retrievedMessages.map(m => (m.content.parts[0] as any).text)).toEqual(['First', 'Second', 'Third']);
|
|
364
|
+
|
|
365
|
+
// const retrievedMessages2: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-two', format: 'v2' });
|
|
366
|
+
// expect(retrievedMessages2).toHaveLength(3);
|
|
367
|
+
// expect(retrievedMessages2.map(m => (m.content.parts[0] as any).text)).toEqual(['Fourth', 'Fifth', 'Sixth']);
|
|
368
|
+
|
|
369
|
+
// const retrievedMessages3: MastraMessageV2[] = await store.getMessages({ threadId: 'thread-three', format: 'v2' });
|
|
370
|
+
// expect(retrievedMessages3).toHaveLength(2);
|
|
371
|
+
// expect(retrievedMessages3.map(m => (m.content.parts[0] as any).text)).toEqual(['Seventh', 'Eighth']);
|
|
372
|
+
|
|
373
|
+
// const crossThreadMessages: MastraMessageV2[] = await store.getMessages({
|
|
374
|
+
// threadId: 'thread-doesnt-exist',
|
|
375
|
+
// resourceId: 'cross-thread-resource',
|
|
376
|
+
// format: 'v2',
|
|
377
|
+
// selectBy: {
|
|
378
|
+
// last: 0,
|
|
379
|
+
// include: [
|
|
380
|
+
// {
|
|
381
|
+
// id: messages[1].id,
|
|
382
|
+
// withNextMessages: 2,
|
|
383
|
+
// withPreviousMessages: 2,
|
|
384
|
+
// },
|
|
385
|
+
// {
|
|
386
|
+
// id: messages[4].id,
|
|
387
|
+
// withPreviousMessages: 2,
|
|
388
|
+
// withNextMessages: 2,
|
|
389
|
+
// },
|
|
390
|
+
// ],
|
|
391
|
+
// },
|
|
392
|
+
// });
|
|
393
|
+
|
|
394
|
+
// expect(crossThreadMessages).toHaveLength(6);
|
|
395
|
+
// expect(crossThreadMessages.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
396
|
+
// expect(crossThreadMessages.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
397
|
+
|
|
398
|
+
// const crossThreadMessages2: MastraMessageV2[] = await store.getMessages({
|
|
399
|
+
// threadId: 'thread-one',
|
|
400
|
+
// resourceId: 'cross-thread-resource',
|
|
401
|
+
// format: 'v2',
|
|
402
|
+
// selectBy: {
|
|
403
|
+
// last: 0,
|
|
404
|
+
// include: [
|
|
405
|
+
// {
|
|
406
|
+
// id: messages[4].id,
|
|
407
|
+
// withPreviousMessages: 1,
|
|
408
|
+
// withNextMessages: 30,
|
|
409
|
+
// },
|
|
410
|
+
// ],
|
|
411
|
+
// },
|
|
412
|
+
// });
|
|
413
|
+
|
|
414
|
+
// expect(crossThreadMessages2).toHaveLength(3);
|
|
415
|
+
// expect(crossThreadMessages2.filter(m => m.threadId === `thread-one`)).toHaveLength(0);
|
|
416
|
+
// expect(crossThreadMessages2.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
417
|
+
|
|
418
|
+
// const crossThreadMessages3: MastraMessageV2[] = await store.getMessages({
|
|
419
|
+
// threadId: 'thread-two',
|
|
420
|
+
// resourceId: 'cross-thread-resource',
|
|
421
|
+
// format: 'v2',
|
|
422
|
+
// selectBy: {
|
|
423
|
+
// last: 0,
|
|
424
|
+
// include: [
|
|
425
|
+
// {
|
|
426
|
+
// id: messages[1].id,
|
|
427
|
+
// withNextMessages: 1,
|
|
428
|
+
// withPreviousMessages: 1,
|
|
429
|
+
// },
|
|
430
|
+
// ],
|
|
431
|
+
// },
|
|
432
|
+
// });
|
|
433
|
+
|
|
434
|
+
// expect(crossThreadMessages3).toHaveLength(3);
|
|
435
|
+
// expect(crossThreadMessages3.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
436
|
+
// expect(crossThreadMessages3.filter(m => m.threadId === `thread-two`)).toHaveLength(0);
|
|
437
|
+
// });
|
|
303
438
|
});
|
|
304
439
|
|
|
305
440
|
describe('Edge Cases and Error Handling', () => {
|
|
@@ -773,6 +908,89 @@ describe('MongoDBStore', () => {
|
|
|
773
908
|
});
|
|
774
909
|
});
|
|
775
910
|
|
|
911
|
+
describe('alterTable (no-op/schemaless)', () => {
|
|
912
|
+
const TEST_TABLE = 'test_alter_table'; // Use "table" or "collection" as appropriate
|
|
913
|
+
beforeEach(async () => {
|
|
914
|
+
await store.clearTable({ tableName: TEST_TABLE as TABLE_NAMES });
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
afterEach(async () => {
|
|
918
|
+
await store.clearTable({ tableName: TEST_TABLE as TABLE_NAMES });
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
it('allows inserting records with new fields without alterTable', async () => {
|
|
922
|
+
await store.insert({
|
|
923
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
924
|
+
record: { id: '1', name: 'Alice' },
|
|
925
|
+
});
|
|
926
|
+
await store.insert({
|
|
927
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
928
|
+
record: { id: '2', name: 'Bob', newField: 123 },
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
const row = await store.load<{ id: string; name: string; newField?: number }[]>({
|
|
932
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
933
|
+
keys: { id: '2' },
|
|
934
|
+
});
|
|
935
|
+
expect(row?.[0]?.newField).toBe(123);
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
it('does not throw when calling alterTable (no-op)', async () => {
|
|
939
|
+
await expect(
|
|
940
|
+
store.alterTable({
|
|
941
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
942
|
+
schema: {
|
|
943
|
+
id: { type: 'text', primaryKey: true, nullable: false },
|
|
944
|
+
name: { type: 'text', nullable: true },
|
|
945
|
+
extra: { type: 'integer', nullable: true },
|
|
946
|
+
},
|
|
947
|
+
ifNotExists: ['extra'],
|
|
948
|
+
}),
|
|
949
|
+
).resolves.not.toThrow();
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
it('can add multiple new fields at write time', async () => {
|
|
953
|
+
await store.insert({
|
|
954
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
955
|
+
record: { id: '3', name: 'Charlie', age: 30, city: 'Paris' },
|
|
956
|
+
});
|
|
957
|
+
const row = await store.load<{ id: string; name: string; age?: number; city?: string }[]>({
|
|
958
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
959
|
+
keys: { id: '3' },
|
|
960
|
+
});
|
|
961
|
+
expect(row?.[0]?.age).toBe(30);
|
|
962
|
+
expect(row?.[0]?.city).toBe('Paris');
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
it('can retrieve all fields, including dynamically added ones', async () => {
|
|
966
|
+
await store.insert({
|
|
967
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
968
|
+
record: { id: '4', name: 'Dana', hobby: 'skiing' },
|
|
969
|
+
});
|
|
970
|
+
const row = await store.load<{ id: string; name: string; hobby?: string }[]>({
|
|
971
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
972
|
+
keys: { id: '4' },
|
|
973
|
+
});
|
|
974
|
+
expect(row?.[0]?.hobby).toBe('skiing');
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
it('does not restrict or error on arbitrary new fields', async () => {
|
|
978
|
+
await expect(
|
|
979
|
+
store.insert({
|
|
980
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
981
|
+
record: { id: '5', weirdField: { nested: true }, another: [1, 2, 3] },
|
|
982
|
+
}),
|
|
983
|
+
).resolves.not.toThrow();
|
|
984
|
+
|
|
985
|
+
const row = await store.load<{ id: string; weirdField?: any; another?: any }[]>({
|
|
986
|
+
tableName: TEST_TABLE as TABLE_NAMES,
|
|
987
|
+
keys: { id: '5' },
|
|
988
|
+
});
|
|
989
|
+
expect(row?.[0]?.weirdField).toEqual({ nested: true });
|
|
990
|
+
expect(row?.[0]?.another).toEqual([1, 2, 3]);
|
|
991
|
+
});
|
|
992
|
+
});
|
|
993
|
+
|
|
776
994
|
afterAll(async () => {
|
|
777
995
|
try {
|
|
778
996
|
await store.close();
|
package/src/storage/index.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { MessageList } from '@mastra/core/agent';
|
|
2
2
|
import type { MetricResult, TestInfo } from '@mastra/core/eval';
|
|
3
3
|
import type { MastraMessageV1, MastraMessageV2, StorageThreadType } from '@mastra/core/memory';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
EvalRow,
|
|
6
|
+
PaginationInfo,
|
|
7
|
+
StorageColumn,
|
|
8
|
+
StorageGetMessagesArg,
|
|
9
|
+
StorageGetTracesArg,
|
|
10
|
+
TABLE_NAMES,
|
|
11
|
+
WorkflowRun,
|
|
12
|
+
} from '@mastra/core/storage';
|
|
5
13
|
import {
|
|
6
14
|
MastraStorage,
|
|
7
15
|
TABLE_EVALS,
|
|
@@ -10,6 +18,7 @@ import {
|
|
|
10
18
|
TABLE_TRACES,
|
|
11
19
|
TABLE_WORKFLOW_SNAPSHOT,
|
|
12
20
|
} from '@mastra/core/storage';
|
|
21
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
13
22
|
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
14
23
|
import type { Db, MongoClientOptions } from 'mongodb';
|
|
15
24
|
import { MongoClient } from 'mongodb';
|
|
@@ -74,6 +83,20 @@ export class MongoDBStore extends MastraStorage {
|
|
|
74
83
|
// Nothing to do here, MongoDB is schemaless
|
|
75
84
|
}
|
|
76
85
|
|
|
86
|
+
/**
|
|
87
|
+
* No-op: This backend is schemaless and does not require schema changes.
|
|
88
|
+
* @param tableName Name of the table
|
|
89
|
+
* @param schema Schema of the table
|
|
90
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
91
|
+
*/
|
|
92
|
+
async alterTable(_args: {
|
|
93
|
+
tableName: TABLE_NAMES;
|
|
94
|
+
schema: Record<string, StorageColumn>;
|
|
95
|
+
ifNotExists: string[];
|
|
96
|
+
}): Promise<void> {
|
|
97
|
+
// Nothing to do here, MongoDB is schemaless
|
|
98
|
+
}
|
|
99
|
+
|
|
77
100
|
async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
|
|
78
101
|
try {
|
|
79
102
|
const collection = await this.getCollection(tableName);
|
|
@@ -232,7 +255,15 @@ export class MongoDBStore extends MastraStorage {
|
|
|
232
255
|
}
|
|
233
256
|
}
|
|
234
257
|
|
|
235
|
-
async getMessages
|
|
258
|
+
public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
|
|
259
|
+
public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
260
|
+
public async getMessages({
|
|
261
|
+
threadId,
|
|
262
|
+
selectBy,
|
|
263
|
+
format,
|
|
264
|
+
}: StorageGetMessagesArg & {
|
|
265
|
+
format?: 'v1' | 'v2';
|
|
266
|
+
}): Promise<MastraMessageV1[] | MastraMessageV2[]> {
|
|
236
267
|
try {
|
|
237
268
|
const limit = typeof selectBy?.last === 'number' ? selectBy.last : 40;
|
|
238
269
|
const include = selectBy?.include || [];
|
|
@@ -287,7 +318,9 @@ export class MongoDBStore extends MastraStorage {
|
|
|
287
318
|
// Sort all messages by creation date ascending
|
|
288
319
|
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
289
320
|
|
|
290
|
-
|
|
321
|
+
const list = new MessageList().add(messages.slice(0, limit), 'memory');
|
|
322
|
+
if (format === `v2`) return list.get.all.v2();
|
|
323
|
+
return list.get.all.v1();
|
|
291
324
|
} catch (error) {
|
|
292
325
|
this.logger.error('Error getting messages:', error as Error);
|
|
293
326
|
throw error;
|
|
@@ -652,6 +685,7 @@ export class MongoDBStore extends MastraStorage {
|
|
|
652
685
|
type: row.type,
|
|
653
686
|
createdAt: new Date(row.createdAt as string),
|
|
654
687
|
threadId: row.thread_id,
|
|
688
|
+
resourceId: row.resourceId,
|
|
655
689
|
} as MastraMessageV2;
|
|
656
690
|
}
|
|
657
691
|
|
|
@@ -679,6 +713,24 @@ export class MongoDBStore extends MastraStorage {
|
|
|
679
713
|
};
|
|
680
714
|
}
|
|
681
715
|
|
|
716
|
+
async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
|
|
717
|
+
throw new Error('Method not implemented.');
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
async getThreadsByResourceIdPaginated(_args: {
|
|
721
|
+
resourceId: string;
|
|
722
|
+
page?: number;
|
|
723
|
+
perPage?: number;
|
|
724
|
+
}): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
|
|
725
|
+
throw new Error('Method not implemented.');
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
async getMessagesPaginated(
|
|
729
|
+
_args: StorageGetMessagesArg,
|
|
730
|
+
): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
|
|
731
|
+
throw new Error('Method not implemented.');
|
|
732
|
+
}
|
|
733
|
+
|
|
682
734
|
async close(): Promise<void> {
|
|
683
735
|
await this.#client.close();
|
|
684
736
|
}
|