@mastra/upstash 1.0.0-beta.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +985 -0
- package/dist/docs/README.md +34 -0
- package/dist/docs/SKILL.md +35 -0
- package/dist/docs/SOURCE_MAP.json +6 -0
- package/dist/docs/memory/01-working-memory.md +390 -0
- package/dist/docs/rag/01-vector-databases.md +643 -0
- package/dist/docs/rag/02-retrieval.md +548 -0
- package/dist/docs/storage/01-reference.md +143 -0
- package/dist/docs/vectors/01-reference.md +233 -0
- package/dist/index.cjs +189 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +188 -61
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +3 -2
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +1 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +8 -4
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +10 -9
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Vectors API Reference
|
|
2
|
+
|
|
3
|
+
> API reference for vectors - 1 entries
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Reference: Upstash Vector Store
|
|
9
|
+
|
|
10
|
+
> Documentation for the UpstashVector class in Mastra, which provides vector search using Upstash Vector.
|
|
11
|
+
|
|
12
|
+
The UpstashVector class provides vector search using [Upstash Vector](https://upstash.com/vector), a serverless vector database service that provides vector similarity search with metadata filtering capabilities and hybrid search support.
|
|
13
|
+
|
|
14
|
+
## Constructor Options
|
|
15
|
+
|
|
16
|
+
## Methods
|
|
17
|
+
|
|
18
|
+
### createIndex()
|
|
19
|
+
|
|
20
|
+
Note: This method is a no-op for Upstash as indexes are created automatically.
|
|
21
|
+
|
|
22
|
+
### upsert()
|
|
23
|
+
|
|
24
|
+
### query()
|
|
25
|
+
|
|
26
|
+
### listIndexes()
|
|
27
|
+
|
|
28
|
+
Returns an array of index names (namespaces) as strings.
|
|
29
|
+
|
|
30
|
+
### describeIndex()
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface IndexStats {
|
|
36
|
+
dimension: number;
|
|
37
|
+
count: number;
|
|
38
|
+
metric: "cosine" | "euclidean" | "dotproduct";
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### deleteIndex()
|
|
43
|
+
|
|
44
|
+
### updateVector()
|
|
45
|
+
|
|
46
|
+
The `update` object can have the following properties:
|
|
47
|
+
|
|
48
|
+
- `vector` (optional): An array of numbers representing the new dense vector.
|
|
49
|
+
- `sparseVector` (optional): A sparse vector object with `indices` and `values` arrays for hybrid indexes.
|
|
50
|
+
- `metadata` (optional): A record of key-value pairs for metadata.
|
|
51
|
+
|
|
52
|
+
### deleteVector()
|
|
53
|
+
|
|
54
|
+
Attempts to delete an item by its ID from the specified index. Logs an error message if the deletion fails.
|
|
55
|
+
|
|
56
|
+
## Hybrid Vector Search
|
|
57
|
+
|
|
58
|
+
Upstash Vector supports hybrid search that combines semantic search (dense vectors) with keyword-based search (sparse vectors) for improved relevance and accuracy.
|
|
59
|
+
|
|
60
|
+
### Basic Hybrid Usage
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { UpstashVector } from "@mastra/upstash";
|
|
64
|
+
|
|
65
|
+
const vectorStore = new UpstashVector({
|
|
66
|
+
id: 'upstash-vector',
|
|
67
|
+
url: process.env.UPSTASH_VECTOR_URL,
|
|
68
|
+
token: process.env.UPSTASH_VECTOR_TOKEN,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Upsert vectors with both dense and sparse components
|
|
72
|
+
const denseVectors = [
|
|
73
|
+
[0.1, 0.2, 0.3],
|
|
74
|
+
[0.4, 0.5, 0.6],
|
|
75
|
+
];
|
|
76
|
+
const sparseVectors = [
|
|
77
|
+
{ indices: [1, 5, 10], values: [0.8, 0.6, 0.4] },
|
|
78
|
+
{ indices: [2, 6, 11], values: [0.7, 0.5, 0.3] },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
await vectorStore.upsert({
|
|
82
|
+
indexName: "hybrid-index",
|
|
83
|
+
vectors: denseVectors,
|
|
84
|
+
sparseVectors: sparseVectors,
|
|
85
|
+
metadata: [{ title: "Document 1" }, { title: "Document 2" }],
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Query with hybrid search
|
|
89
|
+
const results = await vectorStore.query({
|
|
90
|
+
indexName: "hybrid-index",
|
|
91
|
+
queryVector: [0.1, 0.2, 0.3],
|
|
92
|
+
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
|
|
93
|
+
topK: 10,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Advanced Hybrid Search Options
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { FusionAlgorithm, QueryMode } from "@upstash/vector";
|
|
101
|
+
|
|
102
|
+
// Query with specific fusion algorithm
|
|
103
|
+
const fusionResults = await vectorStore.query({
|
|
104
|
+
indexName: "hybrid-index",
|
|
105
|
+
queryVector: [0.1, 0.2, 0.3],
|
|
106
|
+
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
|
|
107
|
+
fusionAlgorithm: FusionAlgorithm.RRF,
|
|
108
|
+
topK: 10,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Dense-only search
|
|
112
|
+
const denseResults = await vectorStore.query({
|
|
113
|
+
indexName: "hybrid-index",
|
|
114
|
+
queryVector: [0.1, 0.2, 0.3],
|
|
115
|
+
queryMode: QueryMode.DENSE,
|
|
116
|
+
topK: 10,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Sparse-only search
|
|
120
|
+
const sparseResults = await vectorStore.query({
|
|
121
|
+
indexName: "hybrid-index",
|
|
122
|
+
queryVector: [0.1, 0.2, 0.3], // Still required for index structure
|
|
123
|
+
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
|
|
124
|
+
queryMode: QueryMode.SPARSE,
|
|
125
|
+
topK: 10,
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Updating Hybrid Vectors
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Update both dense and sparse components
|
|
133
|
+
await vectorStore.updateVector({
|
|
134
|
+
indexName: "hybrid-index",
|
|
135
|
+
id: "vector-id",
|
|
136
|
+
update: {
|
|
137
|
+
vector: [0.2, 0.3, 0.4],
|
|
138
|
+
sparseVector: { indices: [2, 7, 12], values: [0.9, 0.8, 0.6] },
|
|
139
|
+
metadata: { title: "Updated Document" },
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Response Types
|
|
145
|
+
|
|
146
|
+
Query results are returned in this format:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
interface QueryResult {
|
|
150
|
+
id: string;
|
|
151
|
+
score: number;
|
|
152
|
+
metadata: Record<string, any>;
|
|
153
|
+
vector?: number[]; // Only included if includeVector is true
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Error Handling
|
|
158
|
+
|
|
159
|
+
The store throws typed errors that can be caught:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
try {
|
|
163
|
+
await store.query({
|
|
164
|
+
indexName: "index_name",
|
|
165
|
+
queryVector: queryVector,
|
|
166
|
+
});
|
|
167
|
+
} catch (error) {
|
|
168
|
+
if (error instanceof VectorStoreError) {
|
|
169
|
+
console.log(error.code); // 'connection_failed' | 'invalid_dimension' | etc
|
|
170
|
+
console.log(error.details); // Additional error context
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Environment Variables
|
|
176
|
+
|
|
177
|
+
Required environment variables:
|
|
178
|
+
|
|
179
|
+
- `UPSTASH_VECTOR_URL`: Your Upstash Vector database URL
|
|
180
|
+
- `UPSTASH_VECTOR_TOKEN`: Your Upstash Vector API token
|
|
181
|
+
|
|
182
|
+
## Usage Example
|
|
183
|
+
|
|
184
|
+
### Local embeddings with fastembed
|
|
185
|
+
|
|
186
|
+
Embeddings are numeric vectors used by memory's `semanticRecall` to retrieve related messages by meaning (not keywords). This setup uses `@mastra/fastembed` to generate vector embeddings.
|
|
187
|
+
|
|
188
|
+
Install `fastembed` to get started:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm install @mastra/fastembed@beta
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Add the following to your agent:
|
|
195
|
+
|
|
196
|
+
```typescript title="src/mastra/agents/example-upstash-agent.ts"
|
|
197
|
+
import { Memory } from "@mastra/memory";
|
|
198
|
+
import { Agent } from "@mastra/core/agent";
|
|
199
|
+
import { UpstashStore, UpstashVector } from "@mastra/upstash";
|
|
200
|
+
import { fastembed } from "@mastra/fastembed";
|
|
201
|
+
|
|
202
|
+
export const upstashAgent = new Agent({
|
|
203
|
+
id: "upstash-agent",
|
|
204
|
+
name: "Upstash Agent",
|
|
205
|
+
instructions:
|
|
206
|
+
"You are an AI agent with the ability to automatically recall memories from previous interactions.",
|
|
207
|
+
model: "openai/gpt-5.1",
|
|
208
|
+
memory: new Memory({
|
|
209
|
+
storage: new UpstashStore({
|
|
210
|
+
id: 'upstash-agent-storage',
|
|
211
|
+
url: process.env.UPSTASH_REDIS_REST_URL!,
|
|
212
|
+
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
|
|
213
|
+
}),
|
|
214
|
+
vector: new UpstashVector({
|
|
215
|
+
id: 'upstash-agent-vector',
|
|
216
|
+
url: process.env.UPSTASH_VECTOR_REST_URL!,
|
|
217
|
+
token: process.env.UPSTASH_VECTOR_REST_TOKEN!,
|
|
218
|
+
}),
|
|
219
|
+
embedder: fastembed,
|
|
220
|
+
options: {
|
|
221
|
+
lastMessages: 10,
|
|
222
|
+
semanticRecall: {
|
|
223
|
+
topK: 3,
|
|
224
|
+
messageRange: 2,
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Related
|
|
232
|
+
|
|
233
|
+
- [Metadata Filters](../rag/metadata-filters)
|
package/dist/index.cjs
CHANGED
|
@@ -192,19 +192,34 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
192
192
|
);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
-
async
|
|
196
|
-
const {
|
|
195
|
+
async listThreads(args) {
|
|
196
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
197
197
|
const { field, direction } = this.parseOrderBy(orderBy);
|
|
198
|
+
try {
|
|
199
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
200
|
+
} catch (error$1) {
|
|
201
|
+
throw new error.MastraError(
|
|
202
|
+
{
|
|
203
|
+
id: storage.createStorageErrorId("UPSTASH", "LIST_THREADS", "INVALID_PAGE"),
|
|
204
|
+
domain: error.ErrorDomain.STORAGE,
|
|
205
|
+
category: error.ErrorCategory.USER,
|
|
206
|
+
details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
|
|
207
|
+
},
|
|
208
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid pagination parameters")
|
|
209
|
+
);
|
|
210
|
+
}
|
|
198
211
|
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
199
|
-
|
|
212
|
+
try {
|
|
213
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
214
|
+
} catch (error$1) {
|
|
200
215
|
throw new error.MastraError(
|
|
201
216
|
{
|
|
202
|
-
id: storage.createStorageErrorId("UPSTASH", "
|
|
217
|
+
id: storage.createStorageErrorId("UPSTASH", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
203
218
|
domain: error.ErrorDomain.STORAGE,
|
|
204
219
|
category: error.ErrorCategory.USER,
|
|
205
|
-
details: {
|
|
220
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
206
221
|
},
|
|
207
|
-
new Error("
|
|
222
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid metadata key")
|
|
208
223
|
);
|
|
209
224
|
}
|
|
210
225
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
@@ -212,19 +227,35 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
212
227
|
let allThreads = [];
|
|
213
228
|
const pattern = `${storage.TABLE_THREADS}:*`;
|
|
214
229
|
const keys = await this.#db.scanKeys(pattern);
|
|
230
|
+
if (keys.length === 0) {
|
|
231
|
+
return {
|
|
232
|
+
threads: [],
|
|
233
|
+
total: 0,
|
|
234
|
+
page,
|
|
235
|
+
perPage: perPageForResponse,
|
|
236
|
+
hasMore: false
|
|
237
|
+
};
|
|
238
|
+
}
|
|
215
239
|
const pipeline = this.client.pipeline();
|
|
216
240
|
keys.forEach((key) => pipeline.get(key));
|
|
217
241
|
const results = await pipeline.exec();
|
|
218
242
|
for (let i = 0; i < results.length; i++) {
|
|
219
243
|
const thread = results[i];
|
|
220
|
-
if (thread
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
createdAt: storage.ensureDate(thread.createdAt),
|
|
224
|
-
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
225
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
226
|
-
});
|
|
244
|
+
if (!thread) continue;
|
|
245
|
+
if (filter?.resourceId && thread.resourceId !== filter.resourceId) {
|
|
246
|
+
continue;
|
|
227
247
|
}
|
|
248
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
249
|
+
const threadMetadata = typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata;
|
|
250
|
+
const matches = Object.entries(filter.metadata).every(([key, value]) => threadMetadata?.[key] === value);
|
|
251
|
+
if (!matches) continue;
|
|
252
|
+
}
|
|
253
|
+
allThreads.push({
|
|
254
|
+
...thread,
|
|
255
|
+
createdAt: storage.ensureDate(thread.createdAt),
|
|
256
|
+
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
257
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
258
|
+
});
|
|
228
259
|
}
|
|
229
260
|
const sortedThreads = this.sortThreads(allThreads, field, direction);
|
|
230
261
|
const total = sortedThreads.length;
|
|
@@ -241,11 +272,12 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
241
272
|
} catch (error$1) {
|
|
242
273
|
const mastraError = new error.MastraError(
|
|
243
274
|
{
|
|
244
|
-
id: storage.createStorageErrorId("UPSTASH", "
|
|
275
|
+
id: storage.createStorageErrorId("UPSTASH", "LIST_THREADS", "FAILED"),
|
|
245
276
|
domain: error.ErrorDomain.STORAGE,
|
|
246
277
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
247
278
|
details: {
|
|
248
|
-
resourceId,
|
|
279
|
+
...filter?.resourceId && { resourceId: filter.resourceId },
|
|
280
|
+
hasMetadataFilter: !!filter?.metadata,
|
|
249
281
|
page,
|
|
250
282
|
perPage
|
|
251
283
|
}
|
|
@@ -637,15 +669,11 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
637
669
|
if (resourceId) {
|
|
638
670
|
messagesData = messagesData.filter((msg) => msg.resourceId === resourceId);
|
|
639
671
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
if (dateRange?.end) {
|
|
646
|
-
const toDate = dateRange.end;
|
|
647
|
-
messagesData = messagesData.filter((msg) => new Date(msg.createdAt).getTime() <= toDate.getTime());
|
|
648
|
-
}
|
|
672
|
+
messagesData = storage.filterByDateRange(
|
|
673
|
+
messagesData,
|
|
674
|
+
(msg) => new Date(msg.createdAt),
|
|
675
|
+
filter?.dateRange
|
|
676
|
+
);
|
|
649
677
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
650
678
|
const getFieldValue = (msg) => {
|
|
651
679
|
if (field === "createdAt") {
|
|
@@ -993,6 +1021,118 @@ var StoreMemoryUpstash = class extends storage.MemoryStorage {
|
|
|
993
1021
|
}
|
|
994
1022
|
});
|
|
995
1023
|
}
|
|
1024
|
+
async cloneThread(args) {
|
|
1025
|
+
const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;
|
|
1026
|
+
const sourceThread = await this.getThreadById({ threadId: sourceThreadId });
|
|
1027
|
+
if (!sourceThread) {
|
|
1028
|
+
throw new error.MastraError({
|
|
1029
|
+
id: storage.createStorageErrorId("UPSTASH", "CLONE_THREAD", "SOURCE_NOT_FOUND"),
|
|
1030
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1031
|
+
category: error.ErrorCategory.USER,
|
|
1032
|
+
text: `Source thread with id ${sourceThreadId} not found`,
|
|
1033
|
+
details: { sourceThreadId }
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
const newThreadId = providedThreadId || crypto.randomUUID();
|
|
1037
|
+
const existingThread = await this.getThreadById({ threadId: newThreadId });
|
|
1038
|
+
if (existingThread) {
|
|
1039
|
+
throw new error.MastraError({
|
|
1040
|
+
id: storage.createStorageErrorId("UPSTASH", "CLONE_THREAD", "THREAD_EXISTS"),
|
|
1041
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1042
|
+
category: error.ErrorCategory.USER,
|
|
1043
|
+
text: `Thread with id ${newThreadId} already exists`,
|
|
1044
|
+
details: { newThreadId }
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
try {
|
|
1048
|
+
const threadMessagesKey = getThreadMessagesKey(sourceThreadId);
|
|
1049
|
+
const messageIds = await this.client.zrange(threadMessagesKey, 0, -1);
|
|
1050
|
+
const pipeline = this.client.pipeline();
|
|
1051
|
+
for (const mid of messageIds) {
|
|
1052
|
+
pipeline.get(getMessageKey(sourceThreadId, mid));
|
|
1053
|
+
}
|
|
1054
|
+
const results = await pipeline.exec();
|
|
1055
|
+
let sourceMessages = results.filter((msg) => msg !== null).map((msg) => ({
|
|
1056
|
+
...msg,
|
|
1057
|
+
createdAt: new Date(msg.createdAt)
|
|
1058
|
+
}));
|
|
1059
|
+
if (options?.messageFilter?.startDate || options?.messageFilter?.endDate) {
|
|
1060
|
+
sourceMessages = storage.filterByDateRange(sourceMessages, (msg) => new Date(msg.createdAt), {
|
|
1061
|
+
start: options.messageFilter?.startDate,
|
|
1062
|
+
end: options.messageFilter?.endDate
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
if (options?.messageFilter?.messageIds && options.messageFilter.messageIds.length > 0) {
|
|
1066
|
+
const messageIdSet = new Set(options.messageFilter.messageIds);
|
|
1067
|
+
sourceMessages = sourceMessages.filter((msg) => messageIdSet.has(msg.id));
|
|
1068
|
+
}
|
|
1069
|
+
sourceMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
1070
|
+
if (options?.messageLimit && options.messageLimit > 0 && sourceMessages.length > options.messageLimit) {
|
|
1071
|
+
sourceMessages = sourceMessages.slice(-options.messageLimit);
|
|
1072
|
+
}
|
|
1073
|
+
const now = /* @__PURE__ */ new Date();
|
|
1074
|
+
const lastMessageId = sourceMessages.length > 0 ? sourceMessages[sourceMessages.length - 1].id : void 0;
|
|
1075
|
+
const cloneMetadata = {
|
|
1076
|
+
sourceThreadId,
|
|
1077
|
+
clonedAt: now,
|
|
1078
|
+
...lastMessageId && { lastMessageId }
|
|
1079
|
+
};
|
|
1080
|
+
const newThread = {
|
|
1081
|
+
id: newThreadId,
|
|
1082
|
+
resourceId: resourceId || sourceThread.resourceId,
|
|
1083
|
+
title: title || (sourceThread.title ? `Clone of ${sourceThread.title}` : void 0),
|
|
1084
|
+
metadata: {
|
|
1085
|
+
...metadata,
|
|
1086
|
+
clone: cloneMetadata
|
|
1087
|
+
},
|
|
1088
|
+
createdAt: now,
|
|
1089
|
+
updatedAt: now
|
|
1090
|
+
};
|
|
1091
|
+
const writePipeline = this.client.pipeline();
|
|
1092
|
+
const threadKey = getKey(storage.TABLE_THREADS, { id: newThreadId });
|
|
1093
|
+
writePipeline.set(threadKey, processRecord(storage.TABLE_THREADS, newThread).processedRecord);
|
|
1094
|
+
const clonedMessages = [];
|
|
1095
|
+
const targetResourceId = resourceId || sourceThread.resourceId;
|
|
1096
|
+
const newThreadMessagesKey = getThreadMessagesKey(newThreadId);
|
|
1097
|
+
for (let i = 0; i < sourceMessages.length; i++) {
|
|
1098
|
+
const sourceMsg = sourceMessages[i];
|
|
1099
|
+
const newMessageId = crypto.randomUUID();
|
|
1100
|
+
const { _index, ...restMsg } = sourceMsg;
|
|
1101
|
+
const newMessage = {
|
|
1102
|
+
...restMsg,
|
|
1103
|
+
id: newMessageId,
|
|
1104
|
+
threadId: newThreadId,
|
|
1105
|
+
resourceId: targetResourceId
|
|
1106
|
+
};
|
|
1107
|
+
const messageKey = getMessageKey(newThreadId, newMessageId);
|
|
1108
|
+
writePipeline.set(messageKey, newMessage);
|
|
1109
|
+
writePipeline.set(getMessageIndexKey(newMessageId), newThreadId);
|
|
1110
|
+
writePipeline.zadd(newThreadMessagesKey, {
|
|
1111
|
+
score: i,
|
|
1112
|
+
member: newMessageId
|
|
1113
|
+
});
|
|
1114
|
+
clonedMessages.push(newMessage);
|
|
1115
|
+
}
|
|
1116
|
+
await writePipeline.exec();
|
|
1117
|
+
return {
|
|
1118
|
+
thread: newThread,
|
|
1119
|
+
clonedMessages
|
|
1120
|
+
};
|
|
1121
|
+
} catch (error$1) {
|
|
1122
|
+
if (error$1 instanceof error.MastraError) {
|
|
1123
|
+
throw error$1;
|
|
1124
|
+
}
|
|
1125
|
+
throw new error.MastraError(
|
|
1126
|
+
{
|
|
1127
|
+
id: storage.createStorageErrorId("UPSTASH", "CLONE_THREAD", "FAILED"),
|
|
1128
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1129
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1130
|
+
details: { sourceThreadId, newThreadId }
|
|
1131
|
+
},
|
|
1132
|
+
error$1
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
996
1136
|
};
|
|
997
1137
|
function transformScoreRow(row) {
|
|
998
1138
|
return storage.transformScoreRow(row);
|
|
@@ -1273,24 +1413,6 @@ var ScoresUpstash = class extends storage.ScoresStorage {
|
|
|
1273
1413
|
};
|
|
1274
1414
|
}
|
|
1275
1415
|
};
|
|
1276
|
-
function parseWorkflowRun(row) {
|
|
1277
|
-
let parsedSnapshot = row.snapshot;
|
|
1278
|
-
if (typeof parsedSnapshot === "string") {
|
|
1279
|
-
try {
|
|
1280
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1281
|
-
} catch (e) {
|
|
1282
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
return {
|
|
1286
|
-
workflowName: row.workflow_name,
|
|
1287
|
-
runId: row.run_id,
|
|
1288
|
-
snapshot: parsedSnapshot,
|
|
1289
|
-
createdAt: storage.ensureDate(row.createdAt),
|
|
1290
|
-
updatedAt: storage.ensureDate(row.updatedAt),
|
|
1291
|
-
resourceId: row.resourceId
|
|
1292
|
-
};
|
|
1293
|
-
}
|
|
1294
1416
|
var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
1295
1417
|
client;
|
|
1296
1418
|
#db;
|
|
@@ -1300,6 +1422,24 @@ var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
|
1300
1422
|
this.client = client;
|
|
1301
1423
|
this.#db = new UpstashDB({ client });
|
|
1302
1424
|
}
|
|
1425
|
+
parseWorkflowRun(row) {
|
|
1426
|
+
let parsedSnapshot = row.snapshot;
|
|
1427
|
+
if (typeof parsedSnapshot === "string") {
|
|
1428
|
+
try {
|
|
1429
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1430
|
+
} catch (e) {
|
|
1431
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
return {
|
|
1435
|
+
workflowName: row.workflow_name,
|
|
1436
|
+
runId: row.run_id,
|
|
1437
|
+
snapshot: parsedSnapshot,
|
|
1438
|
+
createdAt: storage.ensureDate(row.createdAt),
|
|
1439
|
+
updatedAt: storage.ensureDate(row.updatedAt),
|
|
1440
|
+
resourceId: row.resourceId
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1303
1443
|
async dangerouslyClearAll() {
|
|
1304
1444
|
await this.#db.deleteData({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1305
1445
|
}
|
|
@@ -1465,7 +1605,7 @@ var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
|
1465
1605
|
);
|
|
1466
1606
|
const data = workflows.find((w) => w?.run_id === runId && w?.workflow_name === workflowName);
|
|
1467
1607
|
if (!data) return null;
|
|
1468
|
-
return parseWorkflowRun(data);
|
|
1608
|
+
return this.parseWorkflowRun(data);
|
|
1469
1609
|
} catch (error$1) {
|
|
1470
1610
|
throw new error.MastraError(
|
|
1471
1611
|
{
|
|
@@ -1550,7 +1690,7 @@ var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
|
1550
1690
|
const results = await pipeline.exec();
|
|
1551
1691
|
let runs = results.map((result) => result).filter(
|
|
1552
1692
|
(record) => record !== null && record !== void 0 && typeof record === "object" && "workflow_name" in record
|
|
1553
|
-
).filter((record) => !workflowName || record.workflow_name === workflowName).map((w) => parseWorkflowRun(w)).filter((w) => {
|
|
1693
|
+
).filter((record) => !workflowName || record.workflow_name === workflowName).map((w) => this.parseWorkflowRun(w)).filter((w) => {
|
|
1554
1694
|
if (fromDate && w.createdAt < fromDate) return false;
|
|
1555
1695
|
if (toDate && w.createdAt > toDate) return false;
|
|
1556
1696
|
if (status) {
|
|
@@ -1559,7 +1699,7 @@ var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
|
1559
1699
|
try {
|
|
1560
1700
|
snapshot = JSON.parse(snapshot);
|
|
1561
1701
|
} catch (e) {
|
|
1562
|
-
|
|
1702
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${w.workflowName}: ${e}`);
|
|
1563
1703
|
return false;
|
|
1564
1704
|
}
|
|
1565
1705
|
}
|
|
@@ -1597,7 +1737,7 @@ var WorkflowsUpstash = class extends storage.WorkflowsStorage {
|
|
|
1597
1737
|
var isClientConfig = (config) => {
|
|
1598
1738
|
return "client" in config;
|
|
1599
1739
|
};
|
|
1600
|
-
var UpstashStore = class extends storage.
|
|
1740
|
+
var UpstashStore = class extends storage.MastraCompositeStore {
|
|
1601
1741
|
redis;
|
|
1602
1742
|
stores;
|
|
1603
1743
|
constructor(config) {
|
|
@@ -1625,19 +1765,6 @@ var UpstashStore = class extends storage.MastraStorage {
|
|
|
1625
1765
|
memory
|
|
1626
1766
|
};
|
|
1627
1767
|
}
|
|
1628
|
-
get supports() {
|
|
1629
|
-
return {
|
|
1630
|
-
selectByIncludeResourceScope: true,
|
|
1631
|
-
resourceWorkingMemory: true,
|
|
1632
|
-
hasColumn: false,
|
|
1633
|
-
createTable: false,
|
|
1634
|
-
deleteMessages: true,
|
|
1635
|
-
observability: false,
|
|
1636
|
-
indexManagement: false,
|
|
1637
|
-
listScoresBySpan: true,
|
|
1638
|
-
agents: false
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
1768
|
async close() {
|
|
1642
1769
|
}
|
|
1643
1770
|
};
|
|
@@ -2332,8 +2459,11 @@ Example Complex Query:
|
|
|
2332
2459
|
]
|
|
2333
2460
|
}`;
|
|
2334
2461
|
|
|
2462
|
+
exports.ScoresUpstash = ScoresUpstash;
|
|
2463
|
+
exports.StoreMemoryUpstash = StoreMemoryUpstash;
|
|
2335
2464
|
exports.UPSTASH_PROMPT = UPSTASH_PROMPT;
|
|
2336
2465
|
exports.UpstashStore = UpstashStore;
|
|
2337
2466
|
exports.UpstashVector = UpstashVector;
|
|
2467
|
+
exports.WorkflowsUpstash = WorkflowsUpstash;
|
|
2338
2468
|
//# sourceMappingURL=index.cjs.map
|
|
2339
2469
|
//# sourceMappingURL=index.cjs.map
|