@mastra/cloudflare 1.0.0-beta.6 → 1.0.0-beta.8
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 +232 -0
- package/dist/index.cjs +1417 -1478
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1418 -1479
- package/dist/index.js.map +1 -1
- package/dist/storage/{domains/operations → db}/index.d.ts +22 -25
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +6 -5
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +11 -23
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +9 -13
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +21 -164
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/types.d.ts +33 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var error = require('@mastra/core/error');
|
|
|
4
4
|
var storage = require('@mastra/core/storage');
|
|
5
5
|
var Cloudflare = require('cloudflare');
|
|
6
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
7
8
|
var evals = require('@mastra/core/evals');
|
|
8
9
|
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -11,1508 +12,1576 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
11
12
|
var Cloudflare__default = /*#__PURE__*/_interopDefault(Cloudflare);
|
|
12
13
|
|
|
13
14
|
// src/storage/index.ts
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
function resolveCloudflareConfig(config) {
|
|
16
|
+
if ("client" in config) {
|
|
17
|
+
return {
|
|
18
|
+
client: config.client,
|
|
19
|
+
accountId: config.accountId,
|
|
20
|
+
namespacePrefix: config.namespacePrefix
|
|
21
|
+
};
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
if ("bindings" in config) {
|
|
24
|
+
return {
|
|
25
|
+
bindings: config.bindings,
|
|
26
|
+
namespacePrefix: config.keyPrefix
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
client: new Cloudflare__default.default({ apiToken: config.apiToken }),
|
|
31
|
+
accountId: config.accountId,
|
|
32
|
+
namespacePrefix: config.namespacePrefix
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
var CloudflareKVDB = class extends base.MastraBase {
|
|
36
|
+
bindings;
|
|
37
|
+
client;
|
|
38
|
+
accountId;
|
|
39
|
+
namespacePrefix;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
super({
|
|
42
|
+
component: "STORAGE",
|
|
43
|
+
name: "CLOUDFLARE_KV_DB"
|
|
44
|
+
});
|
|
45
|
+
this.bindings = config.bindings;
|
|
46
|
+
this.namespacePrefix = config.namespacePrefix || "";
|
|
47
|
+
this.client = config.client;
|
|
48
|
+
this.accountId = config.accountId;
|
|
49
|
+
}
|
|
50
|
+
getBinding(tableName) {
|
|
51
|
+
if (!this.bindings) {
|
|
52
|
+
throw new Error(`Cannot use Workers API binding for ${tableName}: Store initialized with REST API configuration`);
|
|
53
|
+
}
|
|
54
|
+
const binding = this.bindings[tableName];
|
|
55
|
+
if (!binding) throw new Error(`No binding found for namespace ${tableName}`);
|
|
56
|
+
return binding;
|
|
57
|
+
}
|
|
58
|
+
getKey(tableName, record) {
|
|
59
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
60
|
+
switch (tableName) {
|
|
61
|
+
case storage.TABLE_THREADS:
|
|
62
|
+
if (!record.id) throw new Error("Thread ID is required");
|
|
63
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
64
|
+
case storage.TABLE_MESSAGES:
|
|
65
|
+
if (!record.threadId || !record.id) throw new Error("Thread ID and Message ID are required");
|
|
66
|
+
return `${prefix}${tableName}:${record.threadId}:${record.id}`;
|
|
67
|
+
case storage.TABLE_WORKFLOW_SNAPSHOT:
|
|
68
|
+
if (!record.workflow_name || !record.run_id) {
|
|
69
|
+
throw new Error("Workflow name, and run ID are required");
|
|
70
|
+
}
|
|
71
|
+
let key = `${prefix}${tableName}:${record.workflow_name}:${record.run_id}`;
|
|
72
|
+
if (record.resourceId) {
|
|
73
|
+
key = `${key}:${record.resourceId}`;
|
|
74
|
+
}
|
|
75
|
+
return key;
|
|
76
|
+
case storage.TABLE_TRACES:
|
|
77
|
+
if (!record.id) throw new Error("Trace ID is required");
|
|
78
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
79
|
+
case storage.TABLE_SCORERS:
|
|
80
|
+
if (!record.id) throw new Error("Score ID is required");
|
|
81
|
+
return `${prefix}${tableName}:${record.id}`;
|
|
82
|
+
default:
|
|
83
|
+
throw new Error(`Unsupported table: ${tableName}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
getSchemaKey(tableName) {
|
|
87
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
88
|
+
return `${prefix}schema:${tableName}`;
|
|
23
89
|
}
|
|
24
90
|
/**
|
|
25
|
-
*
|
|
26
|
-
* Returns type, length, and keys only to prevent PII leakage.
|
|
91
|
+
* Helper to safely parse data from KV storage
|
|
27
92
|
*/
|
|
28
|
-
|
|
29
|
-
if (!
|
|
30
|
-
if (typeof content === "string") return { type: "string", length: content.length };
|
|
31
|
-
if (Array.isArray(content)) return { type: "array", length: content.length };
|
|
32
|
-
if (typeof content === "object") return { type: "object", keys: Object.keys(content) };
|
|
33
|
-
return { type: typeof content };
|
|
34
|
-
}
|
|
35
|
-
async getThreadById({ threadId }) {
|
|
36
|
-
const thread = await this.operations.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
37
|
-
if (!thread) return null;
|
|
93
|
+
safeParse(text) {
|
|
94
|
+
if (!text) return null;
|
|
38
95
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const mastraError = new error.MastraError(
|
|
47
|
-
{
|
|
48
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "GET_THREAD_BY_ID", "FAILED"),
|
|
49
|
-
domain: error.ErrorDomain.STORAGE,
|
|
50
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
51
|
-
details: {
|
|
52
|
-
threadId
|
|
96
|
+
const data = JSON.parse(text);
|
|
97
|
+
if (data && typeof data === "object" && "value" in data) {
|
|
98
|
+
if (typeof data.value === "string") {
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(data.value);
|
|
101
|
+
} catch {
|
|
102
|
+
return data.value;
|
|
53
103
|
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return data;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
110
|
+
this.logger.error("Failed to parse text:", { message, text });
|
|
59
111
|
return null;
|
|
60
112
|
}
|
|
61
113
|
}
|
|
62
|
-
async
|
|
63
|
-
|
|
64
|
-
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
65
|
-
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
66
|
-
if (page < 0) {
|
|
67
|
-
throw new error.MastraError(
|
|
68
|
-
{
|
|
69
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
70
|
-
domain: error.ErrorDomain.STORAGE,
|
|
71
|
-
category: error.ErrorCategory.USER,
|
|
72
|
-
details: { page }
|
|
73
|
-
},
|
|
74
|
-
new Error("page must be >= 0")
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
78
|
-
const { field, direction } = this.parseOrderBy(orderBy);
|
|
79
|
-
const prefix = this.operations.namespacePrefix ? `${this.operations.namespacePrefix}:` : "";
|
|
80
|
-
const keyObjs = await this.operations.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
|
|
81
|
-
const threads = [];
|
|
82
|
-
for (const { name: key } of keyObjs) {
|
|
83
|
-
const data = await this.operations.getKV(storage.TABLE_THREADS, key);
|
|
84
|
-
if (!data) continue;
|
|
85
|
-
if (data.resourceId !== resourceId) continue;
|
|
86
|
-
threads.push(data);
|
|
87
|
-
}
|
|
88
|
-
threads.sort((a, b) => {
|
|
89
|
-
const aTime = new Date(a[field] || 0).getTime();
|
|
90
|
-
const bTime = new Date(b[field] || 0).getTime();
|
|
91
|
-
return direction === "ASC" ? aTime - bTime : bTime - aTime;
|
|
92
|
-
});
|
|
93
|
-
const end = perPageInput === false ? threads.length : offset + perPage;
|
|
94
|
-
const paginatedThreads = threads.slice(offset, end);
|
|
114
|
+
async createNamespaceById(title) {
|
|
115
|
+
if (this.bindings) {
|
|
95
116
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
hasMore: perPageInput === false ? false : offset + perPage < threads.length,
|
|
100
|
-
threads: paginatedThreads
|
|
117
|
+
id: title,
|
|
118
|
+
title,
|
|
119
|
+
supports_url_encoding: true
|
|
101
120
|
};
|
|
102
|
-
} catch (error$1) {
|
|
103
|
-
throw new error.MastraError(
|
|
104
|
-
{
|
|
105
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
106
|
-
domain: error.ErrorDomain.STORAGE,
|
|
107
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
108
|
-
text: "Failed to get threads by resource ID with pagination"
|
|
109
|
-
},
|
|
110
|
-
error$1
|
|
111
|
-
);
|
|
112
121
|
}
|
|
122
|
+
return await this.client.kv.namespaces.create({
|
|
123
|
+
account_id: this.accountId,
|
|
124
|
+
title
|
|
125
|
+
});
|
|
113
126
|
}
|
|
114
|
-
async
|
|
127
|
+
async createNamespace(namespaceName) {
|
|
115
128
|
try {
|
|
116
|
-
await this.
|
|
117
|
-
return
|
|
118
|
-
} catch (error
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
error$1
|
|
129
|
-
);
|
|
129
|
+
const response = await this.createNamespaceById(namespaceName);
|
|
130
|
+
return response.id;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (error.message && error.message.includes("already exists")) {
|
|
133
|
+
const namespaces = await this.listNamespaces();
|
|
134
|
+
const namespace = namespaces.result.find((ns) => ns.title === namespaceName);
|
|
135
|
+
if (namespace) return namespace.id;
|
|
136
|
+
}
|
|
137
|
+
this.logger.error("Error creating namespace:", error);
|
|
138
|
+
throw new Error(`Failed to create namespace ${namespaceName}: ${error.message}`);
|
|
130
139
|
}
|
|
131
140
|
}
|
|
132
|
-
async
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
throw new Error(`Thread ${id} not found`);
|
|
141
|
-
}
|
|
142
|
-
const updatedThread = {
|
|
143
|
-
...thread,
|
|
144
|
-
title,
|
|
145
|
-
metadata: this.ensureMetadata({
|
|
146
|
-
...thread.metadata ?? {},
|
|
147
|
-
...metadata
|
|
148
|
-
}),
|
|
149
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
141
|
+
async listNamespaces() {
|
|
142
|
+
if (this.bindings) {
|
|
143
|
+
return {
|
|
144
|
+
result: Object.keys(this.bindings).map((name) => ({
|
|
145
|
+
id: name,
|
|
146
|
+
title: name,
|
|
147
|
+
supports_url_encoding: true
|
|
148
|
+
}))
|
|
150
149
|
};
|
|
151
|
-
await this.operations.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
|
|
152
|
-
return updatedThread;
|
|
153
|
-
} catch (error$1) {
|
|
154
|
-
throw new error.MastraError(
|
|
155
|
-
{
|
|
156
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "UPDATE_THREAD", "FAILED"),
|
|
157
|
-
domain: error.ErrorDomain.STORAGE,
|
|
158
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
159
|
-
details: {
|
|
160
|
-
threadId: id,
|
|
161
|
-
title
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
error$1
|
|
165
|
-
);
|
|
166
150
|
}
|
|
151
|
+
let allNamespaces = [];
|
|
152
|
+
let currentPage = 1;
|
|
153
|
+
const perPage = 50;
|
|
154
|
+
let morePagesExist = true;
|
|
155
|
+
while (morePagesExist) {
|
|
156
|
+
const response = await this.client.kv.namespaces.list({
|
|
157
|
+
account_id: this.accountId,
|
|
158
|
+
page: currentPage,
|
|
159
|
+
per_page: perPage
|
|
160
|
+
});
|
|
161
|
+
if (response.result) {
|
|
162
|
+
allNamespaces = allNamespaces.concat(response.result);
|
|
163
|
+
}
|
|
164
|
+
morePagesExist = response.result ? response.result.length === perPage : false;
|
|
165
|
+
if (morePagesExist) {
|
|
166
|
+
currentPage++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { result: allNamespaces };
|
|
167
170
|
}
|
|
168
|
-
|
|
171
|
+
async getNamespaceIdByName(namespaceName) {
|
|
169
172
|
try {
|
|
170
|
-
|
|
173
|
+
const response = await this.listNamespaces();
|
|
174
|
+
const namespace = response.result.find((ns) => ns.title === namespaceName);
|
|
175
|
+
return namespace ? namespace.id : null;
|
|
171
176
|
} catch (error) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
throw error;
|
|
177
|
+
this.logger.error(`Failed to get namespace ID for ${namespaceName}:`, error);
|
|
178
|
+
return null;
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
182
|
-
this.logger?.error(`Error getting thread messages key for thread ${threadId}:`, { message });
|
|
183
|
-
throw error;
|
|
181
|
+
async getOrCreateNamespaceId(namespaceName) {
|
|
182
|
+
let namespaceId = await this.getNamespaceIdByName(namespaceName);
|
|
183
|
+
if (!namespaceId) {
|
|
184
|
+
namespaceId = await this.createNamespace(namespaceName);
|
|
184
185
|
}
|
|
186
|
+
return namespaceId;
|
|
185
187
|
}
|
|
186
|
-
async
|
|
188
|
+
async getNamespaceId(tableName) {
|
|
189
|
+
const prefix = this.namespacePrefix ? `${this.namespacePrefix}_` : "";
|
|
187
190
|
try {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
const messageKeys = await this.operations.listKV(storage.TABLE_MESSAGES);
|
|
193
|
-
const threadMessageKeys = messageKeys.filter((key) => key.name.includes(`${storage.TABLE_MESSAGES}:${threadId}:`));
|
|
194
|
-
await Promise.all([
|
|
195
|
-
// Delete message order
|
|
196
|
-
this.operations.deleteKV(storage.TABLE_MESSAGES, this.getThreadMessagesKey(threadId)),
|
|
197
|
-
// Delete all messages
|
|
198
|
-
...threadMessageKeys.map((key) => this.operations.deleteKV(storage.TABLE_MESSAGES, key.name)),
|
|
199
|
-
// Delete thread
|
|
200
|
-
this.operations.deleteKV(storage.TABLE_THREADS, this.operations.getKey(storage.TABLE_THREADS, { id: threadId }))
|
|
201
|
-
]);
|
|
202
|
-
} catch (error$1) {
|
|
203
|
-
throw new error.MastraError(
|
|
204
|
-
{
|
|
205
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "DELETE_THREAD", "FAILED"),
|
|
206
|
-
domain: error.ErrorDomain.STORAGE,
|
|
207
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
208
|
-
details: {
|
|
209
|
-
threadId
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
error$1
|
|
213
|
-
);
|
|
191
|
+
return await this.getOrCreateNamespaceId(`${prefix}${tableName}`);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
this.logger.error("Error fetching namespace ID:", error);
|
|
194
|
+
throw new Error(`Failed to fetch namespace ID for table ${tableName}: ${error.message}`);
|
|
214
195
|
}
|
|
215
196
|
}
|
|
216
|
-
|
|
217
|
-
* Searches all threads in the KV store to find a message by its ID.
|
|
218
|
-
*
|
|
219
|
-
* **Performance Warning**: This method sequentially scans all threads to locate
|
|
220
|
-
* the message. For stores with many threads, this can result in significant
|
|
221
|
-
* latency and API calls. When possible, callers should provide the `threadId`
|
|
222
|
-
* directly to avoid this full scan.
|
|
223
|
-
*
|
|
224
|
-
* @param messageId - The globally unique message ID to search for
|
|
225
|
-
* @returns The message with its threadId if found, null otherwise
|
|
226
|
-
*/
|
|
227
|
-
async findMessageInAnyThread(messageId) {
|
|
197
|
+
async getNamespaceValue(tableName, key) {
|
|
228
198
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
199
|
+
if (this.bindings) {
|
|
200
|
+
const binding = this.getBinding(tableName);
|
|
201
|
+
const result = await binding.getWithMetadata(key, "text");
|
|
202
|
+
if (!result) return null;
|
|
203
|
+
return JSON.stringify(result);
|
|
204
|
+
} else {
|
|
205
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
206
|
+
const response = await this.client.kv.namespaces.values.get(namespaceId, key, {
|
|
207
|
+
account_id: this.accountId
|
|
208
|
+
});
|
|
209
|
+
return await response.text();
|
|
239
210
|
}
|
|
240
|
-
return null;
|
|
241
211
|
} catch (error) {
|
|
242
|
-
|
|
212
|
+
if (error.message && error.message.includes("key not found")) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
216
|
+
this.logger.error(`Failed to get value for ${tableName} ${key}:`, { message });
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async getKV(tableName, key) {
|
|
221
|
+
try {
|
|
222
|
+
const text = await this.getNamespaceValue(tableName, key);
|
|
223
|
+
return this.safeParse(text);
|
|
224
|
+
} catch (error) {
|
|
225
|
+
this.logger.error(`Failed to get KV value for ${tableName}:${key}:`, error);
|
|
226
|
+
throw new Error(`Failed to get KV value: ${error.message}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async getTableSchema(tableName) {
|
|
230
|
+
try {
|
|
231
|
+
const schemaKey = this.getSchemaKey(tableName);
|
|
232
|
+
return await this.getKV(tableName, schemaKey);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
235
|
+
this.logger.error(`Failed to get schema for ${tableName}:`, { message });
|
|
243
236
|
return null;
|
|
244
237
|
}
|
|
245
238
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
239
|
+
validateColumnValue(value, column) {
|
|
240
|
+
if (value === void 0 || value === null) {
|
|
241
|
+
return column.nullable ?? false;
|
|
242
|
+
}
|
|
243
|
+
switch (column.type) {
|
|
244
|
+
case "text":
|
|
245
|
+
case "uuid":
|
|
246
|
+
return typeof value === "string";
|
|
247
|
+
case "integer":
|
|
248
|
+
case "bigint":
|
|
249
|
+
return typeof value === "number";
|
|
250
|
+
case "timestamp":
|
|
251
|
+
return value instanceof Date || typeof value === "string" && !isNaN(Date.parse(value));
|
|
252
|
+
case "jsonb":
|
|
253
|
+
if (typeof value !== "object") return false;
|
|
254
|
+
try {
|
|
255
|
+
JSON.stringify(value);
|
|
256
|
+
return true;
|
|
257
|
+
} catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
default:
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
260
263
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const currentOrder = await this.getSortedMessages(orderKey);
|
|
271
|
-
const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
|
|
272
|
-
for (const entry of newEntries) {
|
|
273
|
-
orderMap.set(entry.id, entry);
|
|
264
|
+
async validateAgainstSchema(record, schema) {
|
|
265
|
+
try {
|
|
266
|
+
if (!schema || typeof schema !== "object" || schema.value === null) {
|
|
267
|
+
throw new Error("Invalid schema format");
|
|
268
|
+
}
|
|
269
|
+
for (const [columnName, column] of Object.entries(schema)) {
|
|
270
|
+
const value = record[columnName];
|
|
271
|
+
if (column.primaryKey && (value === void 0 || value === null)) {
|
|
272
|
+
throw new Error(`Missing primary key value for column ${columnName}`);
|
|
274
273
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
key: orderKey,
|
|
279
|
-
value: JSON.stringify(updatedOrder)
|
|
280
|
-
});
|
|
281
|
-
} catch (error) {
|
|
282
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
283
|
-
this.logger?.error(`Error updating sorted order for key ${orderKey}:`, { message });
|
|
284
|
-
throw error;
|
|
285
|
-
} finally {
|
|
286
|
-
if (this.updateQueue.get(orderKey) === nextPromise) {
|
|
287
|
-
this.updateQueue.delete(orderKey);
|
|
274
|
+
if (!this.validateColumnValue(value, column)) {
|
|
275
|
+
const valueType = value === null ? "null" : typeof value;
|
|
276
|
+
throw new Error(`Invalid value for column ${columnName}: expected ${column.type}, got ${valueType}`);
|
|
288
277
|
}
|
|
289
278
|
}
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
async getSortedMessages(orderKey) {
|
|
295
|
-
const raw = await this.operations.getKV(storage.TABLE_MESSAGES, orderKey);
|
|
296
|
-
if (!raw) return [];
|
|
297
|
-
try {
|
|
298
|
-
const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
|
|
299
|
-
return Array.isArray(arr) ? arr : [];
|
|
300
|
-
} catch (e) {
|
|
301
|
-
this.logger?.error(`Error parsing order data for key ${orderKey}:`, { e });
|
|
302
|
-
return [];
|
|
279
|
+
} catch (error) {
|
|
280
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
281
|
+
this.logger.error(`Error validating record against schema:`, { message, record, schema });
|
|
282
|
+
throw error;
|
|
303
283
|
}
|
|
304
284
|
}
|
|
305
|
-
async
|
|
285
|
+
async validateRecord(record, tableName) {
|
|
306
286
|
try {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
287
|
+
if (!record || typeof record !== "object") {
|
|
288
|
+
throw new Error("Record must be an object");
|
|
289
|
+
}
|
|
290
|
+
const recordTyped = record;
|
|
291
|
+
const schema = await this.getTableSchema(tableName);
|
|
292
|
+
if (schema) {
|
|
293
|
+
await this.validateAgainstSchema(recordTyped, schema);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
switch (tableName) {
|
|
297
|
+
case storage.TABLE_THREADS:
|
|
298
|
+
if (!("id" in recordTyped) || !("resourceId" in recordTyped) || !("title" in recordTyped)) {
|
|
299
|
+
throw new Error("Thread record missing required fields");
|
|
300
|
+
}
|
|
301
|
+
break;
|
|
302
|
+
case storage.TABLE_MESSAGES:
|
|
303
|
+
if (!("id" in recordTyped) || !("threadId" in recordTyped) || !("content" in recordTyped) || !("role" in recordTyped)) {
|
|
304
|
+
throw new Error("Message record missing required fields");
|
|
305
|
+
}
|
|
306
|
+
break;
|
|
307
|
+
case storage.TABLE_WORKFLOW_SNAPSHOT:
|
|
308
|
+
if (!("workflow_name" in recordTyped) || !("run_id" in recordTyped)) {
|
|
309
|
+
throw new Error("Workflow record missing required fields");
|
|
310
|
+
}
|
|
311
|
+
break;
|
|
312
|
+
case storage.TABLE_TRACES:
|
|
313
|
+
if (!("id" in recordTyped)) {
|
|
314
|
+
throw new Error("Trace record missing required fields");
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
case storage.TABLE_SCORERS:
|
|
318
|
+
if (!("id" in recordTyped) || !("scorerId" in recordTyped)) {
|
|
319
|
+
throw new Error("Score record missing required fields");
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
default:
|
|
323
|
+
throw new Error(`Unknown table type: ${tableName}`);
|
|
324
|
+
}
|
|
326
325
|
} catch (error) {
|
|
327
|
-
|
|
326
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
327
|
+
this.logger.error(`Failed to validate record for ${tableName}:`, { message, record });
|
|
328
328
|
throw error;
|
|
329
329
|
}
|
|
330
330
|
}
|
|
331
|
-
async
|
|
332
|
-
const { messages } = args;
|
|
333
|
-
if (!Array.isArray(messages) || messages.length === 0) return { messages: [] };
|
|
331
|
+
async insert({ tableName, record }) {
|
|
334
332
|
try {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (!message.content) errors.push("content is required");
|
|
340
|
-
if (!message.role) errors.push("role is required");
|
|
341
|
-
if (!message.createdAt) errors.push("createdAt is required");
|
|
342
|
-
if (message.resourceId === null || message.resourceId === void 0) errors.push("resourceId is required");
|
|
343
|
-
if (errors.length > 0) {
|
|
344
|
-
throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
|
|
345
|
-
}
|
|
346
|
-
return {
|
|
347
|
-
...message,
|
|
348
|
-
createdAt: storage.ensureDate(message.createdAt),
|
|
349
|
-
type: message.type || "v2",
|
|
350
|
-
_index: index
|
|
351
|
-
};
|
|
352
|
-
}).filter((m) => !!m);
|
|
353
|
-
const messageMigrationTasks = [];
|
|
354
|
-
for (const message of validatedMessages) {
|
|
355
|
-
const existingMessage = await this.findMessageInAnyThread(message.id);
|
|
356
|
-
this.logger?.debug(
|
|
357
|
-
`Checking message ${message.id}: existing=${existingMessage?.threadId}, new=${message.threadId}`
|
|
358
|
-
);
|
|
359
|
-
if (existingMessage && existingMessage.threadId && existingMessage.threadId !== message.threadId) {
|
|
360
|
-
this.logger?.debug(`Migrating message ${message.id} from ${existingMessage.threadId} to ${message.threadId}`);
|
|
361
|
-
messageMigrationTasks.push(this.migrateMessage(message.id, existingMessage.threadId, message.threadId));
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
await Promise.all(messageMigrationTasks);
|
|
365
|
-
const messagesByThread = validatedMessages.reduce((acc, message) => {
|
|
366
|
-
if (message.threadId && !acc.has(message.threadId)) {
|
|
367
|
-
acc.set(message.threadId, []);
|
|
368
|
-
}
|
|
369
|
-
if (message.threadId) {
|
|
370
|
-
acc.get(message.threadId).push(message);
|
|
371
|
-
}
|
|
372
|
-
return acc;
|
|
373
|
-
}, /* @__PURE__ */ new Map());
|
|
374
|
-
await Promise.all(
|
|
375
|
-
Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
|
|
376
|
-
try {
|
|
377
|
-
const thread = await this.getThreadById({ threadId });
|
|
378
|
-
if (!thread) {
|
|
379
|
-
throw new Error(`Thread ${threadId} not found`);
|
|
380
|
-
}
|
|
381
|
-
await Promise.all(
|
|
382
|
-
threadMessages.map(async (message) => {
|
|
383
|
-
const key = this.getMessageKey(threadId, message.id);
|
|
384
|
-
const { _index, ...cleanMessage } = message;
|
|
385
|
-
const serializedMessage = {
|
|
386
|
-
...cleanMessage,
|
|
387
|
-
createdAt: storage.serializeDate(cleanMessage.createdAt)
|
|
388
|
-
};
|
|
389
|
-
this.logger?.debug(`Saving message ${message.id}`, {
|
|
390
|
-
contentSummary: this.summarizeMessageContent(serializedMessage.content)
|
|
391
|
-
});
|
|
392
|
-
await this.operations.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
|
|
393
|
-
})
|
|
394
|
-
);
|
|
395
|
-
const orderKey = this.getThreadMessagesKey(threadId);
|
|
396
|
-
const entries = await this.updateSorting(threadMessages);
|
|
397
|
-
await this.updateSortedMessages(orderKey, entries);
|
|
398
|
-
const updatedThread = {
|
|
399
|
-
...thread,
|
|
400
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
401
|
-
};
|
|
402
|
-
await this.operations.putKV({
|
|
403
|
-
tableName: storage.TABLE_THREADS,
|
|
404
|
-
key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
405
|
-
value: updatedThread
|
|
406
|
-
});
|
|
407
|
-
} catch (error$1) {
|
|
408
|
-
throw new error.MastraError(
|
|
409
|
-
{
|
|
410
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "SAVE_MESSAGES", "FAILED"),
|
|
411
|
-
domain: error.ErrorDomain.STORAGE,
|
|
412
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
413
|
-
details: {
|
|
414
|
-
threadId
|
|
415
|
-
}
|
|
416
|
-
},
|
|
417
|
-
error$1
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
})
|
|
421
|
-
);
|
|
422
|
-
const prepared = validatedMessages.map(
|
|
423
|
-
({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
|
|
424
|
-
);
|
|
425
|
-
const list = new agent.MessageList().add(prepared, "memory");
|
|
426
|
-
return { messages: list.get.all.db() };
|
|
333
|
+
const key = this.getKey(tableName, record);
|
|
334
|
+
const processedRecord = { ...record };
|
|
335
|
+
await this.validateRecord(processedRecord, tableName);
|
|
336
|
+
await this.putKV({ tableName, key, value: processedRecord });
|
|
427
337
|
} catch (error$1) {
|
|
428
338
|
throw new error.MastraError(
|
|
429
339
|
{
|
|
430
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
340
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "INSERT", "FAILED"),
|
|
431
341
|
domain: error.ErrorDomain.STORAGE,
|
|
432
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
342
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
343
|
+
details: {
|
|
344
|
+
tableName
|
|
345
|
+
}
|
|
433
346
|
},
|
|
434
347
|
error$1
|
|
435
348
|
);
|
|
436
349
|
}
|
|
437
350
|
}
|
|
438
|
-
async
|
|
439
|
-
const order = await this.getSortedMessages(orderKey);
|
|
440
|
-
const index = order.findIndex((item) => item.id === id);
|
|
441
|
-
return index >= 0 ? index : null;
|
|
442
|
-
}
|
|
443
|
-
async getRange(orderKey, start, end) {
|
|
444
|
-
const order = await this.getSortedMessages(orderKey);
|
|
445
|
-
const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
|
|
446
|
-
const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
|
|
447
|
-
const sliced = order.slice(actualStart, actualEnd + 1);
|
|
448
|
-
return sliced.map((item) => item.id);
|
|
449
|
-
}
|
|
450
|
-
async getLastN(orderKey, n) {
|
|
451
|
-
return this.getRange(orderKey, -n, -1);
|
|
452
|
-
}
|
|
453
|
-
async getFullOrder(orderKey) {
|
|
454
|
-
return this.getRange(orderKey, 0, -1);
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Retrieves messages specified in the include array along with their surrounding context.
|
|
458
|
-
*
|
|
459
|
-
* **Performance Note**: When `threadId` is not provided in an include entry, this method
|
|
460
|
-
* must call `findMessageInAnyThread` which sequentially scans all threads in the KV store.
|
|
461
|
-
* For optimal performance, callers should provide `threadId` in include entries when known.
|
|
462
|
-
*
|
|
463
|
-
* @param include - Array of message IDs to include, optionally with context windows
|
|
464
|
-
* @param messageIds - Set to accumulate the message IDs that should be fetched
|
|
465
|
-
*/
|
|
466
|
-
async getIncludedMessagesWithContext(include, messageIds) {
|
|
467
|
-
await Promise.all(
|
|
468
|
-
include.map(async (item) => {
|
|
469
|
-
let targetThreadId = item.threadId;
|
|
470
|
-
if (!targetThreadId) {
|
|
471
|
-
const foundMessage = await this.findMessageInAnyThread(item.id);
|
|
472
|
-
if (!foundMessage) return;
|
|
473
|
-
targetThreadId = foundMessage.threadId;
|
|
474
|
-
}
|
|
475
|
-
if (!targetThreadId) return;
|
|
476
|
-
const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
|
|
477
|
-
messageIds.add(item.id);
|
|
478
|
-
if (!item.withPreviousMessages && !item.withNextMessages) return;
|
|
479
|
-
const rank = await this.getRank(threadMessagesKey, item.id);
|
|
480
|
-
if (rank === null) return;
|
|
481
|
-
if (item.withPreviousMessages) {
|
|
482
|
-
const prevIds = await this.getRange(
|
|
483
|
-
threadMessagesKey,
|
|
484
|
-
Math.max(0, rank - item.withPreviousMessages),
|
|
485
|
-
rank - 1
|
|
486
|
-
);
|
|
487
|
-
prevIds.forEach((id) => messageIds.add(id));
|
|
488
|
-
}
|
|
489
|
-
if (item.withNextMessages) {
|
|
490
|
-
const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
491
|
-
nextIds.forEach((id) => messageIds.add(id));
|
|
492
|
-
}
|
|
493
|
-
})
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
|
-
async getRecentMessages(threadId, limit, messageIds) {
|
|
497
|
-
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
498
|
-
if (limit <= 0) return;
|
|
499
|
-
try {
|
|
500
|
-
const threadMessagesKey = this.getThreadMessagesKey(threadId);
|
|
501
|
-
const latestIds = await this.getLastN(threadMessagesKey, limit);
|
|
502
|
-
latestIds.forEach((id) => messageIds.add(id));
|
|
503
|
-
} catch {
|
|
504
|
-
this.logger?.debug(`No message order found for thread ${threadId}, skipping latest messages`);
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Fetches and parses messages from one or more threads.
|
|
509
|
-
*
|
|
510
|
-
* **Performance Note**: When neither `include` entries with `threadId` nor `targetThreadId`
|
|
511
|
-
* are provided, this method falls back to `findMessageInAnyThread` which scans all threads.
|
|
512
|
-
* For optimal performance, provide `threadId` in include entries or specify `targetThreadId`.
|
|
513
|
-
*/
|
|
514
|
-
async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
|
|
515
|
-
const messageIdToThreadId = /* @__PURE__ */ new Map();
|
|
516
|
-
if (include) {
|
|
517
|
-
for (const item of include) {
|
|
518
|
-
if (item.threadId) {
|
|
519
|
-
messageIdToThreadId.set(item.id, item.threadId);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
const messages = await Promise.all(
|
|
524
|
-
messageIds.map(async (id) => {
|
|
525
|
-
try {
|
|
526
|
-
let threadId = messageIdToThreadId.get(id);
|
|
527
|
-
if (!threadId) {
|
|
528
|
-
if (targetThreadId) {
|
|
529
|
-
threadId = targetThreadId;
|
|
530
|
-
} else {
|
|
531
|
-
const foundMessage = await this.findMessageInAnyThread(id);
|
|
532
|
-
if (foundMessage) {
|
|
533
|
-
threadId = foundMessage.threadId;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
if (!threadId) return null;
|
|
538
|
-
const key = this.getMessageKey(threadId, id);
|
|
539
|
-
const data = await this.operations.getKV(storage.TABLE_MESSAGES, key);
|
|
540
|
-
if (!data) return null;
|
|
541
|
-
const parsed = typeof data === "string" ? JSON.parse(data) : data;
|
|
542
|
-
this.logger?.debug(`Retrieved message ${id} from thread ${threadId}`, {
|
|
543
|
-
contentSummary: this.summarizeMessageContent(parsed.content)
|
|
544
|
-
});
|
|
545
|
-
return parsed;
|
|
546
|
-
} catch (error) {
|
|
547
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
548
|
-
this.logger?.error(`Error retrieving message ${id}:`, { message });
|
|
549
|
-
return null;
|
|
550
|
-
}
|
|
551
|
-
})
|
|
552
|
-
);
|
|
553
|
-
return messages.filter((msg) => msg !== null);
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Retrieves messages by their IDs.
|
|
557
|
-
*
|
|
558
|
-
* **Performance Warning**: This method calls `findMessageInAnyThread` for each message ID,
|
|
559
|
-
* which scans all threads in the KV store. For large numbers of messages or threads,
|
|
560
|
-
* this can result in significant latency. Consider using `listMessages` with specific
|
|
561
|
-
* thread IDs when the thread context is known.
|
|
562
|
-
*/
|
|
563
|
-
async listMessagesById({ messageIds }) {
|
|
564
|
-
if (messageIds.length === 0) return { messages: [] };
|
|
351
|
+
async load({ tableName, keys }) {
|
|
565
352
|
try {
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
);
|
|
569
|
-
|
|
570
|
-
...message,
|
|
571
|
-
...message.type !== `v2` && { type: message.type },
|
|
572
|
-
createdAt: storage.ensureDate(message.createdAt)
|
|
573
|
-
}));
|
|
574
|
-
const list = new agent.MessageList().add(prepared, "memory");
|
|
575
|
-
return { messages: list.get.all.db() };
|
|
353
|
+
const key = this.getKey(tableName, keys);
|
|
354
|
+
const data = await this.getKV(tableName, key);
|
|
355
|
+
if (!data) return null;
|
|
356
|
+
return data;
|
|
576
357
|
} catch (error$1) {
|
|
577
358
|
const mastraError = new error.MastraError(
|
|
578
359
|
{
|
|
579
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
360
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LOAD", "FAILED"),
|
|
580
361
|
domain: error.ErrorDomain.STORAGE,
|
|
581
362
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
582
|
-
text: `Error retrieving messages by ID`,
|
|
583
363
|
details: {
|
|
584
|
-
|
|
364
|
+
tableName
|
|
585
365
|
}
|
|
586
366
|
},
|
|
587
367
|
error$1
|
|
588
368
|
);
|
|
589
369
|
this.logger?.trackException(mastraError);
|
|
590
370
|
this.logger?.error(mastraError.toString());
|
|
591
|
-
return
|
|
371
|
+
return null;
|
|
592
372
|
}
|
|
593
373
|
}
|
|
594
|
-
async
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
374
|
+
async batchInsert(input) {
|
|
375
|
+
if (!input.records || input.records.length === 0) return;
|
|
376
|
+
try {
|
|
377
|
+
await Promise.all(
|
|
378
|
+
input.records.map(async (record) => {
|
|
379
|
+
const key = this.getKey(input.tableName, record);
|
|
380
|
+
await this.putKV({ tableName: input.tableName, key, value: record });
|
|
381
|
+
})
|
|
382
|
+
);
|
|
383
|
+
} catch (error$1) {
|
|
599
384
|
throw new error.MastraError(
|
|
600
385
|
{
|
|
601
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
386
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "BATCH_INSERT", "FAILED"),
|
|
602
387
|
domain: error.ErrorDomain.STORAGE,
|
|
603
388
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
604
|
-
|
|
389
|
+
text: `Error in batch insert for table ${input.tableName}`,
|
|
390
|
+
details: {
|
|
391
|
+
tableName: input.tableName
|
|
392
|
+
}
|
|
605
393
|
},
|
|
606
|
-
|
|
394
|
+
error$1
|
|
607
395
|
);
|
|
608
396
|
}
|
|
609
|
-
|
|
610
|
-
|
|
397
|
+
}
|
|
398
|
+
safeSerialize(data) {
|
|
399
|
+
return typeof data === "string" ? data : JSON.stringify(data);
|
|
400
|
+
}
|
|
401
|
+
async putNamespaceValue({
|
|
402
|
+
tableName,
|
|
403
|
+
key,
|
|
404
|
+
value,
|
|
405
|
+
metadata
|
|
406
|
+
}) {
|
|
611
407
|
try {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
category: error.ErrorCategory.USER,
|
|
618
|
-
details: { page }
|
|
619
|
-
},
|
|
620
|
-
new Error("page must be >= 0")
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
624
|
-
const threadMessageIds = /* @__PURE__ */ new Set();
|
|
625
|
-
for (const tid of threadIds) {
|
|
626
|
-
try {
|
|
627
|
-
const threadMessagesKey = this.getThreadMessagesKey(tid);
|
|
628
|
-
const allIds = await this.getFullOrder(threadMessagesKey);
|
|
629
|
-
allIds.forEach((id) => threadMessageIds.add(id));
|
|
630
|
-
} catch {
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
const threadMessages = await this.fetchAndParseMessagesFromMultipleThreads(
|
|
634
|
-
Array.from(threadMessageIds),
|
|
635
|
-
void 0,
|
|
636
|
-
threadIds.length === 1 ? threadIds[0] : void 0
|
|
637
|
-
);
|
|
638
|
-
let filteredThreadMessages = threadMessages;
|
|
639
|
-
if (resourceId) {
|
|
640
|
-
filteredThreadMessages = filteredThreadMessages.filter((msg) => msg.resourceId === resourceId);
|
|
641
|
-
}
|
|
642
|
-
const dateRange = filter?.dateRange;
|
|
643
|
-
if (dateRange) {
|
|
644
|
-
filteredThreadMessages = filteredThreadMessages.filter((msg) => {
|
|
645
|
-
const messageDate = new Date(msg.createdAt);
|
|
646
|
-
if (dateRange.start && messageDate < new Date(dateRange.start)) return false;
|
|
647
|
-
if (dateRange.end && messageDate > new Date(dateRange.end)) return false;
|
|
648
|
-
return true;
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
const total = filteredThreadMessages.length;
|
|
652
|
-
if (perPage === 0 && (!include || include.length === 0)) {
|
|
653
|
-
return {
|
|
654
|
-
messages: [],
|
|
655
|
-
total,
|
|
656
|
-
page,
|
|
657
|
-
perPage: perPageForResponse,
|
|
658
|
-
hasMore: offset < total
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
filteredThreadMessages.sort((a, b) => {
|
|
662
|
-
const timeA = new Date(a.createdAt).getTime();
|
|
663
|
-
const timeB = new Date(b.createdAt).getTime();
|
|
664
|
-
const timeDiff = direction === "ASC" ? timeA - timeB : timeB - timeA;
|
|
665
|
-
if (timeDiff === 0) {
|
|
666
|
-
return a.id.localeCompare(b.id);
|
|
667
|
-
}
|
|
668
|
-
return timeDiff;
|
|
669
|
-
});
|
|
670
|
-
let paginatedMessages;
|
|
671
|
-
if (perPage === 0) {
|
|
672
|
-
paginatedMessages = [];
|
|
673
|
-
} else if (perPage === Number.MAX_SAFE_INTEGER) {
|
|
674
|
-
paginatedMessages = filteredThreadMessages;
|
|
408
|
+
const serializedValue = this.safeSerialize(value);
|
|
409
|
+
const serializedMetadata = metadata ? this.safeSerialize(metadata) : "";
|
|
410
|
+
if (this.bindings) {
|
|
411
|
+
const binding = this.getBinding(tableName);
|
|
412
|
+
await binding.put(key, serializedValue, { metadata: serializedMetadata });
|
|
675
413
|
} else {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
const paginatedIds = new Set(paginatedMessages.map((m) => m.id));
|
|
683
|
-
const idsToFetch = Array.from(includedMessageIds).filter((id) => !paginatedIds.has(id));
|
|
684
|
-
if (idsToFetch.length > 0) {
|
|
685
|
-
includedMessages = await this.fetchAndParseMessagesFromMultipleThreads(idsToFetch, include, void 0);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
689
|
-
const allMessages = [];
|
|
690
|
-
for (const msg of paginatedMessages) {
|
|
691
|
-
if (!seenIds.has(msg.id)) {
|
|
692
|
-
allMessages.push(msg);
|
|
693
|
-
seenIds.add(msg.id);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
for (const msg of includedMessages) {
|
|
697
|
-
if (!seenIds.has(msg.id)) {
|
|
698
|
-
allMessages.push(msg);
|
|
699
|
-
seenIds.add(msg.id);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
allMessages.sort((a, b) => {
|
|
703
|
-
const timeA = new Date(a.createdAt).getTime();
|
|
704
|
-
const timeB = new Date(b.createdAt).getTime();
|
|
705
|
-
const timeDiff = direction === "ASC" ? timeA - timeB : timeB - timeA;
|
|
706
|
-
if (timeDiff === 0) {
|
|
707
|
-
return a.id.localeCompare(b.id);
|
|
708
|
-
}
|
|
709
|
-
return timeDiff;
|
|
710
|
-
});
|
|
711
|
-
let filteredMessages = allMessages;
|
|
712
|
-
const paginatedCount = paginatedMessages.length;
|
|
713
|
-
if (total === 0 && filteredMessages.length === 0 && (!include || include.length === 0)) {
|
|
714
|
-
return {
|
|
715
|
-
messages: [],
|
|
716
|
-
total: 0,
|
|
717
|
-
page,
|
|
718
|
-
perPage: perPageForResponse,
|
|
719
|
-
hasMore: false
|
|
720
|
-
};
|
|
414
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
415
|
+
await this.client.kv.namespaces.values.update(namespaceId, key, {
|
|
416
|
+
account_id: this.accountId,
|
|
417
|
+
value: serializedValue,
|
|
418
|
+
metadata: serializedMetadata
|
|
419
|
+
});
|
|
721
420
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
752
|
-
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + paginatedCount < total;
|
|
753
|
-
return {
|
|
754
|
-
messages: finalMessages,
|
|
755
|
-
total,
|
|
756
|
-
page,
|
|
757
|
-
perPage: perPageForResponse,
|
|
758
|
-
hasMore
|
|
421
|
+
} catch (error) {
|
|
422
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
423
|
+
this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
async putKV({
|
|
428
|
+
tableName,
|
|
429
|
+
key,
|
|
430
|
+
value,
|
|
431
|
+
metadata
|
|
432
|
+
}) {
|
|
433
|
+
try {
|
|
434
|
+
await this.putNamespaceValue({ tableName, key, value, metadata });
|
|
435
|
+
} catch (error) {
|
|
436
|
+
this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
|
|
437
|
+
throw new Error(`Failed to put KV value: ${error.message}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async createTable({
|
|
441
|
+
tableName,
|
|
442
|
+
schema
|
|
443
|
+
}) {
|
|
444
|
+
try {
|
|
445
|
+
const schemaKey = this.getSchemaKey(tableName);
|
|
446
|
+
const metadata = {
|
|
447
|
+
type: "table_schema",
|
|
448
|
+
tableName,
|
|
449
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
759
450
|
};
|
|
451
|
+
await this.putKV({ tableName, key: schemaKey, value: schema, metadata });
|
|
760
452
|
} catch (error$1) {
|
|
761
|
-
|
|
453
|
+
throw new error.MastraError(
|
|
762
454
|
{
|
|
763
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
455
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "CREATE_TABLE", "FAILED"),
|
|
764
456
|
domain: error.ErrorDomain.STORAGE,
|
|
765
457
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
766
|
-
text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
767
458
|
details: {
|
|
768
|
-
|
|
769
|
-
resourceId: resourceId ?? ""
|
|
459
|
+
tableName
|
|
770
460
|
}
|
|
771
461
|
},
|
|
772
462
|
error$1
|
|
773
463
|
);
|
|
774
|
-
this.logger?.error?.(mastraError.toString());
|
|
775
|
-
this.logger?.trackException?.(mastraError);
|
|
776
|
-
return {
|
|
777
|
-
messages: [],
|
|
778
|
-
total: 0,
|
|
779
|
-
page,
|
|
780
|
-
perPage: perPageForResponse,
|
|
781
|
-
hasMore: false
|
|
782
|
-
};
|
|
783
464
|
}
|
|
784
465
|
}
|
|
785
|
-
async
|
|
466
|
+
async clearTable({ tableName }) {
|
|
786
467
|
try {
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
messageKey = key;
|
|
800
|
-
break;
|
|
468
|
+
const keys = await this.listKV(tableName);
|
|
469
|
+
if (keys.length > 0) {
|
|
470
|
+
await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
|
|
471
|
+
}
|
|
472
|
+
} catch (error$1) {
|
|
473
|
+
throw new error.MastraError(
|
|
474
|
+
{
|
|
475
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "CLEAR_TABLE", "FAILED"),
|
|
476
|
+
domain: error.ErrorDomain.STORAGE,
|
|
477
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
478
|
+
details: {
|
|
479
|
+
tableName
|
|
801
480
|
}
|
|
802
|
-
}
|
|
803
|
-
if (!existingMessage) {
|
|
804
|
-
continue;
|
|
805
|
-
}
|
|
806
|
-
const updatedMessage = {
|
|
807
|
-
...existingMessage,
|
|
808
|
-
...otherFields,
|
|
809
|
-
id
|
|
810
|
-
};
|
|
811
|
-
if (content) {
|
|
812
|
-
if (content.metadata !== void 0) {
|
|
813
|
-
updatedMessage.content = {
|
|
814
|
-
...updatedMessage.content,
|
|
815
|
-
metadata: {
|
|
816
|
-
...updatedMessage.content?.metadata,
|
|
817
|
-
...content.metadata
|
|
818
|
-
}
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
if (content.content !== void 0) {
|
|
822
|
-
updatedMessage.content = {
|
|
823
|
-
...updatedMessage.content,
|
|
824
|
-
content: content.content
|
|
825
|
-
};
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
829
|
-
await this.operations.deleteKV(storage.TABLE_MESSAGES, messageKey);
|
|
830
|
-
updatedMessage.threadId = messageUpdate.threadId;
|
|
831
|
-
const newMessageKey = this.getMessageKey(messageUpdate.threadId, id);
|
|
832
|
-
await this.operations.putKV({
|
|
833
|
-
tableName: storage.TABLE_MESSAGES,
|
|
834
|
-
key: newMessageKey,
|
|
835
|
-
value: updatedMessage
|
|
836
|
-
});
|
|
837
|
-
if (existingMessage.threadId) {
|
|
838
|
-
const sourceOrderKey = this.getThreadMessagesKey(existingMessage.threadId);
|
|
839
|
-
const sourceEntries = await this.getSortedMessages(sourceOrderKey);
|
|
840
|
-
const filteredEntries = sourceEntries.filter((entry) => entry.id !== id);
|
|
841
|
-
await this.updateSortedMessages(sourceOrderKey, filteredEntries);
|
|
842
|
-
}
|
|
843
|
-
const destOrderKey = this.getThreadMessagesKey(messageUpdate.threadId);
|
|
844
|
-
const destEntries = await this.getSortedMessages(destOrderKey);
|
|
845
|
-
const newEntry = { id, score: Date.now() };
|
|
846
|
-
destEntries.push(newEntry);
|
|
847
|
-
await this.updateSortedMessages(destOrderKey, destEntries);
|
|
848
|
-
} else {
|
|
849
|
-
await this.operations.putKV({
|
|
850
|
-
tableName: storage.TABLE_MESSAGES,
|
|
851
|
-
key: messageKey,
|
|
852
|
-
value: updatedMessage
|
|
853
|
-
});
|
|
854
|
-
}
|
|
855
|
-
const threadsToUpdate = /* @__PURE__ */ new Set();
|
|
856
|
-
if (updatedMessage.threadId) {
|
|
857
|
-
threadsToUpdate.add(updatedMessage.threadId);
|
|
858
|
-
}
|
|
859
|
-
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
860
|
-
if (existingMessage.threadId) {
|
|
861
|
-
threadsToUpdate.add(existingMessage.threadId);
|
|
862
|
-
}
|
|
863
|
-
threadsToUpdate.add(messageUpdate.threadId);
|
|
864
|
-
}
|
|
865
|
-
for (const threadId of threadsToUpdate) {
|
|
866
|
-
const thread = await this.getThreadById({ threadId });
|
|
867
|
-
if (thread) {
|
|
868
|
-
const updatedThread = {
|
|
869
|
-
...thread,
|
|
870
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
871
|
-
};
|
|
872
|
-
await this.operations.putKV({
|
|
873
|
-
tableName: storage.TABLE_THREADS,
|
|
874
|
-
key: this.operations.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
875
|
-
value: updatedThread
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
updatedMessages.push(updatedMessage);
|
|
880
|
-
}
|
|
881
|
-
return updatedMessages;
|
|
882
|
-
} catch (error$1) {
|
|
883
|
-
throw new error.MastraError(
|
|
884
|
-
{
|
|
885
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "UPDATE_MESSAGES", "FAILED"),
|
|
886
|
-
domain: error.ErrorDomain.STORAGE,
|
|
887
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
888
|
-
text: "Failed to update messages"
|
|
889
481
|
},
|
|
890
482
|
error$1
|
|
891
483
|
);
|
|
892
484
|
}
|
|
893
485
|
}
|
|
894
|
-
async
|
|
486
|
+
async dropTable({ tableName }) {
|
|
895
487
|
try {
|
|
896
|
-
const
|
|
897
|
-
if (
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
...resource,
|
|
901
|
-
createdAt: storage.ensureDate(resource.createdAt),
|
|
902
|
-
updatedAt: storage.ensureDate(resource.updatedAt),
|
|
903
|
-
metadata: this.ensureMetadata(resource.metadata)
|
|
904
|
-
};
|
|
488
|
+
const keys = await this.listKV(tableName);
|
|
489
|
+
if (keys.length > 0) {
|
|
490
|
+
await Promise.all(keys.map((keyObj) => this.deleteKV(tableName, keyObj.name)));
|
|
491
|
+
}
|
|
905
492
|
} catch (error$1) {
|
|
906
|
-
|
|
493
|
+
throw new error.MastraError(
|
|
907
494
|
{
|
|
908
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
495
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "DROP_TABLE", "FAILED"),
|
|
909
496
|
domain: error.ErrorDomain.STORAGE,
|
|
910
497
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
911
498
|
details: {
|
|
912
|
-
|
|
499
|
+
tableName
|
|
913
500
|
}
|
|
914
501
|
},
|
|
915
502
|
error$1
|
|
916
503
|
);
|
|
917
|
-
this.logger?.trackException(mastraError);
|
|
918
|
-
this.logger?.error(mastraError.toString());
|
|
919
|
-
return null;
|
|
920
504
|
}
|
|
921
505
|
}
|
|
922
|
-
async
|
|
506
|
+
async listNamespaceKeys(tableName, options) {
|
|
923
507
|
try {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
508
|
+
if (this.bindings) {
|
|
509
|
+
const binding = this.getBinding(tableName);
|
|
510
|
+
const response = await binding.list({
|
|
511
|
+
limit: options?.limit || 1e3,
|
|
512
|
+
prefix: options?.prefix
|
|
513
|
+
});
|
|
514
|
+
return response.keys;
|
|
515
|
+
} else {
|
|
516
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
517
|
+
const response = await this.client.kv.namespaces.keys.list(namespaceId, {
|
|
518
|
+
account_id: this.accountId,
|
|
519
|
+
limit: options?.limit || 1e3,
|
|
520
|
+
prefix: options?.prefix
|
|
521
|
+
});
|
|
522
|
+
return response.result;
|
|
523
|
+
}
|
|
934
524
|
} catch (error$1) {
|
|
935
525
|
throw new error.MastraError(
|
|
936
526
|
{
|
|
937
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
527
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_NAMESPACE_KEYS", "FAILED"),
|
|
938
528
|
domain: error.ErrorDomain.STORAGE,
|
|
939
529
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
940
530
|
details: {
|
|
941
|
-
|
|
531
|
+
tableName
|
|
942
532
|
}
|
|
943
533
|
},
|
|
944
534
|
error$1
|
|
945
535
|
);
|
|
946
536
|
}
|
|
947
537
|
}
|
|
948
|
-
async
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
538
|
+
async deleteNamespaceValue(tableName, key) {
|
|
539
|
+
if (this.bindings) {
|
|
540
|
+
const binding = this.getBinding(tableName);
|
|
541
|
+
await binding.delete(key);
|
|
542
|
+
} else {
|
|
543
|
+
const namespaceId = await this.getNamespaceId(tableName);
|
|
544
|
+
await this.client.kv.namespaces.values.delete(namespaceId, key, {
|
|
545
|
+
account_id: this.accountId
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
async deleteKV(tableName, key) {
|
|
550
|
+
try {
|
|
551
|
+
await this.deleteNamespaceValue(tableName, key);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
this.logger.error(`Failed to delete KV value for ${tableName}:${key}:`, error);
|
|
554
|
+
throw new Error(`Failed to delete KV value: ${error.message}`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async listKV(tableName, options) {
|
|
558
|
+
try {
|
|
559
|
+
return await this.listNamespaceKeys(tableName, options);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
this.logger.error(`Failed to list KV for ${tableName}:`, error);
|
|
562
|
+
throw new Error(`Failed to list KV: ${error.message}`);
|
|
963
563
|
}
|
|
964
|
-
const updatedAt = /* @__PURE__ */ new Date();
|
|
965
|
-
const updatedResource = {
|
|
966
|
-
...existingResource,
|
|
967
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
968
|
-
metadata: {
|
|
969
|
-
...existingResource.metadata,
|
|
970
|
-
...metadata
|
|
971
|
-
},
|
|
972
|
-
updatedAt
|
|
973
|
-
};
|
|
974
|
-
return this.saveResource({ resource: updatedResource });
|
|
975
564
|
}
|
|
976
565
|
};
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
constructor({
|
|
983
|
-
namespacePrefix,
|
|
984
|
-
bindings,
|
|
985
|
-
client,
|
|
986
|
-
accountId
|
|
987
|
-
}) {
|
|
566
|
+
|
|
567
|
+
// src/storage/domains/memory/index.ts
|
|
568
|
+
var MemoryStorageCloudflare = class extends storage.MemoryStorage {
|
|
569
|
+
#db;
|
|
570
|
+
constructor(config) {
|
|
988
571
|
super();
|
|
989
|
-
this
|
|
990
|
-
this.namespacePrefix = namespacePrefix;
|
|
991
|
-
this.client = client;
|
|
992
|
-
this.accountId = accountId;
|
|
572
|
+
this.#db = new CloudflareKVDB(resolveCloudflareConfig(config));
|
|
993
573
|
}
|
|
994
|
-
async
|
|
995
|
-
return true;
|
|
574
|
+
async init() {
|
|
996
575
|
}
|
|
997
|
-
async
|
|
576
|
+
async dangerouslyClearAll() {
|
|
577
|
+
await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
578
|
+
await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
579
|
+
await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
998
580
|
}
|
|
999
|
-
|
|
581
|
+
ensureMetadata(metadata) {
|
|
582
|
+
if (!metadata) return void 0;
|
|
583
|
+
return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Summarizes message content without exposing raw data (for logging).
|
|
587
|
+
* Returns type, length, and keys only to prevent PII leakage.
|
|
588
|
+
*/
|
|
589
|
+
summarizeMessageContent(content) {
|
|
590
|
+
if (!content) return { type: "undefined" };
|
|
591
|
+
if (typeof content === "string") return { type: "string", length: content.length };
|
|
592
|
+
if (Array.isArray(content)) return { type: "array", length: content.length };
|
|
593
|
+
if (typeof content === "object") return { type: "object", keys: Object.keys(content) };
|
|
594
|
+
return { type: typeof content };
|
|
595
|
+
}
|
|
596
|
+
async getThreadById({ threadId }) {
|
|
597
|
+
const thread = await this.#db.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
598
|
+
if (!thread) return null;
|
|
1000
599
|
try {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
600
|
+
return {
|
|
601
|
+
...thread,
|
|
602
|
+
createdAt: storage.ensureDate(thread.createdAt),
|
|
603
|
+
updatedAt: storage.ensureDate(thread.updatedAt),
|
|
604
|
+
metadata: this.ensureMetadata(thread.metadata)
|
|
605
|
+
};
|
|
1005
606
|
} catch (error$1) {
|
|
1006
|
-
|
|
607
|
+
const mastraError = new error.MastraError(
|
|
1007
608
|
{
|
|
1008
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
609
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "GET_THREAD_BY_ID", "FAILED"),
|
|
1009
610
|
domain: error.ErrorDomain.STORAGE,
|
|
1010
611
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1011
612
|
details: {
|
|
1012
|
-
|
|
613
|
+
threadId
|
|
1013
614
|
}
|
|
1014
615
|
},
|
|
1015
616
|
error$1
|
|
1016
617
|
);
|
|
618
|
+
this.logger?.trackException(mastraError);
|
|
619
|
+
this.logger?.error(mastraError.toString());
|
|
620
|
+
return null;
|
|
1017
621
|
}
|
|
1018
622
|
}
|
|
1019
|
-
async
|
|
623
|
+
async listThreadsByResourceId(args) {
|
|
1020
624
|
try {
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
|
|
625
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
626
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
627
|
+
if (page < 0) {
|
|
628
|
+
throw new error.MastraError(
|
|
629
|
+
{
|
|
630
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
631
|
+
domain: error.ErrorDomain.STORAGE,
|
|
632
|
+
category: error.ErrorCategory.USER,
|
|
633
|
+
details: { page }
|
|
634
|
+
},
|
|
635
|
+
new Error("page must be >= 0")
|
|
636
|
+
);
|
|
1024
637
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
)
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
let key = `${prefix}${tableName}:${record.workflow_name}:${record.run_id}`;
|
|
1061
|
-
if (record.resourceId) {
|
|
1062
|
-
key = `${key}:${record.resourceId}`;
|
|
1063
|
-
}
|
|
1064
|
-
return key;
|
|
1065
|
-
case storage.TABLE_TRACES:
|
|
1066
|
-
if (!record.id) throw new Error("Trace ID is required");
|
|
1067
|
-
return `${prefix}${tableName}:${record.id}`;
|
|
1068
|
-
case storage.TABLE_SCORERS:
|
|
1069
|
-
if (!record.id) throw new Error("Score ID is required");
|
|
1070
|
-
return `${prefix}${tableName}:${record.id}`;
|
|
1071
|
-
default:
|
|
1072
|
-
throw new Error(`Unsupported table: ${tableName}`);
|
|
638
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
639
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
640
|
+
const prefix = this.#db.namespacePrefix ? `${this.#db.namespacePrefix}:` : "";
|
|
641
|
+
const keyObjs = await this.#db.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
|
|
642
|
+
const threads = [];
|
|
643
|
+
for (const { name: key } of keyObjs) {
|
|
644
|
+
const data = await this.#db.getKV(storage.TABLE_THREADS, key);
|
|
645
|
+
if (!data) continue;
|
|
646
|
+
if (data.resourceId !== resourceId) continue;
|
|
647
|
+
threads.push(data);
|
|
648
|
+
}
|
|
649
|
+
threads.sort((a, b) => {
|
|
650
|
+
const aTime = new Date(a[field] || 0).getTime();
|
|
651
|
+
const bTime = new Date(b[field] || 0).getTime();
|
|
652
|
+
return direction === "ASC" ? aTime - bTime : bTime - aTime;
|
|
653
|
+
});
|
|
654
|
+
const end = perPageInput === false ? threads.length : offset + perPage;
|
|
655
|
+
const paginatedThreads = threads.slice(offset, end);
|
|
656
|
+
return {
|
|
657
|
+
page,
|
|
658
|
+
perPage: perPageForResponse,
|
|
659
|
+
total: threads.length,
|
|
660
|
+
hasMore: perPageInput === false ? false : offset + perPage < threads.length,
|
|
661
|
+
threads: paginatedThreads
|
|
662
|
+
};
|
|
663
|
+
} catch (error$1) {
|
|
664
|
+
throw new error.MastraError(
|
|
665
|
+
{
|
|
666
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
667
|
+
domain: error.ErrorDomain.STORAGE,
|
|
668
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
669
|
+
text: "Failed to get threads by resource ID with pagination"
|
|
670
|
+
},
|
|
671
|
+
error$1
|
|
672
|
+
);
|
|
1073
673
|
}
|
|
1074
674
|
}
|
|
1075
|
-
|
|
1076
|
-
const prefix = this.namespacePrefix ? `${this.namespacePrefix}:` : "";
|
|
1077
|
-
return `${prefix}schema:${tableName}`;
|
|
1078
|
-
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Helper to safely parse data from KV storage
|
|
1081
|
-
*/
|
|
1082
|
-
safeParse(text) {
|
|
1083
|
-
if (!text) return null;
|
|
675
|
+
async saveThread({ thread }) {
|
|
1084
676
|
try {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
677
|
+
await this.#db.insert({ tableName: storage.TABLE_THREADS, record: thread });
|
|
678
|
+
return thread;
|
|
679
|
+
} catch (error$1) {
|
|
680
|
+
throw new error.MastraError(
|
|
681
|
+
{
|
|
682
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "SAVE_THREAD", "FAILED"),
|
|
683
|
+
domain: error.ErrorDomain.STORAGE,
|
|
684
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
685
|
+
details: {
|
|
686
|
+
threadId: thread.id
|
|
1092
687
|
}
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
return data;
|
|
1097
|
-
} catch (error) {
|
|
1098
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1099
|
-
this.logger.error("Failed to parse text:", { message, text });
|
|
1100
|
-
return null;
|
|
688
|
+
},
|
|
689
|
+
error$1
|
|
690
|
+
);
|
|
1101
691
|
}
|
|
1102
692
|
}
|
|
1103
|
-
async
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
693
|
+
async updateThread({
|
|
694
|
+
id,
|
|
695
|
+
title,
|
|
696
|
+
metadata
|
|
697
|
+
}) {
|
|
698
|
+
try {
|
|
699
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
700
|
+
if (!thread) {
|
|
701
|
+
throw new Error(`Thread ${id} not found`);
|
|
702
|
+
}
|
|
703
|
+
const updatedThread = {
|
|
704
|
+
...thread,
|
|
1108
705
|
title,
|
|
1109
|
-
|
|
706
|
+
metadata: this.ensureMetadata({
|
|
707
|
+
...thread.metadata ?? {},
|
|
708
|
+
...metadata
|
|
709
|
+
}),
|
|
710
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1110
711
|
};
|
|
712
|
+
await this.#db.insert({ tableName: storage.TABLE_THREADS, record: updatedThread });
|
|
713
|
+
return updatedThread;
|
|
714
|
+
} catch (error$1) {
|
|
715
|
+
throw new error.MastraError(
|
|
716
|
+
{
|
|
717
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "UPDATE_THREAD", "FAILED"),
|
|
718
|
+
domain: error.ErrorDomain.STORAGE,
|
|
719
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
720
|
+
details: {
|
|
721
|
+
threadId: id,
|
|
722
|
+
title
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
error$1
|
|
726
|
+
);
|
|
1111
727
|
}
|
|
1112
|
-
return await this.client.kv.namespaces.create({
|
|
1113
|
-
account_id: this.accountId,
|
|
1114
|
-
title
|
|
1115
|
-
});
|
|
1116
728
|
}
|
|
1117
|
-
|
|
729
|
+
getMessageKey(threadId, messageId) {
|
|
1118
730
|
try {
|
|
1119
|
-
|
|
1120
|
-
return response.id;
|
|
731
|
+
return this.#db.getKey(storage.TABLE_MESSAGES, { threadId, id: messageId });
|
|
1121
732
|
} catch (error) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (namespace) return namespace.id;
|
|
1126
|
-
}
|
|
1127
|
-
this.logger.error("Error creating namespace:", error);
|
|
1128
|
-
throw new Error(`Failed to create namespace ${namespaceName}: ${error.message}`);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
async listNamespaces() {
|
|
1132
|
-
if (this.bindings) {
|
|
1133
|
-
return {
|
|
1134
|
-
result: Object.keys(this.bindings).map((name) => ({
|
|
1135
|
-
id: name,
|
|
1136
|
-
title: name,
|
|
1137
|
-
supports_url_encoding: true
|
|
1138
|
-
}))
|
|
1139
|
-
};
|
|
1140
|
-
}
|
|
1141
|
-
let allNamespaces = [];
|
|
1142
|
-
let currentPage = 1;
|
|
1143
|
-
const perPage = 50;
|
|
1144
|
-
let morePagesExist = true;
|
|
1145
|
-
while (morePagesExist) {
|
|
1146
|
-
const response = await this.client.kv.namespaces.list({
|
|
1147
|
-
account_id: this.accountId,
|
|
1148
|
-
page: currentPage,
|
|
1149
|
-
per_page: perPage
|
|
1150
|
-
});
|
|
1151
|
-
if (response.result) {
|
|
1152
|
-
allNamespaces = allNamespaces.concat(response.result);
|
|
1153
|
-
}
|
|
1154
|
-
morePagesExist = response.result ? response.result.length === perPage : false;
|
|
1155
|
-
if (morePagesExist) {
|
|
1156
|
-
currentPage++;
|
|
1157
|
-
}
|
|
733
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
734
|
+
this.logger?.error(`Error getting message key for thread ${threadId} and message ${messageId}:`, { message });
|
|
735
|
+
throw error;
|
|
1158
736
|
}
|
|
1159
|
-
return { result: allNamespaces };
|
|
1160
737
|
}
|
|
1161
|
-
|
|
738
|
+
getThreadMessagesKey(threadId) {
|
|
1162
739
|
try {
|
|
1163
|
-
|
|
1164
|
-
const namespace = response.result.find((ns) => ns.title === namespaceName);
|
|
1165
|
-
return namespace ? namespace.id : null;
|
|
740
|
+
return this.#db.getKey(storage.TABLE_MESSAGES, { threadId, id: "messages" });
|
|
1166
741
|
} catch (error) {
|
|
1167
|
-
|
|
1168
|
-
|
|
742
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
743
|
+
this.logger?.error(`Error getting thread messages key for thread ${threadId}:`, { message });
|
|
744
|
+
throw error;
|
|
1169
745
|
}
|
|
1170
746
|
}
|
|
1171
|
-
async
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
747
|
+
async deleteThread({ threadId }) {
|
|
748
|
+
try {
|
|
749
|
+
const thread = await this.getThreadById({ threadId });
|
|
750
|
+
if (!thread) {
|
|
751
|
+
throw new Error(`Thread ${threadId} not found`);
|
|
752
|
+
}
|
|
753
|
+
const messageKeys = await this.#db.listKV(storage.TABLE_MESSAGES);
|
|
754
|
+
const threadMessageKeys = messageKeys.filter((key) => key.name.includes(`${storage.TABLE_MESSAGES}:${threadId}:`));
|
|
755
|
+
await Promise.all([
|
|
756
|
+
// Delete message order
|
|
757
|
+
this.#db.deleteKV(storage.TABLE_MESSAGES, this.getThreadMessagesKey(threadId)),
|
|
758
|
+
// Delete all messages
|
|
759
|
+
...threadMessageKeys.map((key) => this.#db.deleteKV(storage.TABLE_MESSAGES, key.name)),
|
|
760
|
+
// Delete thread
|
|
761
|
+
this.#db.deleteKV(storage.TABLE_THREADS, this.#db.getKey(storage.TABLE_THREADS, { id: threadId }))
|
|
762
|
+
]);
|
|
763
|
+
} catch (error$1) {
|
|
764
|
+
throw new error.MastraError(
|
|
765
|
+
{
|
|
766
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "DELETE_THREAD", "FAILED"),
|
|
767
|
+
domain: error.ErrorDomain.STORAGE,
|
|
768
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
769
|
+
details: {
|
|
770
|
+
threadId
|
|
771
|
+
}
|
|
772
|
+
},
|
|
773
|
+
error$1
|
|
774
|
+
);
|
|
1175
775
|
}
|
|
1176
|
-
return namespaceId;
|
|
1177
776
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
777
|
+
/**
|
|
778
|
+
* Searches all threads in the KV store to find a message by its ID.
|
|
779
|
+
*
|
|
780
|
+
* **Performance Warning**: This method sequentially scans all threads to locate
|
|
781
|
+
* the message. For stores with many threads, this can result in significant
|
|
782
|
+
* latency and API calls. When possible, callers should provide the `threadId`
|
|
783
|
+
* directly to avoid this full scan.
|
|
784
|
+
*
|
|
785
|
+
* @param messageId - The globally unique message ID to search for
|
|
786
|
+
* @returns The message with its threadId if found, null otherwise
|
|
787
|
+
*/
|
|
788
|
+
async findMessageInAnyThread(messageId) {
|
|
1180
789
|
try {
|
|
1181
|
-
|
|
790
|
+
const prefix = this.#db.namespacePrefix ? `${this.#db.namespacePrefix}:` : "";
|
|
791
|
+
const threadKeys = await this.#db.listKV(storage.TABLE_THREADS, { prefix: `${prefix}${storage.TABLE_THREADS}` });
|
|
792
|
+
for (const { name: threadKey } of threadKeys) {
|
|
793
|
+
const threadId = threadKey.split(":").pop();
|
|
794
|
+
if (!threadId || threadId === "messages") continue;
|
|
795
|
+
const messageKey = this.getMessageKey(threadId, messageId);
|
|
796
|
+
const message = await this.#db.getKV(storage.TABLE_MESSAGES, messageKey);
|
|
797
|
+
if (message) {
|
|
798
|
+
return { ...message, threadId };
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
1182
802
|
} catch (error) {
|
|
1183
|
-
this.logger
|
|
1184
|
-
|
|
803
|
+
this.logger?.error(`Error finding message ${messageId} in any thread:`, error);
|
|
804
|
+
return null;
|
|
1185
805
|
}
|
|
1186
806
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
807
|
+
/**
|
|
808
|
+
* Queue for serializing sorted order updates.
|
|
809
|
+
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
810
|
+
*/
|
|
811
|
+
updateQueue = /* @__PURE__ */ new Map();
|
|
812
|
+
async updateSorting(threadMessages) {
|
|
813
|
+
return threadMessages.map((msg) => ({
|
|
814
|
+
message: msg,
|
|
815
|
+
// Use _index if available, otherwise timestamp, matching Upstash
|
|
816
|
+
score: msg._index !== void 0 ? msg._index : msg.createdAt.getTime()
|
|
817
|
+
})).sort((a, b) => a.score - b.score).map((item) => ({
|
|
818
|
+
id: item.message.id,
|
|
819
|
+
score: item.score
|
|
820
|
+
}));
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Updates the sorted order for a given key. This operation is eventually consistent.
|
|
824
|
+
* Note: Operations on the same orderKey are serialized using a queue to prevent
|
|
825
|
+
* concurrent updates from conflicting with each other.
|
|
826
|
+
*/
|
|
827
|
+
async updateSortedMessages(orderKey, newEntries) {
|
|
828
|
+
const currentPromise = this.updateQueue.get(orderKey) || Promise.resolve();
|
|
829
|
+
const nextPromise = currentPromise.then(async () => {
|
|
830
|
+
try {
|
|
831
|
+
const currentOrder = await this.getSortedMessages(orderKey);
|
|
832
|
+
const orderMap = new Map(currentOrder.map((entry) => [entry.id, entry]));
|
|
833
|
+
for (const entry of newEntries) {
|
|
834
|
+
orderMap.set(entry.id, entry);
|
|
835
|
+
}
|
|
836
|
+
const updatedOrder = Array.from(orderMap.values()).sort((a, b) => a.score - b.score);
|
|
837
|
+
await this.#db.putKV({
|
|
838
|
+
tableName: storage.TABLE_MESSAGES,
|
|
839
|
+
key: orderKey,
|
|
840
|
+
value: JSON.stringify(updatedOrder)
|
|
1198
841
|
});
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
842
|
+
} catch (error) {
|
|
843
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
844
|
+
this.logger?.error(`Error updating sorted order for key ${orderKey}:`, { message });
|
|
845
|
+
throw error;
|
|
846
|
+
} finally {
|
|
847
|
+
if (this.updateQueue.get(orderKey) === nextPromise) {
|
|
848
|
+
this.updateQueue.delete(orderKey);
|
|
849
|
+
}
|
|
1204
850
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
}
|
|
851
|
+
});
|
|
852
|
+
this.updateQueue.set(orderKey, nextPromise);
|
|
853
|
+
return nextPromise;
|
|
1209
854
|
}
|
|
1210
|
-
async
|
|
855
|
+
async getSortedMessages(orderKey) {
|
|
856
|
+
const raw = await this.#db.getKV(storage.TABLE_MESSAGES, orderKey);
|
|
857
|
+
if (!raw) return [];
|
|
1211
858
|
try {
|
|
1212
|
-
const
|
|
1213
|
-
return
|
|
1214
|
-
} catch (
|
|
1215
|
-
this.logger
|
|
1216
|
-
|
|
859
|
+
const arr = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw));
|
|
860
|
+
return Array.isArray(arr) ? arr : [];
|
|
861
|
+
} catch (e) {
|
|
862
|
+
this.logger?.error(`Error parsing order data for key ${orderKey}:`, { e });
|
|
863
|
+
return [];
|
|
1217
864
|
}
|
|
1218
865
|
}
|
|
1219
|
-
async
|
|
866
|
+
async migrateMessage(messageId, fromThreadId, toThreadId) {
|
|
1220
867
|
try {
|
|
1221
|
-
const
|
|
1222
|
-
|
|
868
|
+
const oldMessageKey = this.getMessageKey(fromThreadId, messageId);
|
|
869
|
+
const message = await this.#db.getKV(storage.TABLE_MESSAGES, oldMessageKey);
|
|
870
|
+
if (!message) return;
|
|
871
|
+
const updatedMessage = {
|
|
872
|
+
...message,
|
|
873
|
+
threadId: toThreadId
|
|
874
|
+
};
|
|
875
|
+
const newMessageKey = this.getMessageKey(toThreadId, messageId);
|
|
876
|
+
await this.#db.putKV({ tableName: storage.TABLE_MESSAGES, key: newMessageKey, value: updatedMessage });
|
|
877
|
+
const oldOrderKey = this.getThreadMessagesKey(fromThreadId);
|
|
878
|
+
const oldEntries = await this.getSortedMessages(oldOrderKey);
|
|
879
|
+
const filteredEntries = oldEntries.filter((entry) => entry.id !== messageId);
|
|
880
|
+
await this.updateSortedMessages(oldOrderKey, filteredEntries);
|
|
881
|
+
const newOrderKey = this.getThreadMessagesKey(toThreadId);
|
|
882
|
+
const newEntries = await this.getSortedMessages(newOrderKey);
|
|
883
|
+
const newEntry = { id: messageId, score: Date.now() };
|
|
884
|
+
newEntries.push(newEntry);
|
|
885
|
+
await this.updateSortedMessages(newOrderKey, newEntries);
|
|
886
|
+
await this.#db.deleteKV(storage.TABLE_MESSAGES, oldMessageKey);
|
|
1223
887
|
} catch (error) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
return null;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
validateColumnValue(value, column) {
|
|
1230
|
-
if (value === void 0 || value === null) {
|
|
1231
|
-
return column.nullable ?? false;
|
|
1232
|
-
}
|
|
1233
|
-
switch (column.type) {
|
|
1234
|
-
case "text":
|
|
1235
|
-
case "uuid":
|
|
1236
|
-
return typeof value === "string";
|
|
1237
|
-
case "integer":
|
|
1238
|
-
case "bigint":
|
|
1239
|
-
return typeof value === "number";
|
|
1240
|
-
case "timestamp":
|
|
1241
|
-
return value instanceof Date || typeof value === "string" && !isNaN(Date.parse(value));
|
|
1242
|
-
case "jsonb":
|
|
1243
|
-
if (typeof value !== "object") return false;
|
|
1244
|
-
try {
|
|
1245
|
-
JSON.stringify(value);
|
|
1246
|
-
return true;
|
|
1247
|
-
} catch {
|
|
1248
|
-
return false;
|
|
1249
|
-
}
|
|
1250
|
-
default:
|
|
1251
|
-
return false;
|
|
888
|
+
this.logger?.error(`Error migrating message ${messageId} from ${fromThreadId} to ${toThreadId}:`, error);
|
|
889
|
+
throw error;
|
|
1252
890
|
}
|
|
1253
891
|
}
|
|
1254
|
-
async
|
|
892
|
+
async saveMessages(args) {
|
|
893
|
+
const { messages } = args;
|
|
894
|
+
if (!Array.isArray(messages) || messages.length === 0) return { messages: [] };
|
|
1255
895
|
try {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
896
|
+
const validatedMessages = messages.map((message, index) => {
|
|
897
|
+
const errors = [];
|
|
898
|
+
if (!message.id) errors.push("id is required");
|
|
899
|
+
if (!message.threadId) errors.push("threadId is required");
|
|
900
|
+
if (!message.content) errors.push("content is required");
|
|
901
|
+
if (!message.role) errors.push("role is required");
|
|
902
|
+
if (!message.createdAt) errors.push("createdAt is required");
|
|
903
|
+
if (message.resourceId === null || message.resourceId === void 0) errors.push("resourceId is required");
|
|
904
|
+
if (errors.length > 0) {
|
|
905
|
+
throw new Error(`Invalid message at index ${index}: ${errors.join(", ")}`);
|
|
1263
906
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
907
|
+
return {
|
|
908
|
+
...message,
|
|
909
|
+
createdAt: storage.ensureDate(message.createdAt),
|
|
910
|
+
type: message.type || "v2",
|
|
911
|
+
_index: index
|
|
912
|
+
};
|
|
913
|
+
}).filter((m) => !!m);
|
|
914
|
+
const messageMigrationTasks = [];
|
|
915
|
+
for (const message of validatedMessages) {
|
|
916
|
+
const existingMessage = await this.findMessageInAnyThread(message.id);
|
|
917
|
+
this.logger?.debug(
|
|
918
|
+
`Checking message ${message.id}: existing=${existingMessage?.threadId}, new=${message.threadId}`
|
|
919
|
+
);
|
|
920
|
+
if (existingMessage && existingMessage.threadId && existingMessage.threadId !== message.threadId) {
|
|
921
|
+
this.logger?.debug(`Migrating message ${message.id} from ${existingMessage.threadId} to ${message.threadId}`);
|
|
922
|
+
messageMigrationTasks.push(this.migrateMessage(message.id, existingMessage.threadId, message.threadId));
|
|
1267
923
|
}
|
|
1268
924
|
}
|
|
1269
|
-
|
|
1270
|
-
const
|
|
1271
|
-
|
|
1272
|
-
|
|
925
|
+
await Promise.all(messageMigrationTasks);
|
|
926
|
+
const messagesByThread = validatedMessages.reduce((acc, message) => {
|
|
927
|
+
if (message.threadId && !acc.has(message.threadId)) {
|
|
928
|
+
acc.set(message.threadId, []);
|
|
929
|
+
}
|
|
930
|
+
if (message.threadId) {
|
|
931
|
+
acc.get(message.threadId).push(message);
|
|
932
|
+
}
|
|
933
|
+
return acc;
|
|
934
|
+
}, /* @__PURE__ */ new Map());
|
|
935
|
+
await Promise.all(
|
|
936
|
+
Array.from(messagesByThread.entries()).map(async ([threadId, threadMessages]) => {
|
|
937
|
+
try {
|
|
938
|
+
const thread = await this.getThreadById({ threadId });
|
|
939
|
+
if (!thread) {
|
|
940
|
+
throw new Error(`Thread ${threadId} not found`);
|
|
941
|
+
}
|
|
942
|
+
await Promise.all(
|
|
943
|
+
threadMessages.map(async (message) => {
|
|
944
|
+
const key = this.getMessageKey(threadId, message.id);
|
|
945
|
+
const { _index, ...cleanMessage } = message;
|
|
946
|
+
const serializedMessage = {
|
|
947
|
+
...cleanMessage,
|
|
948
|
+
createdAt: storage.serializeDate(cleanMessage.createdAt)
|
|
949
|
+
};
|
|
950
|
+
this.logger?.debug(`Saving message ${message.id}`, {
|
|
951
|
+
contentSummary: this.summarizeMessageContent(serializedMessage.content)
|
|
952
|
+
});
|
|
953
|
+
await this.#db.putKV({ tableName: storage.TABLE_MESSAGES, key, value: serializedMessage });
|
|
954
|
+
})
|
|
955
|
+
);
|
|
956
|
+
const orderKey = this.getThreadMessagesKey(threadId);
|
|
957
|
+
const entries = await this.updateSorting(threadMessages);
|
|
958
|
+
await this.updateSortedMessages(orderKey, entries);
|
|
959
|
+
const updatedThread = {
|
|
960
|
+
...thread,
|
|
961
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
962
|
+
};
|
|
963
|
+
await this.#db.putKV({
|
|
964
|
+
tableName: storage.TABLE_THREADS,
|
|
965
|
+
key: this.#db.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
966
|
+
value: updatedThread
|
|
967
|
+
});
|
|
968
|
+
} catch (error$1) {
|
|
969
|
+
throw new error.MastraError(
|
|
970
|
+
{
|
|
971
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "SAVE_MESSAGES", "FAILED"),
|
|
972
|
+
domain: error.ErrorDomain.STORAGE,
|
|
973
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
974
|
+
details: {
|
|
975
|
+
threadId
|
|
976
|
+
}
|
|
977
|
+
},
|
|
978
|
+
error$1
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
})
|
|
982
|
+
);
|
|
983
|
+
const prepared = validatedMessages.map(
|
|
984
|
+
({ _index, ...message }) => ({ ...message, type: message.type !== "v2" ? message.type : void 0 })
|
|
985
|
+
);
|
|
986
|
+
const list = new agent.MessageList().add(prepared, "memory");
|
|
987
|
+
return { messages: list.get.all.db() };
|
|
988
|
+
} catch (error$1) {
|
|
989
|
+
throw new error.MastraError(
|
|
990
|
+
{
|
|
991
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "SAVE_MESSAGES", "FAILED"),
|
|
992
|
+
domain: error.ErrorDomain.STORAGE,
|
|
993
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
994
|
+
},
|
|
995
|
+
error$1
|
|
996
|
+
);
|
|
1273
997
|
}
|
|
1274
998
|
}
|
|
1275
|
-
async
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
999
|
+
async getRank(orderKey, id) {
|
|
1000
|
+
const order = await this.getSortedMessages(orderKey);
|
|
1001
|
+
const index = order.findIndex((item) => item.id === id);
|
|
1002
|
+
return index >= 0 ? index : null;
|
|
1003
|
+
}
|
|
1004
|
+
async getRange(orderKey, start, end) {
|
|
1005
|
+
const order = await this.getSortedMessages(orderKey);
|
|
1006
|
+
const actualStart = start < 0 ? Math.max(0, order.length + start) : start;
|
|
1007
|
+
const actualEnd = end < 0 ? order.length + end : Math.min(end, order.length - 1);
|
|
1008
|
+
const sliced = order.slice(actualStart, actualEnd + 1);
|
|
1009
|
+
return sliced.map((item) => item.id);
|
|
1010
|
+
}
|
|
1011
|
+
async getLastN(orderKey, n) {
|
|
1012
|
+
return this.getRange(orderKey, -n, -1);
|
|
1013
|
+
}
|
|
1014
|
+
async getFullOrder(orderKey) {
|
|
1015
|
+
return this.getRange(orderKey, 0, -1);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Retrieves messages specified in the include array along with their surrounding context.
|
|
1019
|
+
*
|
|
1020
|
+
* **Performance Note**: When `threadId` is not provided in an include entry, this method
|
|
1021
|
+
* must call `findMessageInAnyThread` which sequentially scans all threads in the KV store.
|
|
1022
|
+
* For optimal performance, callers should provide `threadId` in include entries when known.
|
|
1023
|
+
*
|
|
1024
|
+
* @param include - Array of message IDs to include, optionally with context windows
|
|
1025
|
+
* @param messageIds - Set to accumulate the message IDs that should be fetched
|
|
1026
|
+
*/
|
|
1027
|
+
async getIncludedMessagesWithContext(include, messageIds) {
|
|
1028
|
+
await Promise.all(
|
|
1029
|
+
include.map(async (item) => {
|
|
1030
|
+
let targetThreadId = item.threadId;
|
|
1031
|
+
if (!targetThreadId) {
|
|
1032
|
+
const foundMessage = await this.findMessageInAnyThread(item.id);
|
|
1033
|
+
if (!foundMessage) return;
|
|
1034
|
+
targetThreadId = foundMessage.threadId;
|
|
1035
|
+
}
|
|
1036
|
+
if (!targetThreadId) return;
|
|
1037
|
+
const threadMessagesKey = this.getThreadMessagesKey(targetThreadId);
|
|
1038
|
+
messageIds.add(item.id);
|
|
1039
|
+
if (!item.withPreviousMessages && !item.withNextMessages) return;
|
|
1040
|
+
const rank = await this.getRank(threadMessagesKey, item.id);
|
|
1041
|
+
if (rank === null) return;
|
|
1042
|
+
if (item.withPreviousMessages) {
|
|
1043
|
+
const prevIds = await this.getRange(
|
|
1044
|
+
threadMessagesKey,
|
|
1045
|
+
Math.max(0, rank - item.withPreviousMessages),
|
|
1046
|
+
rank - 1
|
|
1047
|
+
);
|
|
1048
|
+
prevIds.forEach((id) => messageIds.add(id));
|
|
1049
|
+
}
|
|
1050
|
+
if (item.withNextMessages) {
|
|
1051
|
+
const nextIds = await this.getRange(threadMessagesKey, rank + 1, rank + item.withNextMessages);
|
|
1052
|
+
nextIds.forEach((id) => messageIds.add(id));
|
|
1053
|
+
}
|
|
1054
|
+
})
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
async getRecentMessages(threadId, limit, messageIds) {
|
|
1058
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
1059
|
+
if (limit <= 0) return;
|
|
1060
|
+
try {
|
|
1061
|
+
const threadMessagesKey = this.getThreadMessagesKey(threadId);
|
|
1062
|
+
const latestIds = await this.getLastN(threadMessagesKey, limit);
|
|
1063
|
+
latestIds.forEach((id) => messageIds.add(id));
|
|
1064
|
+
} catch {
|
|
1065
|
+
this.logger?.debug(`No message order found for thread ${threadId}, skipping latest messages`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Fetches and parses messages from one or more threads.
|
|
1070
|
+
*
|
|
1071
|
+
* **Performance Note**: When neither `include` entries with `threadId` nor `targetThreadId`
|
|
1072
|
+
* are provided, this method falls back to `findMessageInAnyThread` which scans all threads.
|
|
1073
|
+
* For optimal performance, provide `threadId` in include entries or specify `targetThreadId`.
|
|
1074
|
+
*/
|
|
1075
|
+
async fetchAndParseMessagesFromMultipleThreads(messageIds, include, targetThreadId) {
|
|
1076
|
+
const messageIdToThreadId = /* @__PURE__ */ new Map();
|
|
1077
|
+
if (include) {
|
|
1078
|
+
for (const item of include) {
|
|
1079
|
+
if (item.threadId) {
|
|
1080
|
+
messageIdToThreadId.set(item.id, item.threadId);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
const messages = await Promise.all(
|
|
1085
|
+
messageIds.map(async (id) => {
|
|
1086
|
+
try {
|
|
1087
|
+
let threadId = messageIdToThreadId.get(id);
|
|
1088
|
+
if (!threadId) {
|
|
1089
|
+
if (targetThreadId) {
|
|
1090
|
+
threadId = targetThreadId;
|
|
1091
|
+
} else {
|
|
1092
|
+
const foundMessage = await this.findMessageInAnyThread(id);
|
|
1093
|
+
if (foundMessage) {
|
|
1094
|
+
threadId = foundMessage.threadId;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1305
1097
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1098
|
+
if (!threadId) return null;
|
|
1099
|
+
const key = this.getMessageKey(threadId, id);
|
|
1100
|
+
const data = await this.#db.getKV(storage.TABLE_MESSAGES, key);
|
|
1101
|
+
if (!data) return null;
|
|
1102
|
+
const parsed = typeof data === "string" ? JSON.parse(data) : data;
|
|
1103
|
+
this.logger?.debug(`Retrieved message ${id} from thread ${threadId}`, {
|
|
1104
|
+
contentSummary: this.summarizeMessageContent(parsed.content)
|
|
1105
|
+
});
|
|
1106
|
+
return parsed;
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1109
|
+
this.logger?.error(`Error retrieving message ${id}:`, { message });
|
|
1110
|
+
return null;
|
|
1111
|
+
}
|
|
1112
|
+
})
|
|
1113
|
+
);
|
|
1114
|
+
return messages.filter((msg) => msg !== null);
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Retrieves messages by their IDs.
|
|
1118
|
+
*
|
|
1119
|
+
* **Performance Warning**: This method calls `findMessageInAnyThread` for each message ID,
|
|
1120
|
+
* which scans all threads in the KV store. For large numbers of messages or threads,
|
|
1121
|
+
* this can result in significant latency. Consider using `listMessages` with specific
|
|
1122
|
+
* thread IDs when the thread context is known.
|
|
1123
|
+
*/
|
|
1124
|
+
async listMessagesById({ messageIds }) {
|
|
1125
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1126
|
+
try {
|
|
1127
|
+
const messages = (await Promise.all(messageIds.map((id) => this.findMessageInAnyThread(id)))).filter(
|
|
1128
|
+
(result) => !!result
|
|
1129
|
+
);
|
|
1130
|
+
const prepared = messages.map(({ _index, ...message }) => ({
|
|
1131
|
+
...message,
|
|
1132
|
+
...message.type !== `v2` && { type: message.type },
|
|
1133
|
+
createdAt: storage.ensureDate(message.createdAt)
|
|
1134
|
+
}));
|
|
1135
|
+
const list = new agent.MessageList().add(prepared, "memory");
|
|
1136
|
+
return { messages: list.get.all.db() };
|
|
1137
|
+
} catch (error$1) {
|
|
1138
|
+
const mastraError = new error.MastraError(
|
|
1139
|
+
{
|
|
1140
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1141
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1142
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1143
|
+
text: `Error retrieving messages by ID`,
|
|
1144
|
+
details: {
|
|
1145
|
+
messageIds: JSON.stringify(messageIds)
|
|
1310
1146
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1147
|
+
},
|
|
1148
|
+
error$1
|
|
1149
|
+
);
|
|
1150
|
+
this.logger?.trackException(mastraError);
|
|
1151
|
+
this.logger?.error(mastraError.toString());
|
|
1152
|
+
return { messages: [] };
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
async listMessages(args) {
|
|
1156
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1157
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
1158
|
+
const isValidThreadId = (id) => typeof id === "string" && id.trim().length > 0;
|
|
1159
|
+
if (threadIds.length === 0 || threadIds.some((id) => !isValidThreadId(id))) {
|
|
1160
|
+
throw new error.MastraError(
|
|
1161
|
+
{
|
|
1162
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1163
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1164
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1165
|
+
details: { threadId: Array.isArray(threadId) ? JSON.stringify(threadId) : String(threadId) }
|
|
1166
|
+
},
|
|
1167
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
1171
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1172
|
+
try {
|
|
1173
|
+
if (page < 0) {
|
|
1174
|
+
throw new error.MastraError(
|
|
1175
|
+
{
|
|
1176
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1177
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1178
|
+
category: error.ErrorCategory.USER,
|
|
1179
|
+
details: { page }
|
|
1180
|
+
},
|
|
1181
|
+
new Error("page must be >= 0")
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1185
|
+
const threadMessageIds = /* @__PURE__ */ new Set();
|
|
1186
|
+
for (const tid of threadIds) {
|
|
1187
|
+
try {
|
|
1188
|
+
const threadMessagesKey = this.getThreadMessagesKey(tid);
|
|
1189
|
+
const allIds = await this.getFullOrder(threadMessagesKey);
|
|
1190
|
+
allIds.forEach((id) => threadMessageIds.add(id));
|
|
1191
|
+
} catch {
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
const threadMessages = await this.fetchAndParseMessagesFromMultipleThreads(
|
|
1195
|
+
Array.from(threadMessageIds),
|
|
1196
|
+
void 0,
|
|
1197
|
+
threadIds.length === 1 ? threadIds[0] : void 0
|
|
1198
|
+
);
|
|
1199
|
+
let filteredThreadMessages = threadMessages;
|
|
1200
|
+
if (resourceId) {
|
|
1201
|
+
filteredThreadMessages = filteredThreadMessages.filter((msg) => msg.resourceId === resourceId);
|
|
1202
|
+
}
|
|
1203
|
+
const dateRange = filter?.dateRange;
|
|
1204
|
+
if (dateRange) {
|
|
1205
|
+
filteredThreadMessages = filteredThreadMessages.filter((msg) => {
|
|
1206
|
+
const messageDate = new Date(msg.createdAt);
|
|
1207
|
+
if (dateRange.start && messageDate < new Date(dateRange.start)) return false;
|
|
1208
|
+
if (dateRange.end && messageDate > new Date(dateRange.end)) return false;
|
|
1209
|
+
return true;
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
const total = filteredThreadMessages.length;
|
|
1213
|
+
if (perPage === 0 && (!include || include.length === 0)) {
|
|
1214
|
+
return {
|
|
1215
|
+
messages: [],
|
|
1216
|
+
total,
|
|
1217
|
+
page,
|
|
1218
|
+
perPage: perPageForResponse,
|
|
1219
|
+
hasMore: offset < total
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
filteredThreadMessages.sort((a, b) => {
|
|
1223
|
+
const timeA = new Date(a.createdAt).getTime();
|
|
1224
|
+
const timeB = new Date(b.createdAt).getTime();
|
|
1225
|
+
const timeDiff = direction === "ASC" ? timeA - timeB : timeB - timeA;
|
|
1226
|
+
if (timeDiff === 0) {
|
|
1227
|
+
return a.id.localeCompare(b.id);
|
|
1228
|
+
}
|
|
1229
|
+
return timeDiff;
|
|
1230
|
+
});
|
|
1231
|
+
let paginatedMessages;
|
|
1232
|
+
if (perPage === 0) {
|
|
1233
|
+
paginatedMessages = [];
|
|
1234
|
+
} else if (perPage === Number.MAX_SAFE_INTEGER) {
|
|
1235
|
+
paginatedMessages = filteredThreadMessages;
|
|
1236
|
+
} else {
|
|
1237
|
+
paginatedMessages = filteredThreadMessages.slice(offset, offset + perPage);
|
|
1238
|
+
}
|
|
1239
|
+
let includedMessages = [];
|
|
1240
|
+
if (include && include.length > 0) {
|
|
1241
|
+
const includedMessageIds = /* @__PURE__ */ new Set();
|
|
1242
|
+
await this.getIncludedMessagesWithContext(include, includedMessageIds);
|
|
1243
|
+
const paginatedIds = new Set(paginatedMessages.map((m) => m.id));
|
|
1244
|
+
const idsToFetch = Array.from(includedMessageIds).filter((id) => !paginatedIds.has(id));
|
|
1245
|
+
if (idsToFetch.length > 0) {
|
|
1246
|
+
includedMessages = await this.fetchAndParseMessagesFromMultipleThreads(idsToFetch, include, void 0);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1250
|
+
const allMessages = [];
|
|
1251
|
+
for (const msg of paginatedMessages) {
|
|
1252
|
+
if (!seenIds.has(msg.id)) {
|
|
1253
|
+
allMessages.push(msg);
|
|
1254
|
+
seenIds.add(msg.id);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
for (const msg of includedMessages) {
|
|
1258
|
+
if (!seenIds.has(msg.id)) {
|
|
1259
|
+
allMessages.push(msg);
|
|
1260
|
+
seenIds.add(msg.id);
|
|
1261
|
+
}
|
|
1314
1262
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1263
|
+
allMessages.sort((a, b) => {
|
|
1264
|
+
const timeA = new Date(a.createdAt).getTime();
|
|
1265
|
+
const timeB = new Date(b.createdAt).getTime();
|
|
1266
|
+
const timeDiff = direction === "ASC" ? timeA - timeB : timeB - timeA;
|
|
1267
|
+
if (timeDiff === 0) {
|
|
1268
|
+
return a.id.localeCompare(b.id);
|
|
1269
|
+
}
|
|
1270
|
+
return timeDiff;
|
|
1271
|
+
});
|
|
1272
|
+
let filteredMessages = allMessages;
|
|
1273
|
+
const paginatedCount = paginatedMessages.length;
|
|
1274
|
+
if (total === 0 && filteredMessages.length === 0 && (!include || include.length === 0)) {
|
|
1275
|
+
return {
|
|
1276
|
+
messages: [],
|
|
1277
|
+
total: 0,
|
|
1278
|
+
page,
|
|
1279
|
+
perPage: perPageForResponse,
|
|
1280
|
+
hasMore: false
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
const prepared = filteredMessages.map(({ _index, ...message }) => ({
|
|
1284
|
+
...message,
|
|
1285
|
+
type: message.type !== "v2" ? message.type : void 0,
|
|
1286
|
+
createdAt: storage.ensureDate(message.createdAt)
|
|
1287
|
+
}));
|
|
1288
|
+
const primaryThreadId = Array.isArray(threadId) ? threadId[0] : threadId;
|
|
1289
|
+
const list = new agent.MessageList({ threadId: primaryThreadId, resourceId }).add(
|
|
1290
|
+
prepared,
|
|
1291
|
+
"memory"
|
|
1338
1292
|
);
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1293
|
+
let finalMessages = list.get.all.db();
|
|
1294
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
1295
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
1296
|
+
const aVal = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
1297
|
+
const bVal = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
1298
|
+
if (aVal == null && bVal == null) return a.id.localeCompare(b.id);
|
|
1299
|
+
if (aVal == null) return 1;
|
|
1300
|
+
if (bVal == null) return -1;
|
|
1301
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
1302
|
+
const cmp2 = direction === "ASC" ? aVal - bVal : bVal - aVal;
|
|
1303
|
+
return cmp2 !== 0 ? cmp2 : a.id.localeCompare(b.id);
|
|
1304
|
+
}
|
|
1305
|
+
const cmp = direction === "ASC" ? String(aVal).localeCompare(String(bVal)) : String(bVal).localeCompare(String(aVal));
|
|
1306
|
+
return cmp !== 0 ? cmp : a.id.localeCompare(b.id);
|
|
1307
|
+
});
|
|
1308
|
+
const threadIdSet = new Set(threadIds);
|
|
1309
|
+
const returnedThreadMessageIds = new Set(
|
|
1310
|
+
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
1311
|
+
);
|
|
1312
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
1313
|
+
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + paginatedCount < total;
|
|
1314
|
+
return {
|
|
1315
|
+
messages: finalMessages,
|
|
1316
|
+
total,
|
|
1317
|
+
page,
|
|
1318
|
+
perPage: perPageForResponse,
|
|
1319
|
+
hasMore
|
|
1320
|
+
};
|
|
1347
1321
|
} catch (error$1) {
|
|
1348
1322
|
const mastraError = new error.MastraError(
|
|
1349
1323
|
{
|
|
1350
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
1324
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "LIST_MESSAGES", "FAILED"),
|
|
1351
1325
|
domain: error.ErrorDomain.STORAGE,
|
|
1352
1326
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1327
|
+
text: `Failed to list messages for thread ${Array.isArray(threadId) ? threadId.join(",") : threadId}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`,
|
|
1353
1328
|
details: {
|
|
1354
|
-
|
|
1329
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1330
|
+
resourceId: resourceId ?? ""
|
|
1355
1331
|
}
|
|
1356
1332
|
},
|
|
1357
1333
|
error$1
|
|
1358
1334
|
);
|
|
1359
|
-
this.logger?.
|
|
1360
|
-
this.logger?.
|
|
1361
|
-
return
|
|
1335
|
+
this.logger?.error?.(mastraError.toString());
|
|
1336
|
+
this.logger?.trackException?.(mastraError);
|
|
1337
|
+
return {
|
|
1338
|
+
messages: [],
|
|
1339
|
+
total: 0,
|
|
1340
|
+
page,
|
|
1341
|
+
perPage: perPageForResponse,
|
|
1342
|
+
hasMore: false
|
|
1343
|
+
};
|
|
1362
1344
|
}
|
|
1363
1345
|
}
|
|
1364
|
-
async
|
|
1365
|
-
if (!input.records || input.records.length === 0) return;
|
|
1346
|
+
async updateMessages(args) {
|
|
1366
1347
|
try {
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1348
|
+
const { messages } = args;
|
|
1349
|
+
const updatedMessages = [];
|
|
1350
|
+
for (const messageUpdate of messages) {
|
|
1351
|
+
const { id, content, ...otherFields } = messageUpdate;
|
|
1352
|
+
const prefix = this.#db.namespacePrefix ? `${this.#db.namespacePrefix}:` : "";
|
|
1353
|
+
const keyObjs = await this.#db.listKV(storage.TABLE_MESSAGES, { prefix: `${prefix}${storage.TABLE_MESSAGES}` });
|
|
1354
|
+
let existingMessage = null;
|
|
1355
|
+
let messageKey = "";
|
|
1356
|
+
for (const { name: key } of keyObjs) {
|
|
1357
|
+
const data = await this.#db.getKV(storage.TABLE_MESSAGES, key);
|
|
1358
|
+
if (data && data.id === id) {
|
|
1359
|
+
existingMessage = data;
|
|
1360
|
+
messageKey = key;
|
|
1361
|
+
break;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
if (!existingMessage) {
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
const updatedMessage = {
|
|
1368
|
+
...existingMessage,
|
|
1369
|
+
...otherFields,
|
|
1370
|
+
id
|
|
1371
|
+
};
|
|
1372
|
+
if (content) {
|
|
1373
|
+
if (content.metadata !== void 0) {
|
|
1374
|
+
updatedMessage.content = {
|
|
1375
|
+
...updatedMessage.content,
|
|
1376
|
+
metadata: {
|
|
1377
|
+
...updatedMessage.content?.metadata,
|
|
1378
|
+
...content.metadata
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
if (content.content !== void 0) {
|
|
1383
|
+
updatedMessage.content = {
|
|
1384
|
+
...updatedMessage.content,
|
|
1385
|
+
content: content.content
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
1390
|
+
await this.#db.deleteKV(storage.TABLE_MESSAGES, messageKey);
|
|
1391
|
+
updatedMessage.threadId = messageUpdate.threadId;
|
|
1392
|
+
const newMessageKey = this.getMessageKey(messageUpdate.threadId, id);
|
|
1393
|
+
await this.#db.putKV({
|
|
1394
|
+
tableName: storage.TABLE_MESSAGES,
|
|
1395
|
+
key: newMessageKey,
|
|
1396
|
+
value: updatedMessage
|
|
1397
|
+
});
|
|
1398
|
+
if (existingMessage.threadId) {
|
|
1399
|
+
const sourceOrderKey = this.getThreadMessagesKey(existingMessage.threadId);
|
|
1400
|
+
const sourceEntries = await this.getSortedMessages(sourceOrderKey);
|
|
1401
|
+
const filteredEntries = sourceEntries.filter((entry) => entry.id !== id);
|
|
1402
|
+
await this.updateSortedMessages(sourceOrderKey, filteredEntries);
|
|
1403
|
+
}
|
|
1404
|
+
const destOrderKey = this.getThreadMessagesKey(messageUpdate.threadId);
|
|
1405
|
+
const destEntries = await this.getSortedMessages(destOrderKey);
|
|
1406
|
+
const newEntry = { id, score: Date.now() };
|
|
1407
|
+
destEntries.push(newEntry);
|
|
1408
|
+
await this.updateSortedMessages(destOrderKey, destEntries);
|
|
1409
|
+
} else {
|
|
1410
|
+
await this.#db.putKV({
|
|
1411
|
+
tableName: storage.TABLE_MESSAGES,
|
|
1412
|
+
key: messageKey,
|
|
1413
|
+
value: updatedMessage
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
const threadsToUpdate = /* @__PURE__ */ new Set();
|
|
1417
|
+
if (updatedMessage.threadId) {
|
|
1418
|
+
threadsToUpdate.add(updatedMessage.threadId);
|
|
1419
|
+
}
|
|
1420
|
+
if ("threadId" in messageUpdate && messageUpdate.threadId && messageUpdate.threadId !== existingMessage.threadId) {
|
|
1421
|
+
if (existingMessage.threadId) {
|
|
1422
|
+
threadsToUpdate.add(existingMessage.threadId);
|
|
1423
|
+
}
|
|
1424
|
+
threadsToUpdate.add(messageUpdate.threadId);
|
|
1425
|
+
}
|
|
1426
|
+
for (const threadId of threadsToUpdate) {
|
|
1427
|
+
const thread = await this.getThreadById({ threadId });
|
|
1428
|
+
if (thread) {
|
|
1429
|
+
const updatedThread = {
|
|
1430
|
+
...thread,
|
|
1431
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1432
|
+
};
|
|
1433
|
+
await this.#db.putKV({
|
|
1434
|
+
tableName: storage.TABLE_THREADS,
|
|
1435
|
+
key: this.#db.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
1436
|
+
value: updatedThread
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
updatedMessages.push(updatedMessage);
|
|
1441
|
+
}
|
|
1442
|
+
return updatedMessages;
|
|
1373
1443
|
} catch (error$1) {
|
|
1374
1444
|
throw new error.MastraError(
|
|
1375
1445
|
{
|
|
1376
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
1446
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "UPDATE_MESSAGES", "FAILED"),
|
|
1377
1447
|
domain: error.ErrorDomain.STORAGE,
|
|
1378
1448
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1379
|
-
text:
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
},
|
|
1384
|
-
error$1
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* Helper to safely serialize data for KV storage
|
|
1390
|
-
*/
|
|
1391
|
-
safeSerialize(data) {
|
|
1392
|
-
return typeof data === "string" ? data : JSON.stringify(data);
|
|
1393
|
-
}
|
|
1394
|
-
async putNamespaceValue({
|
|
1395
|
-
tableName,
|
|
1396
|
-
key,
|
|
1397
|
-
value,
|
|
1398
|
-
metadata
|
|
1399
|
-
}) {
|
|
1400
|
-
try {
|
|
1401
|
-
const serializedValue = this.safeSerialize(value);
|
|
1402
|
-
const serializedMetadata = metadata ? this.safeSerialize(metadata) : "";
|
|
1403
|
-
if (this.bindings) {
|
|
1404
|
-
const binding = this.getBinding(tableName);
|
|
1405
|
-
await binding.put(key, serializedValue, { metadata: serializedMetadata });
|
|
1406
|
-
} else {
|
|
1407
|
-
const namespaceId = await this.getNamespaceId(tableName);
|
|
1408
|
-
await this.client.kv.namespaces.values.update(namespaceId, key, {
|
|
1409
|
-
account_id: this.accountId,
|
|
1410
|
-
value: serializedValue,
|
|
1411
|
-
metadata: serializedMetadata
|
|
1412
|
-
});
|
|
1413
|
-
}
|
|
1414
|
-
} catch (error) {
|
|
1415
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1416
|
-
this.logger.error(`Failed to put value for ${tableName} ${key}:`, { message });
|
|
1417
|
-
throw error;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
async putKV({
|
|
1421
|
-
tableName,
|
|
1422
|
-
key,
|
|
1423
|
-
value,
|
|
1424
|
-
metadata
|
|
1425
|
-
}) {
|
|
1426
|
-
try {
|
|
1427
|
-
await this.putNamespaceValue({ tableName, key, value, metadata });
|
|
1428
|
-
} catch (error) {
|
|
1429
|
-
this.logger.error(`Failed to put KV value for ${tableName}:${key}:`, error);
|
|
1430
|
-
throw new Error(`Failed to put KV value: ${error.message}`);
|
|
1449
|
+
text: "Failed to update messages"
|
|
1450
|
+
},
|
|
1451
|
+
error$1
|
|
1452
|
+
);
|
|
1431
1453
|
}
|
|
1432
1454
|
}
|
|
1433
|
-
async
|
|
1434
|
-
tableName,
|
|
1435
|
-
schema
|
|
1436
|
-
}) {
|
|
1455
|
+
async getResourceById({ resourceId }) {
|
|
1437
1456
|
try {
|
|
1438
|
-
const
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1457
|
+
const data = await this.#db.getKV(storage.TABLE_RESOURCES, resourceId);
|
|
1458
|
+
if (!data) return null;
|
|
1459
|
+
const resource = typeof data === "string" ? JSON.parse(data) : data;
|
|
1460
|
+
return {
|
|
1461
|
+
...resource,
|
|
1462
|
+
createdAt: storage.ensureDate(resource.createdAt),
|
|
1463
|
+
updatedAt: storage.ensureDate(resource.updatedAt),
|
|
1464
|
+
metadata: this.ensureMetadata(resource.metadata)
|
|
1443
1465
|
};
|
|
1444
|
-
await this.putKV({ tableName, key: schemaKey, value: schema, metadata });
|
|
1445
1466
|
} catch (error$1) {
|
|
1446
|
-
|
|
1467
|
+
const mastraError = new error.MastraError(
|
|
1447
1468
|
{
|
|
1448
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
1469
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
1449
1470
|
domain: error.ErrorDomain.STORAGE,
|
|
1450
1471
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1451
1472
|
details: {
|
|
1452
|
-
|
|
1473
|
+
resourceId
|
|
1453
1474
|
}
|
|
1454
1475
|
},
|
|
1455
1476
|
error$1
|
|
1456
1477
|
);
|
|
1478
|
+
this.logger?.trackException(mastraError);
|
|
1479
|
+
this.logger?.error(mastraError.toString());
|
|
1480
|
+
return null;
|
|
1457
1481
|
}
|
|
1458
1482
|
}
|
|
1459
|
-
async
|
|
1483
|
+
async saveResource({ resource }) {
|
|
1460
1484
|
try {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
account_id: this.accountId,
|
|
1472
|
-
limit: options?.limit || 1e3,
|
|
1473
|
-
prefix: options?.prefix
|
|
1474
|
-
});
|
|
1475
|
-
return response.result;
|
|
1476
|
-
}
|
|
1485
|
+
const resourceToSave = {
|
|
1486
|
+
...resource,
|
|
1487
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : null
|
|
1488
|
+
};
|
|
1489
|
+
await this.#db.putKV({
|
|
1490
|
+
tableName: storage.TABLE_RESOURCES,
|
|
1491
|
+
key: resource.id,
|
|
1492
|
+
value: resourceToSave
|
|
1493
|
+
});
|
|
1494
|
+
return resource;
|
|
1477
1495
|
} catch (error$1) {
|
|
1478
1496
|
throw new error.MastraError(
|
|
1479
1497
|
{
|
|
1480
|
-
id: storage.createStorageErrorId("CLOUDFLARE", "
|
|
1498
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "SAVE_RESOURCE", "FAILED"),
|
|
1481
1499
|
domain: error.ErrorDomain.STORAGE,
|
|
1482
1500
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1483
1501
|
details: {
|
|
1484
|
-
|
|
1502
|
+
resourceId: resource.id
|
|
1485
1503
|
}
|
|
1486
1504
|
},
|
|
1487
1505
|
error$1
|
|
1488
1506
|
);
|
|
1489
1507
|
}
|
|
1490
1508
|
}
|
|
1491
|
-
async
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
this.logger.error(`Failed to delete KV value for ${tableName}:${key}:`, error);
|
|
1507
|
-
throw new Error(`Failed to delete KV value: ${error.message}`);
|
|
1509
|
+
async updateResource({
|
|
1510
|
+
resourceId,
|
|
1511
|
+
workingMemory,
|
|
1512
|
+
metadata
|
|
1513
|
+
}) {
|
|
1514
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1515
|
+
if (!existingResource) {
|
|
1516
|
+
const newResource = {
|
|
1517
|
+
id: resourceId,
|
|
1518
|
+
workingMemory,
|
|
1519
|
+
metadata: metadata || {},
|
|
1520
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1521
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1522
|
+
};
|
|
1523
|
+
return this.saveResource({ resource: newResource });
|
|
1508
1524
|
}
|
|
1525
|
+
const updatedAt = /* @__PURE__ */ new Date();
|
|
1526
|
+
const updatedResource = {
|
|
1527
|
+
...existingResource,
|
|
1528
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1529
|
+
metadata: {
|
|
1530
|
+
...existingResource.metadata,
|
|
1531
|
+
...metadata
|
|
1532
|
+
},
|
|
1533
|
+
updatedAt
|
|
1534
|
+
};
|
|
1535
|
+
return this.saveResource({ resource: updatedResource });
|
|
1509
1536
|
}
|
|
1510
|
-
async
|
|
1537
|
+
async deleteMessages(messageIds) {
|
|
1538
|
+
if (messageIds.length === 0) return;
|
|
1511
1539
|
try {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1540
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
1541
|
+
for (const messageId of messageIds) {
|
|
1542
|
+
const message = await this.findMessageInAnyThread(messageId);
|
|
1543
|
+
if (message?.threadId) {
|
|
1544
|
+
threadIds.add(message.threadId);
|
|
1545
|
+
const messageKey = this.getMessageKey(message.threadId, messageId);
|
|
1546
|
+
await this.#db.deleteKV(storage.TABLE_MESSAGES, messageKey);
|
|
1547
|
+
const orderKey = this.getThreadMessagesKey(message.threadId);
|
|
1548
|
+
const entries = await this.getSortedMessages(orderKey);
|
|
1549
|
+
const filteredEntries = entries.filter((entry) => entry.id !== messageId);
|
|
1550
|
+
if (filteredEntries.length > 0) {
|
|
1551
|
+
await this.#db.putKV({
|
|
1552
|
+
tableName: storage.TABLE_MESSAGES,
|
|
1553
|
+
key: orderKey,
|
|
1554
|
+
value: JSON.stringify(filteredEntries)
|
|
1555
|
+
});
|
|
1556
|
+
} else {
|
|
1557
|
+
await this.#db.deleteKV(storage.TABLE_MESSAGES, orderKey);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
for (const threadId of threadIds) {
|
|
1562
|
+
const thread = await this.getThreadById({ threadId });
|
|
1563
|
+
if (thread) {
|
|
1564
|
+
const updatedThread = {
|
|
1565
|
+
...thread,
|
|
1566
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1567
|
+
};
|
|
1568
|
+
await this.#db.putKV({
|
|
1569
|
+
tableName: storage.TABLE_THREADS,
|
|
1570
|
+
key: this.#db.getKey(storage.TABLE_THREADS, { id: threadId }),
|
|
1571
|
+
value: updatedThread
|
|
1572
|
+
});
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
} catch (error$1) {
|
|
1576
|
+
throw new error.MastraError(
|
|
1577
|
+
{
|
|
1578
|
+
id: storage.createStorageErrorId("CLOUDFLARE", "DELETE_MESSAGES", "FAILED"),
|
|
1579
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1580
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1581
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1582
|
+
},
|
|
1583
|
+
error$1
|
|
1584
|
+
);
|
|
1516
1585
|
}
|
|
1517
1586
|
}
|
|
1518
1587
|
};
|
|
@@ -1520,14 +1589,19 @@ function transformScoreRow(row) {
|
|
|
1520
1589
|
return storage.transformScoreRow(row);
|
|
1521
1590
|
}
|
|
1522
1591
|
var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
1523
|
-
|
|
1524
|
-
constructor(
|
|
1592
|
+
#db;
|
|
1593
|
+
constructor(config) {
|
|
1525
1594
|
super();
|
|
1526
|
-
this
|
|
1595
|
+
this.#db = new CloudflareKVDB(resolveCloudflareConfig(config));
|
|
1596
|
+
}
|
|
1597
|
+
async init() {
|
|
1598
|
+
}
|
|
1599
|
+
async dangerouslyClearAll() {
|
|
1600
|
+
await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1527
1601
|
}
|
|
1528
1602
|
async getScoreById({ id }) {
|
|
1529
1603
|
try {
|
|
1530
|
-
const score = await this.
|
|
1604
|
+
const score = await this.#db.getKV(storage.TABLE_SCORERS, id);
|
|
1531
1605
|
if (!score) {
|
|
1532
1606
|
return null;
|
|
1533
1607
|
}
|
|
@@ -1542,8 +1616,8 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1542
1616
|
},
|
|
1543
1617
|
error$1
|
|
1544
1618
|
);
|
|
1545
|
-
this.logger
|
|
1546
|
-
this.logger
|
|
1619
|
+
this.logger?.trackException(mastraError);
|
|
1620
|
+
this.logger?.error(mastraError.toString());
|
|
1547
1621
|
return null;
|
|
1548
1622
|
}
|
|
1549
1623
|
}
|
|
@@ -1558,7 +1632,7 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1558
1632
|
domain: error.ErrorDomain.STORAGE,
|
|
1559
1633
|
category: error.ErrorCategory.USER,
|
|
1560
1634
|
details: {
|
|
1561
|
-
scorer: score.scorer?.id ?? "unknown",
|
|
1635
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1562
1636
|
entityId: score.entityId ?? "unknown",
|
|
1563
1637
|
entityType: score.entityType ?? "unknown",
|
|
1564
1638
|
traceId: score.traceId ?? "",
|
|
@@ -1586,7 +1660,7 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1586
1660
|
serializedRecord.id = id;
|
|
1587
1661
|
serializedRecord.createdAt = now.toISOString();
|
|
1588
1662
|
serializedRecord.updatedAt = now.toISOString();
|
|
1589
|
-
await this.
|
|
1663
|
+
await this.#db.putKV({
|
|
1590
1664
|
tableName: storage.TABLE_SCORERS,
|
|
1591
1665
|
key: id,
|
|
1592
1666
|
value: serializedRecord
|
|
@@ -1602,8 +1676,8 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1602
1676
|
},
|
|
1603
1677
|
error$1
|
|
1604
1678
|
);
|
|
1605
|
-
this.logger
|
|
1606
|
-
this.logger
|
|
1679
|
+
this.logger?.trackException(mastraError);
|
|
1680
|
+
this.logger?.error(mastraError.toString());
|
|
1607
1681
|
throw mastraError;
|
|
1608
1682
|
}
|
|
1609
1683
|
}
|
|
@@ -1615,10 +1689,10 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1615
1689
|
pagination
|
|
1616
1690
|
}) {
|
|
1617
1691
|
try {
|
|
1618
|
-
const keys = await this.
|
|
1692
|
+
const keys = await this.#db.listKV(storage.TABLE_SCORERS);
|
|
1619
1693
|
const scores = [];
|
|
1620
1694
|
for (const { name: key } of keys) {
|
|
1621
|
-
const score = await this.
|
|
1695
|
+
const score = await this.#db.getKV(storage.TABLE_SCORERS, key);
|
|
1622
1696
|
if (entityId && score.entityId !== entityId) {
|
|
1623
1697
|
continue;
|
|
1624
1698
|
}
|
|
@@ -1672,10 +1746,10 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1672
1746
|
pagination
|
|
1673
1747
|
}) {
|
|
1674
1748
|
try {
|
|
1675
|
-
const keys = await this.
|
|
1749
|
+
const keys = await this.#db.listKV(storage.TABLE_SCORERS);
|
|
1676
1750
|
const scores = [];
|
|
1677
1751
|
for (const { name: key } of keys) {
|
|
1678
|
-
const score = await this.
|
|
1752
|
+
const score = await this.#db.getKV(storage.TABLE_SCORERS, key);
|
|
1679
1753
|
if (score && score.runId === runId) {
|
|
1680
1754
|
scores.push(transformScoreRow(score));
|
|
1681
1755
|
}
|
|
@@ -1710,8 +1784,8 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1710
1784
|
},
|
|
1711
1785
|
error$1
|
|
1712
1786
|
);
|
|
1713
|
-
this.logger
|
|
1714
|
-
this.logger
|
|
1787
|
+
this.logger?.trackException(mastraError);
|
|
1788
|
+
this.logger?.error(mastraError.toString());
|
|
1715
1789
|
return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
|
|
1716
1790
|
}
|
|
1717
1791
|
}
|
|
@@ -1721,10 +1795,10 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1721
1795
|
pagination
|
|
1722
1796
|
}) {
|
|
1723
1797
|
try {
|
|
1724
|
-
const keys = await this.
|
|
1798
|
+
const keys = await this.#db.listKV(storage.TABLE_SCORERS);
|
|
1725
1799
|
const scores = [];
|
|
1726
1800
|
for (const { name: key } of keys) {
|
|
1727
|
-
const score = await this.
|
|
1801
|
+
const score = await this.#db.getKV(storage.TABLE_SCORERS, key);
|
|
1728
1802
|
if (score && score.entityId === entityId && score.entityType === entityType) {
|
|
1729
1803
|
scores.push(transformScoreRow(score));
|
|
1730
1804
|
}
|
|
@@ -1759,8 +1833,8 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1759
1833
|
},
|
|
1760
1834
|
error$1
|
|
1761
1835
|
);
|
|
1762
|
-
this.logger
|
|
1763
|
-
this.logger
|
|
1836
|
+
this.logger?.trackException(mastraError);
|
|
1837
|
+
this.logger?.error(mastraError.toString());
|
|
1764
1838
|
return { pagination: { total: 0, page: 0, perPage: 100, hasMore: false }, scores: [] };
|
|
1765
1839
|
}
|
|
1766
1840
|
}
|
|
@@ -1770,10 +1844,10 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1770
1844
|
pagination
|
|
1771
1845
|
}) {
|
|
1772
1846
|
try {
|
|
1773
|
-
const keys = await this.
|
|
1847
|
+
const keys = await this.#db.listKV(storage.TABLE_SCORERS);
|
|
1774
1848
|
const scores = [];
|
|
1775
1849
|
for (const { name: key } of keys) {
|
|
1776
|
-
const score = await this.
|
|
1850
|
+
const score = await this.#db.getKV(storage.TABLE_SCORERS, key);
|
|
1777
1851
|
if (score && score.traceId === traceId && score.spanId === spanId) {
|
|
1778
1852
|
scores.push(transformScoreRow(score));
|
|
1779
1853
|
}
|
|
@@ -1815,10 +1889,15 @@ var ScoresStorageCloudflare = class extends storage.ScoresStorage {
|
|
|
1815
1889
|
}
|
|
1816
1890
|
};
|
|
1817
1891
|
var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
1818
|
-
|
|
1819
|
-
constructor(
|
|
1892
|
+
#db;
|
|
1893
|
+
constructor(config) {
|
|
1820
1894
|
super();
|
|
1821
|
-
this
|
|
1895
|
+
this.#db = new CloudflareKVDB(resolveCloudflareConfig(config));
|
|
1896
|
+
}
|
|
1897
|
+
async init() {
|
|
1898
|
+
}
|
|
1899
|
+
async dangerouslyClearAll() {
|
|
1900
|
+
await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1822
1901
|
}
|
|
1823
1902
|
validateWorkflowParams(params) {
|
|
1824
1903
|
const { workflowName, runId } = params;
|
|
@@ -1844,17 +1923,20 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
1844
1923
|
}
|
|
1845
1924
|
async persistWorkflowSnapshot(params) {
|
|
1846
1925
|
try {
|
|
1847
|
-
const { workflowName, runId, resourceId, snapshot } = params;
|
|
1848
|
-
|
|
1926
|
+
const { workflowName, runId, resourceId, snapshot, createdAt, updatedAt } = params;
|
|
1927
|
+
const now = /* @__PURE__ */ new Date();
|
|
1928
|
+
const existingKey = this.#db.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId });
|
|
1929
|
+
const existing = await this.#db.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, existingKey);
|
|
1930
|
+
await this.#db.putKV({
|
|
1849
1931
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1850
|
-
key:
|
|
1932
|
+
key: existingKey,
|
|
1851
1933
|
value: {
|
|
1852
1934
|
workflow_name: workflowName,
|
|
1853
1935
|
run_id: runId,
|
|
1854
1936
|
resourceId,
|
|
1855
1937
|
snapshot: JSON.stringify(snapshot),
|
|
1856
|
-
createdAt:
|
|
1857
|
-
updatedAt:
|
|
1938
|
+
createdAt: existing?.createdAt ?? createdAt ?? now,
|
|
1939
|
+
updatedAt: updatedAt ?? now
|
|
1858
1940
|
}
|
|
1859
1941
|
});
|
|
1860
1942
|
} catch (error$1) {
|
|
@@ -1877,8 +1959,8 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
1877
1959
|
try {
|
|
1878
1960
|
this.validateWorkflowParams(params);
|
|
1879
1961
|
const { workflowName, runId } = params;
|
|
1880
|
-
const key = this.
|
|
1881
|
-
const data = await this.
|
|
1962
|
+
const key = this.#db.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId });
|
|
1963
|
+
const data = await this.#db.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1882
1964
|
if (!data) return null;
|
|
1883
1965
|
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
1884
1966
|
return snapshotData;
|
|
@@ -1924,7 +2006,7 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
1924
2006
|
runId,
|
|
1925
2007
|
resourceId
|
|
1926
2008
|
}) {
|
|
1927
|
-
const prefix = this.
|
|
2009
|
+
const prefix = this.#db.namespacePrefix ? `${this.#db.namespacePrefix}:` : "";
|
|
1928
2010
|
let key = `${prefix}${storage.TABLE_WORKFLOW_SNAPSHOT}`;
|
|
1929
2011
|
if (workflowName) key += `:${workflowName}`;
|
|
1930
2012
|
if (runId) key += `:${runId}`;
|
|
@@ -1955,7 +2037,7 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
1955
2037
|
const normalizedPerPage = storage.normalizePerPage(perPage, 20);
|
|
1956
2038
|
const offset = page * normalizedPerPage;
|
|
1957
2039
|
const prefix = this.buildWorkflowSnapshotPrefix({ workflowName });
|
|
1958
|
-
const keyObjs = await this.
|
|
2040
|
+
const keyObjs = await this.#db.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
1959
2041
|
const runs = [];
|
|
1960
2042
|
for (const { name: key } of keyObjs) {
|
|
1961
2043
|
const parts = key.split(":");
|
|
@@ -1964,21 +2046,20 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
1964
2046
|
const wfName = parts[idx + 1];
|
|
1965
2047
|
const keyResourceId = parts.length > idx + 3 ? parts[idx + 3] : void 0;
|
|
1966
2048
|
if (workflowName && wfName !== workflowName) continue;
|
|
1967
|
-
|
|
1968
|
-
const data = await this.operations.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
2049
|
+
const data = await this.#db.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
1969
2050
|
if (!data) continue;
|
|
1970
2051
|
try {
|
|
1971
|
-
|
|
2052
|
+
const effectiveResourceId = keyResourceId || data.resourceId;
|
|
2053
|
+
if (resourceId && effectiveResourceId !== resourceId) continue;
|
|
1972
2054
|
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
1973
2055
|
if (status && snapshotData.status !== status) continue;
|
|
1974
2056
|
const createdAt = storage.ensureDate(data.createdAt);
|
|
1975
2057
|
if (fromDate && createdAt && createdAt < fromDate) continue;
|
|
1976
2058
|
if (toDate && createdAt && createdAt > toDate) continue;
|
|
1977
|
-
const resourceIdToUse = keyResourceId || data.resourceId;
|
|
1978
2059
|
const run = this.parseWorkflowRun({
|
|
1979
2060
|
...data,
|
|
1980
2061
|
workflow_name: wfName,
|
|
1981
|
-
resourceId:
|
|
2062
|
+
resourceId: effectiveResourceId,
|
|
1982
2063
|
snapshot: snapshotData
|
|
1983
2064
|
});
|
|
1984
2065
|
runs.push(run);
|
|
@@ -2019,7 +2100,7 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
2019
2100
|
throw new Error("runId, workflowName, are required");
|
|
2020
2101
|
}
|
|
2021
2102
|
const prefix = this.buildWorkflowSnapshotPrefix({ workflowName, runId });
|
|
2022
|
-
const keyObjs = await this.
|
|
2103
|
+
const keyObjs = await this.#db.listKV(storage.TABLE_WORKFLOW_SNAPSHOT, { prefix });
|
|
2023
2104
|
if (!keyObjs.length) return null;
|
|
2024
2105
|
const exactKey = keyObjs.find((k) => {
|
|
2025
2106
|
const parts = k.name.split(":");
|
|
@@ -2030,7 +2111,7 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
2030
2111
|
return wfName === workflowName && rId === runId;
|
|
2031
2112
|
});
|
|
2032
2113
|
if (!exactKey) return null;
|
|
2033
|
-
const data = await this.
|
|
2114
|
+
const data = await this.#db.getKV(storage.TABLE_WORKFLOW_SNAPSHOT, exactKey.name);
|
|
2034
2115
|
if (!data) return null;
|
|
2035
2116
|
const snapshotData = typeof data.snapshot === "string" ? JSON.parse(data.snapshot) : data.snapshot;
|
|
2036
2117
|
return this.parseWorkflowRun({ ...data, snapshot: snapshotData });
|
|
@@ -2057,8 +2138,8 @@ var WorkflowsStorageCloudflare = class extends storage.WorkflowsStorage {
|
|
|
2057
2138
|
if (!runId || !workflowName) {
|
|
2058
2139
|
throw new Error("runId and workflowName are required");
|
|
2059
2140
|
}
|
|
2060
|
-
const key = this.
|
|
2061
|
-
await this.
|
|
2141
|
+
const key = this.#db.getKey(storage.TABLE_WORKFLOW_SNAPSHOT, { workflow_name: workflowName, run_id: runId });
|
|
2142
|
+
await this.#db.deleteKV(storage.TABLE_WORKFLOW_SNAPSHOT, key);
|
|
2062
2143
|
} catch (error$1) {
|
|
2063
2144
|
throw new error.MastraError(
|
|
2064
2145
|
{
|
|
@@ -2114,20 +2195,36 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
2114
2195
|
}
|
|
2115
2196
|
}
|
|
2116
2197
|
get supports() {
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2198
|
+
return {
|
|
2199
|
+
selectByIncludeResourceScope: true,
|
|
2200
|
+
resourceWorkingMemory: true,
|
|
2201
|
+
hasColumn: false,
|
|
2202
|
+
createTable: false,
|
|
2203
|
+
deleteMessages: true,
|
|
2204
|
+
observability: false,
|
|
2205
|
+
indexManagement: false,
|
|
2206
|
+
listScoresBySpan: true,
|
|
2207
|
+
agents: false
|
|
2208
|
+
};
|
|
2122
2209
|
}
|
|
2123
2210
|
constructor(config) {
|
|
2124
2211
|
super({ id: config.id, name: "Cloudflare", disableInit: config.disableInit });
|
|
2125
2212
|
try {
|
|
2213
|
+
let workflows;
|
|
2214
|
+
let memory;
|
|
2215
|
+
let scores;
|
|
2126
2216
|
if (isWorkersConfig(config)) {
|
|
2127
2217
|
this.validateWorkersConfig(config);
|
|
2128
2218
|
this.bindings = config.bindings;
|
|
2129
2219
|
this.namespacePrefix = config.keyPrefix?.trim() || "";
|
|
2130
2220
|
this.logger.info("Using Cloudflare KV Workers Binding API");
|
|
2221
|
+
const domainConfig = {
|
|
2222
|
+
bindings: this.bindings,
|
|
2223
|
+
keyPrefix: this.namespacePrefix
|
|
2224
|
+
};
|
|
2225
|
+
workflows = new WorkflowsStorageCloudflare(domainConfig);
|
|
2226
|
+
memory = new MemoryStorageCloudflare(domainConfig);
|
|
2227
|
+
scores = new ScoresStorageCloudflare(domainConfig);
|
|
2131
2228
|
} else {
|
|
2132
2229
|
this.validateRestConfig(config);
|
|
2133
2230
|
this.accountId = config.accountId.trim();
|
|
@@ -2136,24 +2233,16 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
2136
2233
|
apiToken: config.apiToken.trim()
|
|
2137
2234
|
});
|
|
2138
2235
|
this.logger.info("Using Cloudflare KV REST API");
|
|
2236
|
+
const domainConfig = {
|
|
2237
|
+
client: this.client,
|
|
2238
|
+
accountId: this.accountId,
|
|
2239
|
+
namespacePrefix: this.namespacePrefix
|
|
2240
|
+
};
|
|
2241
|
+
workflows = new WorkflowsStorageCloudflare(domainConfig);
|
|
2242
|
+
memory = new MemoryStorageCloudflare(domainConfig);
|
|
2243
|
+
scores = new ScoresStorageCloudflare(domainConfig);
|
|
2139
2244
|
}
|
|
2140
|
-
const operations = new StoreOperationsCloudflare({
|
|
2141
|
-
accountId: this.accountId,
|
|
2142
|
-
client: this.client,
|
|
2143
|
-
namespacePrefix: this.namespacePrefix,
|
|
2144
|
-
bindings: this.bindings
|
|
2145
|
-
});
|
|
2146
|
-
const workflows = new WorkflowsStorageCloudflare({
|
|
2147
|
-
operations
|
|
2148
|
-
});
|
|
2149
|
-
const memory = new MemoryStorageCloudflare({
|
|
2150
|
-
operations
|
|
2151
|
-
});
|
|
2152
|
-
const scores = new ScoresStorageCloudflare({
|
|
2153
|
-
operations
|
|
2154
|
-
});
|
|
2155
2245
|
this.stores = {
|
|
2156
|
-
operations,
|
|
2157
2246
|
workflows,
|
|
2158
2247
|
memory,
|
|
2159
2248
|
scores
|
|
@@ -2169,156 +2258,6 @@ var CloudflareStore = class extends storage.MastraStorage {
|
|
|
2169
2258
|
);
|
|
2170
2259
|
}
|
|
2171
2260
|
}
|
|
2172
|
-
async createTable({
|
|
2173
|
-
tableName,
|
|
2174
|
-
schema
|
|
2175
|
-
}) {
|
|
2176
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
2177
|
-
}
|
|
2178
|
-
async alterTable(_args) {
|
|
2179
|
-
return this.stores.operations.alterTable(_args);
|
|
2180
|
-
}
|
|
2181
|
-
async clearTable({ tableName }) {
|
|
2182
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2183
|
-
}
|
|
2184
|
-
async dropTable({ tableName }) {
|
|
2185
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2186
|
-
}
|
|
2187
|
-
async insert({
|
|
2188
|
-
tableName,
|
|
2189
|
-
record
|
|
2190
|
-
}) {
|
|
2191
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2192
|
-
}
|
|
2193
|
-
async load({ tableName, keys }) {
|
|
2194
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2195
|
-
}
|
|
2196
|
-
async getThreadById({ threadId }) {
|
|
2197
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2198
|
-
}
|
|
2199
|
-
async saveThread({ thread }) {
|
|
2200
|
-
return this.stores.memory.saveThread({ thread });
|
|
2201
|
-
}
|
|
2202
|
-
async updateThread({
|
|
2203
|
-
id,
|
|
2204
|
-
title,
|
|
2205
|
-
metadata
|
|
2206
|
-
}) {
|
|
2207
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2208
|
-
}
|
|
2209
|
-
async deleteThread({ threadId }) {
|
|
2210
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2211
|
-
}
|
|
2212
|
-
async saveMessages(args) {
|
|
2213
|
-
return this.stores.memory.saveMessages(args);
|
|
2214
|
-
}
|
|
2215
|
-
async updateWorkflowResults({
|
|
2216
|
-
workflowName,
|
|
2217
|
-
runId,
|
|
2218
|
-
stepId,
|
|
2219
|
-
result,
|
|
2220
|
-
requestContext
|
|
2221
|
-
}) {
|
|
2222
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2223
|
-
}
|
|
2224
|
-
async updateWorkflowState({
|
|
2225
|
-
workflowName,
|
|
2226
|
-
runId,
|
|
2227
|
-
opts
|
|
2228
|
-
}) {
|
|
2229
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2230
|
-
}
|
|
2231
|
-
async listMessagesById({ messageIds }) {
|
|
2232
|
-
return this.stores.memory.listMessagesById({ messageIds });
|
|
2233
|
-
}
|
|
2234
|
-
async persistWorkflowSnapshot(params) {
|
|
2235
|
-
return this.stores.workflows.persistWorkflowSnapshot(params);
|
|
2236
|
-
}
|
|
2237
|
-
async loadWorkflowSnapshot(params) {
|
|
2238
|
-
return this.stores.workflows.loadWorkflowSnapshot(params);
|
|
2239
|
-
}
|
|
2240
|
-
async batchInsert(input) {
|
|
2241
|
-
return this.stores.operations.batchInsert(input);
|
|
2242
|
-
}
|
|
2243
|
-
async listWorkflowRuns({
|
|
2244
|
-
workflowName,
|
|
2245
|
-
perPage = 20,
|
|
2246
|
-
page = 0,
|
|
2247
|
-
resourceId,
|
|
2248
|
-
fromDate,
|
|
2249
|
-
toDate,
|
|
2250
|
-
status
|
|
2251
|
-
} = {}) {
|
|
2252
|
-
return this.stores.workflows.listWorkflowRuns({
|
|
2253
|
-
workflowName,
|
|
2254
|
-
perPage,
|
|
2255
|
-
page,
|
|
2256
|
-
resourceId,
|
|
2257
|
-
fromDate,
|
|
2258
|
-
toDate,
|
|
2259
|
-
status
|
|
2260
|
-
});
|
|
2261
|
-
}
|
|
2262
|
-
async getWorkflowRunById({
|
|
2263
|
-
runId,
|
|
2264
|
-
workflowName
|
|
2265
|
-
}) {
|
|
2266
|
-
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2267
|
-
}
|
|
2268
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2269
|
-
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
2270
|
-
}
|
|
2271
|
-
async updateMessages(args) {
|
|
2272
|
-
return this.stores.memory.updateMessages(args);
|
|
2273
|
-
}
|
|
2274
|
-
async getScoreById({ id }) {
|
|
2275
|
-
return this.stores.scores.getScoreById({ id });
|
|
2276
|
-
}
|
|
2277
|
-
async saveScore(score) {
|
|
2278
|
-
return this.stores.scores.saveScore(score);
|
|
2279
|
-
}
|
|
2280
|
-
async listScoresByRunId({
|
|
2281
|
-
runId,
|
|
2282
|
-
pagination
|
|
2283
|
-
}) {
|
|
2284
|
-
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
2285
|
-
}
|
|
2286
|
-
async listScoresByEntityId({
|
|
2287
|
-
entityId,
|
|
2288
|
-
entityType,
|
|
2289
|
-
pagination
|
|
2290
|
-
}) {
|
|
2291
|
-
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
2292
|
-
}
|
|
2293
|
-
async listScoresByScorerId({
|
|
2294
|
-
scorerId,
|
|
2295
|
-
entityId,
|
|
2296
|
-
entityType,
|
|
2297
|
-
source,
|
|
2298
|
-
pagination
|
|
2299
|
-
}) {
|
|
2300
|
-
return this.stores.scores.listScoresByScorerId({ scorerId, entityId, entityType, source, pagination });
|
|
2301
|
-
}
|
|
2302
|
-
async listScoresBySpan({
|
|
2303
|
-
traceId,
|
|
2304
|
-
spanId,
|
|
2305
|
-
pagination
|
|
2306
|
-
}) {
|
|
2307
|
-
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
2308
|
-
}
|
|
2309
|
-
async getResourceById({ resourceId }) {
|
|
2310
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2311
|
-
}
|
|
2312
|
-
async saveResource({ resource }) {
|
|
2313
|
-
return this.stores.memory.saveResource({ resource });
|
|
2314
|
-
}
|
|
2315
|
-
async updateResource({
|
|
2316
|
-
resourceId,
|
|
2317
|
-
workingMemory,
|
|
2318
|
-
metadata
|
|
2319
|
-
}) {
|
|
2320
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2321
|
-
}
|
|
2322
2261
|
async close() {
|
|
2323
2262
|
}
|
|
2324
2263
|
};
|