@mastra/upstash 0.1.5 → 0.1.6-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 +5 -5
- package/CHANGELOG.md +19 -0
- package/dist/_tsup-dts-rollup.d.ts +12 -12
- package/dist/index.js +3 -11
- package/eslint.config.js +6 -0
- package/package.json +7 -4
- package/src/storage/index.ts +7 -18
- package/src/storage/upstash.test.ts +330 -324
- package/src/vector/filter.ts +2 -1
- package/src/vector/index.test.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/upstash@0.1.
|
|
2
|
+
> @mastra/upstash@0.1.6-alpha.1 build /home/runner/work/mastra/mastra/stores/upstash
|
|
3
3
|
> tsup src/index.ts --format esm --experimental-dts --clean --treeshake
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
7
|
[34mCLI[39m tsup v8.3.6
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 8433ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.7.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/upstash/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
|
-
[32mDTS[39m ⚡️ Build success in
|
|
14
|
+
[32mDTS[39m ⚡️ Build success in 6040ms
|
|
15
15
|
[34mCLI[39m Cleaning output folder
|
|
16
16
|
[34mESM[39m Build start
|
|
17
|
-
[32mESM[39m [1mdist/index.js [22m[
|
|
18
|
-
[32mESM[39m ⚡️ Build success in
|
|
17
|
+
[32mESM[39m [1mdist/index.js [22m[32m15.98 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 577ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @mastra/upstash
|
|
2
2
|
|
|
3
|
+
## 0.1.6-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [0d185b1]
|
|
8
|
+
- Updated dependencies [ed55f1d]
|
|
9
|
+
- Updated dependencies [8d13b14]
|
|
10
|
+
- Updated dependencies [3ee4831]
|
|
11
|
+
- Updated dependencies [108793c]
|
|
12
|
+
- Updated dependencies [5f28f44]
|
|
13
|
+
- @mastra/core@0.4.3-alpha.1
|
|
14
|
+
|
|
15
|
+
## 0.1.6-alpha.0
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [06aa827]
|
|
20
|
+
- @mastra/core@0.4.3-alpha.0
|
|
21
|
+
|
|
3
22
|
## 0.1.5
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
-
import { EvalRow } from '@mastra/core/storage';
|
|
3
|
-
import { Filter } from '@mastra/core/filter';
|
|
2
|
+
import type { EvalRow } from '@mastra/core/storage';
|
|
3
|
+
import type { Filter } from '@mastra/core/filter';
|
|
4
4
|
import { MastraStorage } from '@mastra/core/storage';
|
|
5
5
|
import { MastraVector } from '@mastra/core/vector';
|
|
6
|
-
import { MessageType } from '@mastra/core/memory';
|
|
7
|
-
import { OperatorSupport } from '@mastra/core/filter';
|
|
6
|
+
import type { MessageType } from '@mastra/core/memory';
|
|
7
|
+
import type { OperatorSupport } from '@mastra/core/filter';
|
|
8
8
|
import type { QueryResult } from '@mastra/core/vector';
|
|
9
|
-
import { StorageColumn } from '@mastra/core/storage';
|
|
10
|
-
import { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
11
|
-
import { StorageThreadType } from '@mastra/core/memory';
|
|
12
|
-
import { TABLE_NAMES } from '@mastra/core/storage';
|
|
13
|
-
import { WorkflowRunState } from '@mastra/core/workflows';
|
|
9
|
+
import type { StorageColumn } from '@mastra/core/storage';
|
|
10
|
+
import type { StorageGetMessagesArg } from '@mastra/core/storage';
|
|
11
|
+
import type { StorageThreadType } from '@mastra/core/memory';
|
|
12
|
+
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
13
|
+
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
14
14
|
|
|
15
15
|
declare interface UpstashConfig {
|
|
16
16
|
url: string;
|
|
@@ -34,12 +34,12 @@ export declare class UpstashFilterTranslator extends BaseFilterTranslator {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
declare class UpstashStore extends MastraStorage {
|
|
37
|
-
batchInsert(
|
|
37
|
+
batchInsert(_input: {
|
|
38
38
|
tableName: TABLE_NAMES;
|
|
39
39
|
records: Record<string, any>[];
|
|
40
40
|
}): Promise<void>;
|
|
41
|
-
getEvalsByAgentName(
|
|
42
|
-
getTraces(
|
|
41
|
+
getEvalsByAgentName(_agentName: string, _type?: 'test' | 'live'): Promise<EvalRow[]>;
|
|
42
|
+
getTraces(_input: {
|
|
43
43
|
name?: string;
|
|
44
44
|
scope?: string;
|
|
45
45
|
page: number;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import '@mastra/core/memory';
|
|
2
1
|
import { MastraStorage } from '@mastra/core/storage';
|
|
3
|
-
import '@mastra/core/workflows';
|
|
4
2
|
import { Redis } from '@upstash/redis';
|
|
5
3
|
import { MastraVector } from '@mastra/core/vector';
|
|
6
4
|
import { Index } from '@upstash/vector';
|
|
@@ -8,19 +6,13 @@ import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
|
8
6
|
|
|
9
7
|
// src/storage/index.ts
|
|
10
8
|
var UpstashStore = class extends MastraStorage {
|
|
11
|
-
batchInsert(
|
|
9
|
+
batchInsert(_input) {
|
|
12
10
|
throw new Error("Method not implemented.");
|
|
13
11
|
}
|
|
14
|
-
getEvalsByAgentName(
|
|
12
|
+
getEvalsByAgentName(_agentName, _type) {
|
|
15
13
|
throw new Error("Method not implemented.");
|
|
16
14
|
}
|
|
17
|
-
getTraces({
|
|
18
|
-
name,
|
|
19
|
-
scope,
|
|
20
|
-
page,
|
|
21
|
-
perPage,
|
|
22
|
-
attributes
|
|
23
|
-
}) {
|
|
15
|
+
getTraces(_input) {
|
|
24
16
|
throw new Error("Method not implemented.");
|
|
25
17
|
}
|
|
26
18
|
redis;
|
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/upstash",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6-alpha.1",
|
|
4
4
|
"description": "Upstash provider for Mastra - includes both vector and db storage capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,20 +17,23 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@upstash/redis": "^1.28.3",
|
|
19
19
|
"@upstash/vector": "^1.1.7",
|
|
20
|
-
"@mastra/core": "^0.4.
|
|
20
|
+
"@mastra/core": "^0.4.3-alpha.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@microsoft/api-extractor": "^7.49.2",
|
|
24
24
|
"@types/node": "^22.13.1",
|
|
25
25
|
"tsup": "^8.0.1",
|
|
26
26
|
"typescript": "^5.7.3",
|
|
27
|
-
"vitest": "^3.0.4"
|
|
27
|
+
"vitest": "^3.0.4",
|
|
28
|
+
"eslint": "^9.20.1",
|
|
29
|
+
"@internal/lint": "0.0.0"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
30
32
|
"pretest": "docker compose up -d",
|
|
31
33
|
"test": "vitest run",
|
|
32
34
|
"posttest": "docker compose down",
|
|
33
35
|
"build": "tsup src/index.ts --format esm --experimental-dts --clean --treeshake",
|
|
34
|
-
"build:watch": "pnpm build --watch"
|
|
36
|
+
"build:watch": "pnpm build --watch",
|
|
37
|
+
"lint": "eslint ."
|
|
35
38
|
}
|
|
36
39
|
}
|
package/src/storage/index.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type StorageColumn,
|
|
6
|
-
type StorageGetMessagesArg,
|
|
7
|
-
type EvalRow,
|
|
8
|
-
} from '@mastra/core/storage';
|
|
9
|
-
import { type WorkflowRunState } from '@mastra/core/workflows';
|
|
1
|
+
import type { StorageThreadType, MessageType } from '@mastra/core/memory';
|
|
2
|
+
import { MastraStorage } from '@mastra/core/storage';
|
|
3
|
+
import type { TABLE_NAMES, StorageColumn, StorageGetMessagesArg, EvalRow } from '@mastra/core/storage';
|
|
4
|
+
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
10
5
|
import { Redis } from '@upstash/redis';
|
|
11
6
|
|
|
12
7
|
export interface UpstashConfig {
|
|
@@ -15,19 +10,13 @@ export interface UpstashConfig {
|
|
|
15
10
|
}
|
|
16
11
|
|
|
17
12
|
export class UpstashStore extends MastraStorage {
|
|
18
|
-
batchInsert(
|
|
13
|
+
batchInsert(_input: { tableName: TABLE_NAMES; records: Record<string, any>[] }): Promise<void> {
|
|
19
14
|
throw new Error('Method not implemented.');
|
|
20
15
|
}
|
|
21
|
-
getEvalsByAgentName(
|
|
16
|
+
getEvalsByAgentName(_agentName: string, _type?: 'test' | 'live'): Promise<EvalRow[]> {
|
|
22
17
|
throw new Error('Method not implemented.');
|
|
23
18
|
}
|
|
24
|
-
getTraces({
|
|
25
|
-
name,
|
|
26
|
-
scope,
|
|
27
|
-
page,
|
|
28
|
-
perPage,
|
|
29
|
-
attributes,
|
|
30
|
-
}: {
|
|
19
|
+
getTraces(_input: {
|
|
31
20
|
name?: string;
|
|
32
21
|
scope?: string;
|
|
33
22
|
page: number;
|
|
@@ -3,379 +3,385 @@ import { describe, it, expect, beforeAll, beforeEach, afterAll } from 'vitest';
|
|
|
3
3
|
|
|
4
4
|
import { UpstashStore } from './index';
|
|
5
5
|
|
|
6
|
-
describe(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterAll(async () => {
|
|
20
|
-
// Clean up test tables
|
|
21
|
-
await store.clearTable({ tableName: testTableName });
|
|
22
|
-
await store.clearTable({ tableName: testTableName2 });
|
|
23
|
-
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
24
|
-
await store.clearTable({ tableName: MastraStorage.TABLE_MESSAGES });
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('Table Operations', () => {
|
|
28
|
-
it('should create a new table with schema', async () => {
|
|
29
|
-
await store.createTable({
|
|
30
|
-
tableName: testTableName,
|
|
31
|
-
schema: {
|
|
32
|
-
id: { type: 'text', primaryKey: true },
|
|
33
|
-
data: { type: 'text', nullable: true },
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Verify table exists by inserting and retrieving data
|
|
38
|
-
await store.insert({
|
|
39
|
-
tableName: testTableName,
|
|
40
|
-
record: { id: 'test1', data: 'test-data' },
|
|
6
|
+
describe(
|
|
7
|
+
'UpstashStore',
|
|
8
|
+
() => {
|
|
9
|
+
let store: UpstashStore;
|
|
10
|
+
const testTableName = 'test_table';
|
|
11
|
+
const testTableName2 = 'test_table2';
|
|
12
|
+
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
store = new UpstashStore({
|
|
15
|
+
url: 'http://localhost:8079',
|
|
16
|
+
token: 'test_token',
|
|
41
17
|
});
|
|
18
|
+
await store.init();
|
|
19
|
+
});
|
|
42
20
|
|
|
43
|
-
|
|
44
|
-
|
|
21
|
+
afterAll(async () => {
|
|
22
|
+
// Clean up test tables
|
|
23
|
+
await store.clearTable({ tableName: testTableName });
|
|
24
|
+
await store.clearTable({ tableName: testTableName2 });
|
|
25
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
26
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_MESSAGES });
|
|
45
27
|
});
|
|
46
28
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
29
|
+
describe('Table Operations', () => {
|
|
30
|
+
it('should create a new table with schema', async () => {
|
|
31
|
+
await store.createTable({
|
|
32
|
+
tableName: testTableName,
|
|
33
|
+
schema: {
|
|
34
|
+
id: { type: 'text', primaryKey: true },
|
|
35
|
+
data: { type: 'text', nullable: true },
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Verify table exists by inserting and retrieving data
|
|
40
|
+
await store.insert({
|
|
41
|
+
tableName: testTableName,
|
|
42
|
+
record: { id: 'test1', data: 'test-data' },
|
|
43
|
+
});
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
tableName: testTableName2,
|
|
59
|
-
record: { id: 'test2', data: 'test-data-2' },
|
|
45
|
+
const result = await store.load({ tableName: testTableName, keys: { id: 'test1' } });
|
|
46
|
+
expect(result).toBeTruthy();
|
|
60
47
|
});
|
|
61
48
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
49
|
+
it('should handle multiple table creation', async () => {
|
|
50
|
+
await store.createTable({
|
|
51
|
+
tableName: testTableName2,
|
|
52
|
+
schema: {
|
|
53
|
+
id: { type: 'text', primaryKey: true },
|
|
54
|
+
data: { type: 'text', nullable: true },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
58
|
+
// Verify both tables work independently
|
|
59
|
+
await store.insert({
|
|
60
|
+
tableName: testTableName2,
|
|
61
|
+
record: { id: 'test2', data: 'test-data-2' },
|
|
62
|
+
});
|
|
71
63
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const thread = {
|
|
75
|
-
id: 'thread-1',
|
|
76
|
-
resourceId: 'resource-1',
|
|
77
|
-
title: 'Test Thread',
|
|
78
|
-
createdAt: now,
|
|
79
|
-
updatedAt: now,
|
|
80
|
-
metadata: { key: 'value' },
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const savedThread = await store.saveThread({ thread });
|
|
84
|
-
expect(savedThread).toEqual(thread);
|
|
85
|
-
|
|
86
|
-
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
87
|
-
expect(retrievedThread).toEqual({
|
|
88
|
-
...thread,
|
|
89
|
-
createdAt: new Date(now.toISOString()),
|
|
90
|
-
updatedAt: new Date(now.toISOString()),
|
|
64
|
+
const result = await store.load({ tableName: testTableName2, keys: { id: 'test2' } });
|
|
65
|
+
expect(result).toBeTruthy();
|
|
91
66
|
});
|
|
92
67
|
});
|
|
93
68
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
69
|
+
describe('Thread Operations', () => {
|
|
70
|
+
beforeEach(async () => {
|
|
71
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
72
|
+
});
|
|
98
73
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{
|
|
74
|
+
it('should create and retrieve a thread', async () => {
|
|
75
|
+
const now = new Date();
|
|
76
|
+
const thread = {
|
|
103
77
|
id: 'thread-1',
|
|
104
|
-
resourceId,
|
|
105
|
-
title: 'Thread
|
|
106
|
-
createdAt:
|
|
107
|
-
updatedAt:
|
|
108
|
-
metadata: {},
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
await Promise.all(threads.map(thread => store.saveThread({ thread })));
|
|
121
|
-
|
|
122
|
-
const retrievedThreads = await store.getThreadsByResourceId({ resourceId });
|
|
123
|
-
expect(retrievedThreads).toHaveLength(2);
|
|
124
|
-
expect(retrievedThreads.map(t => t.id)).toEqual(expect.arrayContaining(['thread-1', 'thread-2']));
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should update thread metadata', async () => {
|
|
128
|
-
const thread = {
|
|
129
|
-
id: 'thread-1',
|
|
130
|
-
resourceId: 'resource-1',
|
|
131
|
-
title: 'Test Thread',
|
|
132
|
-
createdAt: new Date(),
|
|
133
|
-
updatedAt: new Date(),
|
|
134
|
-
metadata: { initial: 'value' },
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
await store.saveThread({ thread });
|
|
138
|
-
|
|
139
|
-
const updatedThread = await store.updateThread({
|
|
140
|
-
id: thread.id,
|
|
141
|
-
title: 'Updated Title',
|
|
142
|
-
metadata: { updated: 'value' },
|
|
78
|
+
resourceId: 'resource-1',
|
|
79
|
+
title: 'Test Thread',
|
|
80
|
+
createdAt: now,
|
|
81
|
+
updatedAt: now,
|
|
82
|
+
metadata: { key: 'value' },
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const savedThread = await store.saveThread({ thread });
|
|
86
|
+
expect(savedThread).toEqual(thread);
|
|
87
|
+
|
|
88
|
+
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
89
|
+
expect(retrievedThread).toEqual({
|
|
90
|
+
...thread,
|
|
91
|
+
createdAt: new Date(now.toISOString()),
|
|
92
|
+
updatedAt: new Date(now.toISOString()),
|
|
93
|
+
});
|
|
143
94
|
});
|
|
144
95
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
updated: 'value',
|
|
96
|
+
it('should return null for non-existent thread', async () => {
|
|
97
|
+
const result = await store.getThreadById({ threadId: 'non-existent' });
|
|
98
|
+
expect(result).toBeNull();
|
|
149
99
|
});
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
100
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
101
|
+
it('should get threads by resource ID', async () => {
|
|
102
|
+
const resourceId = 'resource-1';
|
|
103
|
+
const threads = [
|
|
104
|
+
{
|
|
105
|
+
id: 'thread-1',
|
|
106
|
+
resourceId,
|
|
107
|
+
title: 'Thread 1',
|
|
108
|
+
createdAt: new Date(),
|
|
109
|
+
updatedAt: new Date(),
|
|
110
|
+
metadata: {},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'thread-2',
|
|
114
|
+
resourceId,
|
|
115
|
+
title: 'Thread 2',
|
|
116
|
+
createdAt: new Date(),
|
|
117
|
+
updatedAt: new Date(),
|
|
118
|
+
metadata: {},
|
|
119
|
+
},
|
|
120
|
+
];
|
|
157
121
|
|
|
158
|
-
|
|
159
|
-
const now = new Date();
|
|
160
|
-
const thread = {
|
|
161
|
-
id: 'thread-1',
|
|
162
|
-
resourceId: 'resource-1',
|
|
163
|
-
title: 'Test Thread',
|
|
164
|
-
createdAt: now,
|
|
165
|
-
updatedAt: now,
|
|
166
|
-
metadata: {},
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
await store.saveThread({ thread });
|
|
170
|
-
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
171
|
-
expect(retrievedThread?.createdAt).toBeInstanceOf(Date);
|
|
172
|
-
expect(retrievedThread?.updatedAt).toBeInstanceOf(Date);
|
|
173
|
-
expect(retrievedThread?.createdAt.toISOString()).toBe(now.toISOString());
|
|
174
|
-
expect(retrievedThread?.updatedAt.toISOString()).toBe(now.toISOString());
|
|
175
|
-
});
|
|
122
|
+
await Promise.all(threads.map(thread => store.saveThread({ thread })));
|
|
176
123
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
resourceId: 'resource-1',
|
|
182
|
-
title: 'Test Thread',
|
|
183
|
-
createdAt: now.toISOString(),
|
|
184
|
-
updatedAt: now.toISOString(),
|
|
185
|
-
metadata: {},
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
await store.saveThread({ thread: thread as any });
|
|
189
|
-
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
190
|
-
expect(retrievedThread?.createdAt).toBeInstanceOf(Date);
|
|
191
|
-
expect(retrievedThread?.updatedAt).toBeInstanceOf(Date);
|
|
192
|
-
expect(retrievedThread?.createdAt.toISOString()).toBe(now.toISOString());
|
|
193
|
-
expect(retrievedThread?.updatedAt.toISOString()).toBe(now.toISOString());
|
|
194
|
-
});
|
|
124
|
+
const retrievedThreads = await store.getThreadsByResourceId({ resourceId });
|
|
125
|
+
expect(retrievedThreads).toHaveLength(2);
|
|
126
|
+
expect(retrievedThreads.map(t => t.id)).toEqual(expect.arrayContaining(['thread-1', 'thread-2']));
|
|
127
|
+
});
|
|
195
128
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
129
|
+
it('should update thread metadata', async () => {
|
|
130
|
+
const thread = {
|
|
131
|
+
id: 'thread-1',
|
|
132
|
+
resourceId: 'resource-1',
|
|
133
|
+
title: 'Test Thread',
|
|
134
|
+
createdAt: new Date(),
|
|
135
|
+
updatedAt: new Date(),
|
|
136
|
+
metadata: { initial: 'value' },
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
await store.saveThread({ thread });
|
|
140
|
+
|
|
141
|
+
const updatedThread = await store.updateThread({
|
|
142
|
+
id: thread.id,
|
|
143
|
+
title: 'Updated Title',
|
|
144
|
+
metadata: { updated: 'value' },
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(updatedThread.title).toBe('Updated Title');
|
|
148
|
+
expect(updatedThread.metadata).toEqual({
|
|
149
|
+
initial: 'value',
|
|
150
|
+
updated: 'value',
|
|
151
|
+
});
|
|
152
|
+
});
|
|
213
153
|
});
|
|
214
154
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
155
|
+
describe('Date Handling', () => {
|
|
156
|
+
beforeEach(async () => {
|
|
157
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should handle Date objects in thread operations', async () => {
|
|
161
|
+
const now = new Date();
|
|
162
|
+
const thread = {
|
|
219
163
|
id: 'thread-1',
|
|
220
164
|
resourceId: 'resource-1',
|
|
221
|
-
title: 'Thread
|
|
165
|
+
title: 'Test Thread',
|
|
222
166
|
createdAt: now,
|
|
223
|
-
updatedAt: now
|
|
167
|
+
updatedAt: now,
|
|
224
168
|
metadata: {},
|
|
225
|
-
}
|
|
226
|
-
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
await store.saveThread({ thread });
|
|
172
|
+
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
173
|
+
expect(retrievedThread?.createdAt).toBeInstanceOf(Date);
|
|
174
|
+
expect(retrievedThread?.updatedAt).toBeInstanceOf(Date);
|
|
175
|
+
expect(retrievedThread?.createdAt.toISOString()).toBe(now.toISOString());
|
|
176
|
+
expect(retrievedThread?.updatedAt.toISOString()).toBe(now.toISOString());
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should handle ISO string dates in thread operations', async () => {
|
|
180
|
+
const now = new Date();
|
|
181
|
+
const thread = {
|
|
227
182
|
id: 'thread-2',
|
|
228
183
|
resourceId: 'resource-1',
|
|
229
|
-
title: 'Thread
|
|
184
|
+
title: 'Test Thread',
|
|
230
185
|
createdAt: now.toISOString(),
|
|
231
|
-
updatedAt: now,
|
|
186
|
+
updatedAt: now.toISOString(),
|
|
232
187
|
metadata: {},
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
expect(thread.createdAt).toBeInstanceOf(Date);
|
|
242
|
-
expect(thread.updatedAt).toBeInstanceOf(Date);
|
|
243
|
-
expect(thread.createdAt.toISOString()).toBe(now.toISOString());
|
|
244
|
-
expect(thread.updatedAt.toISOString()).toBe(now.toISOString());
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
await store.saveThread({ thread: thread as any });
|
|
191
|
+
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
192
|
+
expect(retrievedThread?.createdAt).toBeInstanceOf(Date);
|
|
193
|
+
expect(retrievedThread?.updatedAt).toBeInstanceOf(Date);
|
|
194
|
+
expect(retrievedThread?.createdAt.toISOString()).toBe(now.toISOString());
|
|
195
|
+
expect(retrievedThread?.updatedAt.toISOString()).toBe(now.toISOString());
|
|
245
196
|
});
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
describe('Message Operations', () => {
|
|
250
|
-
const threadId = 'test-thread';
|
|
251
|
-
|
|
252
|
-
beforeEach(async () => {
|
|
253
|
-
await store.clearTable({ tableName: MastraStorage.TABLE_MESSAGES });
|
|
254
|
-
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
255
197
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
thread
|
|
259
|
-
id:
|
|
198
|
+
it('should handle mixed date formats in thread operations', async () => {
|
|
199
|
+
const now = new Date();
|
|
200
|
+
const thread = {
|
|
201
|
+
id: 'thread-3',
|
|
260
202
|
resourceId: 'resource-1',
|
|
261
203
|
title: 'Test Thread',
|
|
262
|
-
createdAt:
|
|
263
|
-
updatedAt:
|
|
204
|
+
createdAt: now,
|
|
205
|
+
updatedAt: now.toISOString(),
|
|
264
206
|
metadata: {},
|
|
265
|
-
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
await store.saveThread({ thread: thread as any });
|
|
210
|
+
const retrievedThread = await store.getThreadById({ threadId: thread.id });
|
|
211
|
+
expect(retrievedThread?.createdAt).toBeInstanceOf(Date);
|
|
212
|
+
expect(retrievedThread?.updatedAt).toBeInstanceOf(Date);
|
|
213
|
+
expect(retrievedThread?.createdAt.toISOString()).toBe(now.toISOString());
|
|
214
|
+
expect(retrievedThread?.updatedAt.toISOString()).toBe(now.toISOString());
|
|
266
215
|
});
|
|
267
|
-
});
|
|
268
216
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
expect(retrievedMessages.map(m => m.content[0].text)).toEqual(['First', 'Second', 'Third']);
|
|
217
|
+
it('should handle date serialization in getThreadsByResourceId', async () => {
|
|
218
|
+
const now = new Date();
|
|
219
|
+
const threads = [
|
|
220
|
+
{
|
|
221
|
+
id: 'thread-1',
|
|
222
|
+
resourceId: 'resource-1',
|
|
223
|
+
title: 'Thread 1',
|
|
224
|
+
createdAt: now,
|
|
225
|
+
updatedAt: now.toISOString(),
|
|
226
|
+
metadata: {},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: 'thread-2',
|
|
230
|
+
resourceId: 'resource-1',
|
|
231
|
+
title: 'Thread 2',
|
|
232
|
+
createdAt: now.toISOString(),
|
|
233
|
+
updatedAt: now,
|
|
234
|
+
metadata: {},
|
|
235
|
+
},
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
await Promise.all(threads.map(thread => store.saveThread({ thread: thread as any })));
|
|
239
|
+
|
|
240
|
+
const retrievedThreads = await store.getThreadsByResourceId({ resourceId: 'resource-1' });
|
|
241
|
+
expect(retrievedThreads).toHaveLength(2);
|
|
242
|
+
retrievedThreads.forEach(thread => {
|
|
243
|
+
expect(thread.createdAt).toBeInstanceOf(Date);
|
|
244
|
+
expect(thread.updatedAt).toBeInstanceOf(Date);
|
|
245
|
+
expect(thread.createdAt.toISOString()).toBe(now.toISOString());
|
|
246
|
+
expect(thread.updatedAt.toISOString()).toBe(now.toISOString());
|
|
247
|
+
});
|
|
248
|
+
});
|
|
302
249
|
});
|
|
303
250
|
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
251
|
+
describe('Message Operations', () => {
|
|
252
|
+
const threadId = 'test-thread';
|
|
253
|
+
|
|
254
|
+
beforeEach(async () => {
|
|
255
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_MESSAGES });
|
|
256
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_THREADS });
|
|
257
|
+
|
|
258
|
+
// Create a test thread
|
|
259
|
+
await store.saveThread({
|
|
260
|
+
thread: {
|
|
261
|
+
id: threadId,
|
|
262
|
+
resourceId: 'resource-1',
|
|
263
|
+
title: 'Test Thread',
|
|
264
|
+
createdAt: new Date(),
|
|
265
|
+
updatedAt: new Date(),
|
|
266
|
+
metadata: {},
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
});
|
|
308
270
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
271
|
+
it('should save and retrieve messages in order', async () => {
|
|
272
|
+
const messages = [
|
|
273
|
+
{
|
|
274
|
+
id: 'msg-1',
|
|
275
|
+
threadId,
|
|
276
|
+
role: 'user',
|
|
277
|
+
type: 'text',
|
|
278
|
+
content: [{ type: 'text', text: 'First' }],
|
|
279
|
+
createdAt: new Date().toISOString(),
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
id: 'msg-2',
|
|
283
|
+
threadId,
|
|
284
|
+
role: 'assistant',
|
|
285
|
+
type: 'text',
|
|
286
|
+
content: [{ type: 'text', text: 'Second' }],
|
|
287
|
+
createdAt: new Date().toISOString(),
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
id: 'msg-3',
|
|
291
|
+
threadId,
|
|
292
|
+
role: 'user',
|
|
293
|
+
type: 'text',
|
|
294
|
+
content: [{ type: 'text', text: 'Third' }],
|
|
295
|
+
createdAt: new Date().toISOString(),
|
|
296
|
+
},
|
|
297
|
+
];
|
|
331
298
|
|
|
332
|
-
|
|
333
|
-
const testNamespace = 'test';
|
|
334
|
-
const testWorkflow = 'test-workflow';
|
|
335
|
-
const testRunId = 'test-run';
|
|
299
|
+
await store.saveMessages({ messages });
|
|
336
300
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
301
|
+
const retrievedMessages = await store.getMessages({ threadId });
|
|
302
|
+
expect(retrievedMessages).toHaveLength(3);
|
|
303
|
+
expect(retrievedMessages.map(m => m.content[0].text)).toEqual(['First', 'Second', 'Third']);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should handle empty message array', async () => {
|
|
307
|
+
const result = await store.saveMessages({ messages: [] });
|
|
308
|
+
expect(result).toEqual([]);
|
|
309
|
+
});
|
|
340
310
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
311
|
+
it('should handle messages with complex content', async () => {
|
|
312
|
+
const messages = [
|
|
313
|
+
{
|
|
314
|
+
id: 'msg-1',
|
|
315
|
+
threadId,
|
|
316
|
+
role: 'user',
|
|
317
|
+
type: 'text',
|
|
318
|
+
content: [
|
|
319
|
+
{ type: 'text', text: 'Message with' },
|
|
320
|
+
{ type: 'code', text: 'code block', language: 'typescript' },
|
|
321
|
+
{ type: 'text', text: 'and more text' },
|
|
322
|
+
],
|
|
323
|
+
createdAt: new Date().toISOString(),
|
|
347
324
|
},
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
await store.persistWorkflowSnapshot({
|
|
357
|
-
namespace: testNamespace,
|
|
358
|
-
workflowName: testWorkflow,
|
|
359
|
-
runId: testRunId,
|
|
360
|
-
snapshot: mockSnapshot,
|
|
325
|
+
];
|
|
326
|
+
|
|
327
|
+
await store.saveMessages({ messages });
|
|
328
|
+
|
|
329
|
+
const retrievedMessages = await store.getMessages({ threadId });
|
|
330
|
+
expect(retrievedMessages[0].content).toEqual(messages[0].content);
|
|
361
331
|
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
describe('Workflow Operations', () => {
|
|
335
|
+
const testNamespace = 'test';
|
|
336
|
+
const testWorkflow = 'test-workflow';
|
|
337
|
+
const testRunId = 'test-run';
|
|
362
338
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
workflowName: testWorkflow,
|
|
366
|
-
runId: testRunId,
|
|
339
|
+
beforeEach(async () => {
|
|
340
|
+
await store.clearTable({ tableName: MastraStorage.TABLE_WORKFLOW_SNAPSHOT });
|
|
367
341
|
});
|
|
368
342
|
|
|
369
|
-
|
|
370
|
-
|
|
343
|
+
it('should persist and load workflow snapshots', async () => {
|
|
344
|
+
const mockSnapshot = {
|
|
345
|
+
value: { step1: 'completed' },
|
|
346
|
+
context: {
|
|
347
|
+
stepResults: {
|
|
348
|
+
step1: { status: 'success', payload: { result: 'done' } },
|
|
349
|
+
},
|
|
350
|
+
attempts: {},
|
|
351
|
+
triggerData: {},
|
|
352
|
+
},
|
|
353
|
+
runId: testRunId,
|
|
354
|
+
activePaths: [],
|
|
355
|
+
timestamp: Date.now(),
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
await store.persistWorkflowSnapshot({
|
|
359
|
+
namespace: testNamespace,
|
|
360
|
+
workflowName: testWorkflow,
|
|
361
|
+
runId: testRunId,
|
|
362
|
+
snapshot: mockSnapshot,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const loadedSnapshot = await store.loadWorkflowSnapshot({
|
|
366
|
+
namespace: testNamespace,
|
|
367
|
+
workflowName: testWorkflow,
|
|
368
|
+
runId: testRunId,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
expect(loadedSnapshot).toEqual(mockSnapshot);
|
|
372
|
+
});
|
|
371
373
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
374
|
+
it('should return null for non-existent snapshot', async () => {
|
|
375
|
+
const result = await store.loadWorkflowSnapshot({
|
|
376
|
+
namespace: testNamespace,
|
|
377
|
+
workflowName: 'non-existent',
|
|
378
|
+
runId: 'non-existent',
|
|
379
|
+
});
|
|
380
|
+
expect(result).toBeNull();
|
|
377
381
|
});
|
|
378
|
-
expect(result).toBeNull();
|
|
379
382
|
});
|
|
380
|
-
}
|
|
381
|
-
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
timeout: 30000,
|
|
386
|
+
},
|
|
387
|
+
);
|
package/src/vector/filter.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { BaseFilterTranslator
|
|
1
|
+
import { BaseFilterTranslator } from '@mastra/core/filter';
|
|
2
|
+
import type { Filter, FieldCondition, OperatorSupport } from '@mastra/core/filter';
|
|
2
3
|
|
|
3
4
|
export class UpstashFilterTranslator extends BaseFilterTranslator {
|
|
4
5
|
protected override getSupportedOperators(): OperatorSupport {
|
package/src/vector/index.test.ts
CHANGED