@mastra/elasticsearch 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/docs/SKILL.md +4 -3
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/integrations-databases-elasticsearch.md +156 -0
- package/dist/docs/references/{docs-rag-vector-databases.md → reference-rag-vector-databases.md} +46 -5
- package/dist/index.cjs +1643 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +273 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +273 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1618 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
2
24
|
let _elastic_elasticsearch = require("@elastic/elasticsearch");
|
|
3
25
|
let _mastra_core_error = require("@mastra/core/error");
|
|
4
26
|
let _mastra_core_storage = require("@mastra/core/storage");
|
|
5
27
|
let _mastra_core_vector = require("@mastra/core/vector");
|
|
6
28
|
let _mastra_core_vector_filter = require("@mastra/core/vector/filter");
|
|
29
|
+
let _mastra_core_agent = require("@mastra/core/agent");
|
|
30
|
+
let crypto$1 = require("crypto");
|
|
31
|
+
crypto$1 = __toESM(crypto$1, 1);
|
|
32
|
+
let _mastra_core_evals = require("@mastra/core/evals");
|
|
7
33
|
//#region package.json
|
|
8
|
-
var version = "1.
|
|
34
|
+
var version = "1.4.0";
|
|
9
35
|
//#endregion
|
|
10
36
|
//#region src/vector/filter.ts
|
|
11
37
|
/**
|
|
@@ -841,6 +867,1622 @@ var ElasticSearchVector = class extends _mastra_core_vector.MastraVector {
|
|
|
841
867
|
}
|
|
842
868
|
};
|
|
843
869
|
//#endregion
|
|
870
|
+
//#region src/storage/domains/utils.ts
|
|
871
|
+
/**
|
|
872
|
+
* Generate a document key from table name and key parts.
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* ```typescript
|
|
876
|
+
* getKey('mastra_threads', { id: 'thread-123' });
|
|
877
|
+
* // Returns: 'mastra_threads:id:thread-123'
|
|
878
|
+
* ```
|
|
879
|
+
*/
|
|
880
|
+
function getKey(tableName, keys) {
|
|
881
|
+
return `${tableName}:${Object.entries(keys).filter(([_, value]) => value !== void 0).map(([key, value]) => {
|
|
882
|
+
if (value && typeof value === "object") return `${key}:${JSON.stringify(value)}`;
|
|
883
|
+
return `${key}:${value}`;
|
|
884
|
+
}).join(":")}`;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Process a record for storage, generating the appropriate document id and serializing dates.
|
|
888
|
+
*/
|
|
889
|
+
function processRecord(tableName, record) {
|
|
890
|
+
let key;
|
|
891
|
+
if (tableName === _mastra_core_storage.TABLE_MESSAGES) key = getKey(tableName, {
|
|
892
|
+
threadId: record.threadId,
|
|
893
|
+
id: record.id
|
|
894
|
+
});
|
|
895
|
+
else if (tableName === _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT) key = getKey(tableName, {
|
|
896
|
+
namespace: record.namespace || "workflows",
|
|
897
|
+
workflow_name: record.workflow_name,
|
|
898
|
+
run_id: record.run_id,
|
|
899
|
+
...record.resourceId ? { resourceId: record.resourceId } : {}
|
|
900
|
+
});
|
|
901
|
+
else key = getKey(tableName, { id: record.id });
|
|
902
|
+
const processedRecord = {
|
|
903
|
+
...record,
|
|
904
|
+
createdAt: (0, _mastra_core_storage.serializeDate)(record.createdAt),
|
|
905
|
+
updatedAt: (0, _mastra_core_storage.serializeDate)(record.updatedAt)
|
|
906
|
+
};
|
|
907
|
+
return {
|
|
908
|
+
key,
|
|
909
|
+
processedRecord
|
|
910
|
+
};
|
|
911
|
+
}
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region src/storage/db.ts
|
|
914
|
+
const SEARCH_PAGE_SIZE = 1e3;
|
|
915
|
+
/**
|
|
916
|
+
* Thin document-store layer over ElasticSearch.
|
|
917
|
+
*
|
|
918
|
+
* Each Mastra table maps to one ElasticSearch index (same name, already lowercase).
|
|
919
|
+
* Records are stored as opaque JSON strings in a non-indexed `doc` field, with a
|
|
920
|
+
* `key` keyword field (copy of `_id`) used for stable `search_after` pagination.
|
|
921
|
+
*
|
|
922
|
+
* ElasticSearch is near-real-time: all writes use `refresh: true` so
|
|
923
|
+
* subsequent searches observe them, and point reads use `_get` by id (which is
|
|
924
|
+
* real-time regardless of refresh).
|
|
925
|
+
*/
|
|
926
|
+
var ElasticSearchDB = class {
|
|
927
|
+
client;
|
|
928
|
+
ensuredIndexes = /* @__PURE__ */ new Set();
|
|
929
|
+
constructor({ client }) {
|
|
930
|
+
this.client = client;
|
|
931
|
+
}
|
|
932
|
+
getClient() {
|
|
933
|
+
return this.client;
|
|
934
|
+
}
|
|
935
|
+
async ensureIndex(tableName) {
|
|
936
|
+
if (this.ensuredIndexes.has(tableName)) return;
|
|
937
|
+
try {
|
|
938
|
+
if (!await this.client.indices.exists({ index: tableName })) await this.client.indices.create({
|
|
939
|
+
index: tableName,
|
|
940
|
+
mappings: {
|
|
941
|
+
dynamic: false,
|
|
942
|
+
properties: {
|
|
943
|
+
key: { type: "keyword" },
|
|
944
|
+
doc: {
|
|
945
|
+
type: "text",
|
|
946
|
+
index: false
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
this.ensuredIndexes.add(tableName);
|
|
952
|
+
} catch (error) {
|
|
953
|
+
const message = error?.message || error?.toString();
|
|
954
|
+
if (message && message.toLowerCase().includes("already exists")) {
|
|
955
|
+
this.ensuredIndexes.add(tableName);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
throw new _mastra_core_error.MastraError({
|
|
959
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "ENSURE_INDEX", "FAILED"),
|
|
960
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
961
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
962
|
+
details: { tableName }
|
|
963
|
+
}, error);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
async insert({ tableName, record }) {
|
|
967
|
+
const { key, processedRecord } = processRecord(tableName, record);
|
|
968
|
+
await this.set({
|
|
969
|
+
tableName,
|
|
970
|
+
key,
|
|
971
|
+
value: processedRecord
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
async set({ tableName, key, value }) {
|
|
975
|
+
await this.ensureIndex(tableName);
|
|
976
|
+
try {
|
|
977
|
+
await this.client.index({
|
|
978
|
+
index: tableName,
|
|
979
|
+
id: key,
|
|
980
|
+
document: {
|
|
981
|
+
key,
|
|
982
|
+
doc: JSON.stringify(value)
|
|
983
|
+
},
|
|
984
|
+
refresh: true
|
|
985
|
+
});
|
|
986
|
+
} catch (error) {
|
|
987
|
+
throw new _mastra_core_error.MastraError({
|
|
988
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "INSERT", "FAILED"),
|
|
989
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
990
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
991
|
+
details: { tableName }
|
|
992
|
+
}, error);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
async bulkSet({ tableName, entries }) {
|
|
996
|
+
if (entries.length === 0) return;
|
|
997
|
+
await this.ensureIndex(tableName);
|
|
998
|
+
try {
|
|
999
|
+
const operations = entries.flatMap(({ key, value }) => [{ index: {
|
|
1000
|
+
_index: tableName,
|
|
1001
|
+
_id: key
|
|
1002
|
+
} }, {
|
|
1003
|
+
key,
|
|
1004
|
+
doc: JSON.stringify(value)
|
|
1005
|
+
}]);
|
|
1006
|
+
const response = await this.client.bulk({
|
|
1007
|
+
operations,
|
|
1008
|
+
refresh: true
|
|
1009
|
+
});
|
|
1010
|
+
if (response.errors) {
|
|
1011
|
+
const firstError = response.items.find((item) => item.index?.error)?.index?.error;
|
|
1012
|
+
throw new Error(`Bulk write failed: ${firstError?.reason ?? "unknown error"}`);
|
|
1013
|
+
}
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
throw new _mastra_core_error.MastraError({
|
|
1016
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "BATCH_INSERT", "FAILED"),
|
|
1017
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1018
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1019
|
+
details: { tableName }
|
|
1020
|
+
}, error);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
async get({ tableName, keys }) {
|
|
1024
|
+
const key = getKey(tableName, keys);
|
|
1025
|
+
return this.getByKey({
|
|
1026
|
+
tableName,
|
|
1027
|
+
key
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
async getByKey({ tableName, key }) {
|
|
1031
|
+
await this.ensureIndex(tableName);
|
|
1032
|
+
try {
|
|
1033
|
+
const response = await this.client.get({
|
|
1034
|
+
index: tableName,
|
|
1035
|
+
id: key
|
|
1036
|
+
}, { ignore: [404] });
|
|
1037
|
+
if (!response.found || !response._source?.doc) return null;
|
|
1038
|
+
return JSON.parse(response._source.doc);
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
throw new _mastra_core_error.MastraError({
|
|
1041
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LOAD", "FAILED"),
|
|
1042
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1043
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1044
|
+
details: { tableName }
|
|
1045
|
+
}, error);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Returns all documents in a table, parsed. Uses `search_after` on the `key`
|
|
1050
|
+
* field for stable deep pagination.
|
|
1051
|
+
*/
|
|
1052
|
+
async listAll({ tableName, keyPrefix }) {
|
|
1053
|
+
return (await this.listAllEntries({
|
|
1054
|
+
tableName,
|
|
1055
|
+
keyPrefix
|
|
1056
|
+
})).map((entry) => entry.value);
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Returns all `{ key, value }` entries in a table (optionally filtered by key
|
|
1060
|
+
* prefix), using `search_after` pagination.
|
|
1061
|
+
*/
|
|
1062
|
+
async listAllEntries({ tableName, keyPrefix }) {
|
|
1063
|
+
await this.ensureIndex(tableName);
|
|
1064
|
+
try {
|
|
1065
|
+
const results = [];
|
|
1066
|
+
let searchAfter;
|
|
1067
|
+
while (true) {
|
|
1068
|
+
const hits = (await this.client.search({
|
|
1069
|
+
index: tableName,
|
|
1070
|
+
size: SEARCH_PAGE_SIZE,
|
|
1071
|
+
query: keyPrefix ? { prefix: { key: keyPrefix } } : { match_all: {} },
|
|
1072
|
+
sort: [{ key: "asc" }],
|
|
1073
|
+
...searchAfter ? { search_after: searchAfter } : {}
|
|
1074
|
+
})).hits.hits;
|
|
1075
|
+
for (const hit of hits) if (hit._source?.doc) results.push({
|
|
1076
|
+
key: hit._source.key,
|
|
1077
|
+
value: JSON.parse(hit._source.doc)
|
|
1078
|
+
});
|
|
1079
|
+
if (hits.length < SEARCH_PAGE_SIZE) break;
|
|
1080
|
+
searchAfter = hits[hits.length - 1].sort;
|
|
1081
|
+
}
|
|
1082
|
+
return results;
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
throw new _mastra_core_error.MastraError({
|
|
1085
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SCAN", "FAILED"),
|
|
1086
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1087
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1088
|
+
details: { tableName }
|
|
1089
|
+
}, error);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
async delete({ tableName, key }) {
|
|
1093
|
+
await this.ensureIndex(tableName);
|
|
1094
|
+
try {
|
|
1095
|
+
await this.client.delete({
|
|
1096
|
+
index: tableName,
|
|
1097
|
+
id: key,
|
|
1098
|
+
refresh: true
|
|
1099
|
+
}, { ignore: [404] });
|
|
1100
|
+
} catch (error) {
|
|
1101
|
+
throw new _mastra_core_error.MastraError({
|
|
1102
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "DELETE", "FAILED"),
|
|
1103
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1104
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1105
|
+
details: { tableName }
|
|
1106
|
+
}, error);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
async deleteMany({ tableName, keys }) {
|
|
1110
|
+
if (keys.length === 0) return;
|
|
1111
|
+
await this.ensureIndex(tableName);
|
|
1112
|
+
try {
|
|
1113
|
+
await this.client.deleteByQuery({
|
|
1114
|
+
index: tableName,
|
|
1115
|
+
query: { terms: { key: keys } },
|
|
1116
|
+
refresh: true,
|
|
1117
|
+
conflicts: "proceed"
|
|
1118
|
+
});
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
throw new _mastra_core_error.MastraError({
|
|
1121
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "DELETE_MANY", "FAILED"),
|
|
1122
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1123
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1124
|
+
details: { tableName }
|
|
1125
|
+
}, error);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
async deleteData({ tableName, keyPrefix }) {
|
|
1129
|
+
await this.ensureIndex(tableName);
|
|
1130
|
+
try {
|
|
1131
|
+
await this.client.deleteByQuery({
|
|
1132
|
+
index: tableName,
|
|
1133
|
+
query: keyPrefix ? { prefix: { key: keyPrefix } } : { match_all: {} },
|
|
1134
|
+
refresh: true,
|
|
1135
|
+
conflicts: "proceed"
|
|
1136
|
+
});
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
throw new _mastra_core_error.MastraError({
|
|
1139
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "CLEAR_TABLE", "FAILED"),
|
|
1140
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1141
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1142
|
+
details: { tableName }
|
|
1143
|
+
}, error);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
//#endregion
|
|
1148
|
+
//#region src/storage/domains/memory/index.ts
|
|
1149
|
+
var MemoryElasticSearch = class extends _mastra_core_storage.MemoryStorage {
|
|
1150
|
+
supportsPartialThreadUpdate = true;
|
|
1151
|
+
db;
|
|
1152
|
+
constructor(config) {
|
|
1153
|
+
super();
|
|
1154
|
+
this.db = new ElasticSearchDB({ client: config.client });
|
|
1155
|
+
}
|
|
1156
|
+
async dangerouslyClearAll() {
|
|
1157
|
+
await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_THREADS });
|
|
1158
|
+
await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_MESSAGES });
|
|
1159
|
+
await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_RESOURCES });
|
|
1160
|
+
}
|
|
1161
|
+
async getThreadById({ threadId, resourceId }) {
|
|
1162
|
+
try {
|
|
1163
|
+
const thread = await this.db.get({
|
|
1164
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1165
|
+
keys: { id: threadId }
|
|
1166
|
+
});
|
|
1167
|
+
if (!thread || resourceId !== void 0 && thread.resourceId !== resourceId) return null;
|
|
1168
|
+
return {
|
|
1169
|
+
...thread,
|
|
1170
|
+
createdAt: (0, _mastra_core_storage.ensureDate)(thread.createdAt),
|
|
1171
|
+
updatedAt: (0, _mastra_core_storage.ensureDate)(thread.updatedAt),
|
|
1172
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
1173
|
+
};
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
throw new _mastra_core_error.MastraError({
|
|
1176
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "GET_THREAD_BY_ID", "FAILED"),
|
|
1177
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1178
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1179
|
+
details: { threadId }
|
|
1180
|
+
}, error);
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
async listThreadsByResourceId(args) {
|
|
1184
|
+
return this.listThreads(args);
|
|
1185
|
+
}
|
|
1186
|
+
async listThreads(args) {
|
|
1187
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
1188
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
1189
|
+
try {
|
|
1190
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
throw new _mastra_core_error.MastraError({
|
|
1193
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_THREADS", "INVALID_PAGE"),
|
|
1194
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1195
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1196
|
+
details: {
|
|
1197
|
+
page,
|
|
1198
|
+
...perPageInput !== void 0 && { perPage: perPageInput }
|
|
1199
|
+
}
|
|
1200
|
+
}, error instanceof Error ? error : /* @__PURE__ */ new Error("Invalid pagination parameters"));
|
|
1201
|
+
}
|
|
1202
|
+
const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 100);
|
|
1203
|
+
try {
|
|
1204
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
throw new _mastra_core_error.MastraError({
|
|
1207
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
1208
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1209
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1210
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
1211
|
+
}, error instanceof Error ? error : /* @__PURE__ */ new Error("Invalid metadata key"));
|
|
1212
|
+
}
|
|
1213
|
+
const { offset, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
|
|
1214
|
+
try {
|
|
1215
|
+
const allThreads = [];
|
|
1216
|
+
const results = await this.db.listAll({ tableName: _mastra_core_storage.TABLE_THREADS });
|
|
1217
|
+
for (const thread of results) {
|
|
1218
|
+
if (filter?.resourceId && thread.resourceId !== filter.resourceId) continue;
|
|
1219
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
1220
|
+
const threadMetadata = typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata;
|
|
1221
|
+
if (!Object.entries(filter.metadata).every(([key, value]) => (0, _mastra_core_storage.jsonValueEquals)(threadMetadata?.[key], value))) continue;
|
|
1222
|
+
}
|
|
1223
|
+
allThreads.push({
|
|
1224
|
+
...thread,
|
|
1225
|
+
createdAt: (0, _mastra_core_storage.ensureDate)(thread.createdAt),
|
|
1226
|
+
updatedAt: (0, _mastra_core_storage.ensureDate)(thread.updatedAt),
|
|
1227
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
const sortedThreads = this.sortThreads(allThreads, field, direction);
|
|
1231
|
+
const total = sortedThreads.length;
|
|
1232
|
+
const end = perPageInput === false ? total : offset + perPage;
|
|
1233
|
+
return {
|
|
1234
|
+
threads: sortedThreads.slice(offset, end),
|
|
1235
|
+
total,
|
|
1236
|
+
page,
|
|
1237
|
+
perPage: perPageForResponse,
|
|
1238
|
+
hasMore: perPageInput === false ? false : end < total
|
|
1239
|
+
};
|
|
1240
|
+
} catch (error) {
|
|
1241
|
+
if (error instanceof _mastra_core_error.MastraError && error.category === _mastra_core_error.ErrorCategory.USER) throw error;
|
|
1242
|
+
const mastraError = new _mastra_core_error.MastraError({
|
|
1243
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_THREADS", "FAILED"),
|
|
1244
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1245
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1246
|
+
details: {
|
|
1247
|
+
...filter?.resourceId && { resourceId: filter.resourceId },
|
|
1248
|
+
hasMetadataFilter: !!filter?.metadata,
|
|
1249
|
+
page,
|
|
1250
|
+
perPage
|
|
1251
|
+
}
|
|
1252
|
+
}, error);
|
|
1253
|
+
this.logger.trackException(mastraError);
|
|
1254
|
+
this.logger.error(mastraError.toString());
|
|
1255
|
+
throw mastraError;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
async saveThread({ thread }) {
|
|
1259
|
+
try {
|
|
1260
|
+
await this.db.insert({
|
|
1261
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1262
|
+
record: thread
|
|
1263
|
+
});
|
|
1264
|
+
return thread;
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
const mastraError = new _mastra_core_error.MastraError({
|
|
1267
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SAVE_THREAD", "FAILED"),
|
|
1268
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1269
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1270
|
+
details: { threadId: thread.id }
|
|
1271
|
+
}, error);
|
|
1272
|
+
this.logger.trackException(mastraError);
|
|
1273
|
+
this.logger.error(mastraError.toString());
|
|
1274
|
+
throw mastraError;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
async updateThread({ id, title, metadata }) {
|
|
1278
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
1279
|
+
if (!thread) throw new _mastra_core_error.MastraError({
|
|
1280
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "UPDATE_THREAD", "FAILED"),
|
|
1281
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1282
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1283
|
+
text: `Thread ${id} not found`,
|
|
1284
|
+
details: { threadId: id }
|
|
1285
|
+
});
|
|
1286
|
+
const updatedThread = {
|
|
1287
|
+
...thread,
|
|
1288
|
+
title: title ?? thread.title,
|
|
1289
|
+
metadata: {
|
|
1290
|
+
...thread.metadata,
|
|
1291
|
+
...metadata
|
|
1292
|
+
},
|
|
1293
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1294
|
+
};
|
|
1295
|
+
try {
|
|
1296
|
+
await this.saveThread({ thread: updatedThread });
|
|
1297
|
+
return updatedThread;
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
throw new _mastra_core_error.MastraError({
|
|
1300
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "UPDATE_THREAD", "FAILED"),
|
|
1301
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1302
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1303
|
+
details: { threadId: id }
|
|
1304
|
+
}, error);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
async deleteThread({ threadId }) {
|
|
1308
|
+
try {
|
|
1309
|
+
const entries = await this.db.listAllEntries({
|
|
1310
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1311
|
+
keyPrefix: threadMessagesPrefix(threadId)
|
|
1312
|
+
});
|
|
1313
|
+
const keysToDelete = [...entries.map((entry) => entry.key), ...entries.map((entry) => getMessageIndexKey(entry.value.id))];
|
|
1314
|
+
await this.db.deleteMany({
|
|
1315
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1316
|
+
keys: keysToDelete
|
|
1317
|
+
});
|
|
1318
|
+
await this.db.delete({
|
|
1319
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1320
|
+
key: getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId })
|
|
1321
|
+
});
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
throw new _mastra_core_error.MastraError({
|
|
1324
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "DELETE_THREAD", "FAILED"),
|
|
1325
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1326
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1327
|
+
details: { threadId }
|
|
1328
|
+
}, error);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
async saveMessages(args) {
|
|
1332
|
+
const { messages } = args;
|
|
1333
|
+
if (messages.length === 0) return { messages: [] };
|
|
1334
|
+
const threadId = messages[0]?.threadId;
|
|
1335
|
+
let existingThread = null;
|
|
1336
|
+
try {
|
|
1337
|
+
if (!threadId) throw new Error("Thread ID is required");
|
|
1338
|
+
existingThread = await this.getThreadById({ threadId });
|
|
1339
|
+
if (!existingThread) throw new Error(`Thread ${threadId} not found`);
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
throw new _mastra_core_error.MastraError({
|
|
1342
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SAVE_MESSAGES", "INVALID_ARGS"),
|
|
1343
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1344
|
+
category: _mastra_core_error.ErrorCategory.USER
|
|
1345
|
+
}, error);
|
|
1346
|
+
}
|
|
1347
|
+
const messagesWithIndex = messages.map((message, index) => {
|
|
1348
|
+
if (!message.threadId) throw new Error(`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`);
|
|
1349
|
+
if (!message.resourceId) throw new Error(`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`);
|
|
1350
|
+
return {
|
|
1351
|
+
...message,
|
|
1352
|
+
_index: index
|
|
1353
|
+
};
|
|
1354
|
+
});
|
|
1355
|
+
try {
|
|
1356
|
+
const keysToDelete = [];
|
|
1357
|
+
const entries = [];
|
|
1358
|
+
for (const message of messagesWithIndex) {
|
|
1359
|
+
const existingIndex = await this.db.getByKey({
|
|
1360
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1361
|
+
key: getMessageIndexKey(message.id)
|
|
1362
|
+
});
|
|
1363
|
+
if (existingIndex?.threadId && existingIndex.threadId !== message.threadId) keysToDelete.push(getMessageKey(existingIndex.threadId, message.id));
|
|
1364
|
+
entries.push({
|
|
1365
|
+
key: getMessageKey(message.threadId, message.id),
|
|
1366
|
+
value: message
|
|
1367
|
+
});
|
|
1368
|
+
entries.push({
|
|
1369
|
+
key: getMessageIndexKey(message.id),
|
|
1370
|
+
value: { threadId: message.threadId }
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
await this.db.deleteMany({
|
|
1374
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1375
|
+
keys: keysToDelete
|
|
1376
|
+
});
|
|
1377
|
+
await this.db.bulkSet({
|
|
1378
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1379
|
+
entries
|
|
1380
|
+
});
|
|
1381
|
+
const updatedThread = {
|
|
1382
|
+
...existingThread,
|
|
1383
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1384
|
+
};
|
|
1385
|
+
await this.db.insert({
|
|
1386
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1387
|
+
record: updatedThread
|
|
1388
|
+
});
|
|
1389
|
+
return { messages: new _mastra_core_agent.MessageList().add(messages, "memory").get.all.db() };
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
throw new _mastra_core_error.MastraError({
|
|
1392
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SAVE_MESSAGES", "FAILED"),
|
|
1393
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1394
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1395
|
+
details: { threadId }
|
|
1396
|
+
}, error);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Returns all messages that belong to a thread, sorted in insertion order
|
|
1401
|
+
* (createdAt with `_index` tiebreaker).
|
|
1402
|
+
*/
|
|
1403
|
+
async listThreadMessages(threadId) {
|
|
1404
|
+
return (await this.db.listAll({
|
|
1405
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1406
|
+
keyPrefix: threadMessagesPrefix(threadId)
|
|
1407
|
+
})).sort((a, b) => getMessageScore(a) - getMessageScore(b));
|
|
1408
|
+
}
|
|
1409
|
+
/** Returns all message documents across all threads (excludes index docs). */
|
|
1410
|
+
async listAllMessages() {
|
|
1411
|
+
return this.db.listAll({
|
|
1412
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1413
|
+
keyPrefix: `${_mastra_core_storage.TABLE_MESSAGES}:threadId:`
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
async getThreadIdForMessage(messageId) {
|
|
1417
|
+
const indexed = await this.db.getByKey({
|
|
1418
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1419
|
+
key: getMessageIndexKey(messageId)
|
|
1420
|
+
});
|
|
1421
|
+
if (indexed?.threadId) return indexed.threadId;
|
|
1422
|
+
const message = (await this.listAllMessages()).find((msg) => msg.id === messageId);
|
|
1423
|
+
if (!message) return null;
|
|
1424
|
+
if (message.threadId) await this.db.set({
|
|
1425
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1426
|
+
key: getMessageIndexKey(messageId),
|
|
1427
|
+
value: { threadId: message.threadId }
|
|
1428
|
+
});
|
|
1429
|
+
return message.threadId || null;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Fetches the messages named by `include` together with their surrounding context.
|
|
1433
|
+
*
|
|
1434
|
+
* @param include - Message ids to pin, each with an optional before/after window.
|
|
1435
|
+
* @param resourceId - When set, drops any pinned or context message owned by another
|
|
1436
|
+
* resource so an id from another resource returns nothing.
|
|
1437
|
+
*/
|
|
1438
|
+
async getIncludedMessages(include, resourceId) {
|
|
1439
|
+
if (!include?.length) return [];
|
|
1440
|
+
const messagesById = /* @__PURE__ */ new Map();
|
|
1441
|
+
for (const item of include) {
|
|
1442
|
+
const itemThreadId = await this.getThreadIdForMessage(item.id);
|
|
1443
|
+
if (!itemThreadId) continue;
|
|
1444
|
+
let threadMessages = await this.listThreadMessages(itemThreadId);
|
|
1445
|
+
if (resourceId !== void 0) threadMessages = threadMessages.filter((message) => message.resourceId === resourceId);
|
|
1446
|
+
const targetIndex = threadMessages.findIndex((message) => message.id === item.id);
|
|
1447
|
+
if (targetIndex === -1) continue;
|
|
1448
|
+
const start = Math.max(0, targetIndex - (item.withPreviousMessages ?? 0));
|
|
1449
|
+
const end = Math.min(threadMessages.length, targetIndex + (item.withNextMessages ?? 0) + 1);
|
|
1450
|
+
for (const message of threadMessages.slice(start, end)) messagesById.set(message.id, message);
|
|
1451
|
+
}
|
|
1452
|
+
return Array.from(messagesById.values());
|
|
1453
|
+
}
|
|
1454
|
+
parseStoredMessage(storedMessage) {
|
|
1455
|
+
const defaultMessageContent = {
|
|
1456
|
+
format: 2,
|
|
1457
|
+
parts: [{
|
|
1458
|
+
type: "text",
|
|
1459
|
+
text: ""
|
|
1460
|
+
}]
|
|
1461
|
+
};
|
|
1462
|
+
const { _index, ...rest } = storedMessage;
|
|
1463
|
+
return {
|
|
1464
|
+
...rest,
|
|
1465
|
+
createdAt: new Date(rest.createdAt),
|
|
1466
|
+
content: rest.content || defaultMessageContent
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
async listMessagesById({ messageIds }) {
|
|
1470
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1471
|
+
try {
|
|
1472
|
+
const rawMessages = [];
|
|
1473
|
+
const unindexedIds = [];
|
|
1474
|
+
for (const id of messageIds) {
|
|
1475
|
+
const indexed = await this.db.getByKey({
|
|
1476
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1477
|
+
key: getMessageIndexKey(id)
|
|
1478
|
+
});
|
|
1479
|
+
if (!indexed?.threadId) {
|
|
1480
|
+
unindexedIds.push(id);
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
const message = await this.db.getByKey({
|
|
1484
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1485
|
+
key: getMessageKey(indexed.threadId, id)
|
|
1486
|
+
});
|
|
1487
|
+
if (message) rawMessages.push(message);
|
|
1488
|
+
else unindexedIds.push(id);
|
|
1489
|
+
}
|
|
1490
|
+
if (unindexedIds.length > 0) {
|
|
1491
|
+
const allMessages = await this.listAllMessages();
|
|
1492
|
+
const unindexedSet = new Set(unindexedIds);
|
|
1493
|
+
const foundMessages = allMessages.filter((msg) => unindexedSet.has(msg.id));
|
|
1494
|
+
rawMessages.push(...foundMessages);
|
|
1495
|
+
if (foundMessages.length > 0) await this.db.bulkSet({
|
|
1496
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1497
|
+
entries: foundMessages.filter((msg) => msg.threadId).map((msg) => ({
|
|
1498
|
+
key: getMessageIndexKey(msg.id),
|
|
1499
|
+
value: { threadId: msg.threadId }
|
|
1500
|
+
}))
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
return { messages: new _mastra_core_agent.MessageList().add(rawMessages.map(this.parseStoredMessage), "memory").get.all.db() };
|
|
1504
|
+
} catch (error) {
|
|
1505
|
+
throw new _mastra_core_error.MastraError({
|
|
1506
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1507
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1508
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1509
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1510
|
+
}, error);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
async listMessages(args) {
|
|
1514
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1515
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
1516
|
+
const threadIdsSet = new Set(threadIds);
|
|
1517
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) throw new _mastra_core_error.MastraError({
|
|
1518
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1519
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1520
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1521
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1522
|
+
}, /* @__PURE__ */ new Error("threadId must be a non-empty string or array of non-empty strings"));
|
|
1523
|
+
const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 40);
|
|
1524
|
+
const { offset, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
|
|
1525
|
+
const metadataFilter = (0, _mastra_core_storage.validateStorageMetadataFilter)(filter?.metadata);
|
|
1526
|
+
try {
|
|
1527
|
+
if (page < 0) throw new _mastra_core_error.MastraError({
|
|
1528
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
1529
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1530
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1531
|
+
details: { page }
|
|
1532
|
+
}, /* @__PURE__ */ new Error("page must be >= 0"));
|
|
1533
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1534
|
+
const getFieldValue = (msg) => {
|
|
1535
|
+
if (field === "createdAt") return new Date(msg.createdAt).getTime();
|
|
1536
|
+
const value = msg[field];
|
|
1537
|
+
if (typeof value === "number") return value;
|
|
1538
|
+
if (value instanceof Date) return value.getTime();
|
|
1539
|
+
return 0;
|
|
1540
|
+
};
|
|
1541
|
+
if (perPage === 0 && (!include || include.length === 0)) return {
|
|
1542
|
+
messages: [],
|
|
1543
|
+
total: 0,
|
|
1544
|
+
page,
|
|
1545
|
+
perPage: perPageForResponse,
|
|
1546
|
+
hasMore: false
|
|
1547
|
+
};
|
|
1548
|
+
let includedMessages = [];
|
|
1549
|
+
if (include && include.length > 0) includedMessages = (await this.getIncludedMessages(include, resourceId)).map(this.parseStoredMessage);
|
|
1550
|
+
if (perPage === 0 && include && include.length > 0) return {
|
|
1551
|
+
messages: new _mastra_core_agent.MessageList().add(includedMessages, "memory").get.all.db().sort((a, b) => {
|
|
1552
|
+
const aValue = getFieldValue(a);
|
|
1553
|
+
const bValue = getFieldValue(b);
|
|
1554
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1555
|
+
}),
|
|
1556
|
+
total: 0,
|
|
1557
|
+
page,
|
|
1558
|
+
perPage: perPageForResponse,
|
|
1559
|
+
hasMore: false
|
|
1560
|
+
};
|
|
1561
|
+
let messagesData = [];
|
|
1562
|
+
for (const tid of threadIds) {
|
|
1563
|
+
const threadMessages = await this.listThreadMessages(tid);
|
|
1564
|
+
messagesData.push(...threadMessages.map(this.parseStoredMessage));
|
|
1565
|
+
}
|
|
1566
|
+
if (messagesData.length === 0) return {
|
|
1567
|
+
messages: [],
|
|
1568
|
+
total: 0,
|
|
1569
|
+
page,
|
|
1570
|
+
perPage: perPageForResponse,
|
|
1571
|
+
hasMore: false
|
|
1572
|
+
};
|
|
1573
|
+
if (resourceId) messagesData = messagesData.filter((msg) => msg.resourceId === resourceId);
|
|
1574
|
+
messagesData = (0, _mastra_core_storage.filterByDateRange)(messagesData, (msg) => new Date(msg.createdAt), filter?.dateRange);
|
|
1575
|
+
messagesData = messagesData.filter((message) => (0, _mastra_core_storage.storageMessageMatchesMetadataFilter)(message.content, metadataFilter));
|
|
1576
|
+
messagesData.sort((a, b) => {
|
|
1577
|
+
const aValue = getFieldValue(a);
|
|
1578
|
+
const bValue = getFieldValue(b);
|
|
1579
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1580
|
+
});
|
|
1581
|
+
const total = messagesData.length;
|
|
1582
|
+
const start = offset;
|
|
1583
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1584
|
+
const paginatedMessages = messagesData.slice(start, end);
|
|
1585
|
+
const messageIdsSet = /* @__PURE__ */ new Set();
|
|
1586
|
+
const allMessages = [];
|
|
1587
|
+
for (const msg of paginatedMessages) {
|
|
1588
|
+
if (messageIdsSet.has(msg.id)) continue;
|
|
1589
|
+
allMessages.push(msg);
|
|
1590
|
+
messageIdsSet.add(msg.id);
|
|
1591
|
+
}
|
|
1592
|
+
for (const msg of includedMessages) {
|
|
1593
|
+
if (messageIdsSet.has(msg.id)) continue;
|
|
1594
|
+
allMessages.push(msg);
|
|
1595
|
+
messageIdsSet.add(msg.id);
|
|
1596
|
+
}
|
|
1597
|
+
let finalMessages = new _mastra_core_agent.MessageList().add(allMessages, "memory").get.all.db();
|
|
1598
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
1599
|
+
const aValue = getFieldValue(a);
|
|
1600
|
+
const bValue = getFieldValue(b);
|
|
1601
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1602
|
+
});
|
|
1603
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((message) => message.threadId && threadIdsSet.has(message.threadId)).map((message) => message.id));
|
|
1604
|
+
const hasMore = perPageInput !== false && (metadataFilter || returnedThreadMessageIds.size < total) && offset + paginatedMessages.length < total;
|
|
1605
|
+
return {
|
|
1606
|
+
messages: finalMessages,
|
|
1607
|
+
total,
|
|
1608
|
+
page,
|
|
1609
|
+
perPage: perPageForResponse,
|
|
1610
|
+
hasMore
|
|
1611
|
+
};
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
if (error instanceof _mastra_core_error.MastraError && error.category === _mastra_core_error.ErrorCategory.USER) throw error;
|
|
1614
|
+
const mastraError = new _mastra_core_error.MastraError({
|
|
1615
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_MESSAGES", "FAILED"),
|
|
1616
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1617
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1618
|
+
details: {
|
|
1619
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
1620
|
+
resourceId: resourceId ?? ""
|
|
1621
|
+
}
|
|
1622
|
+
}, error);
|
|
1623
|
+
this.logger.error(mastraError.toString());
|
|
1624
|
+
this.logger.trackException(mastraError);
|
|
1625
|
+
throw mastraError;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
async getResourceById({ resourceId }) {
|
|
1629
|
+
try {
|
|
1630
|
+
const resource = await this.db.getByKey({
|
|
1631
|
+
tableName: _mastra_core_storage.TABLE_RESOURCES,
|
|
1632
|
+
key: `${_mastra_core_storage.TABLE_RESOURCES}:${resourceId}`
|
|
1633
|
+
});
|
|
1634
|
+
if (!resource) return null;
|
|
1635
|
+
return {
|
|
1636
|
+
...resource,
|
|
1637
|
+
createdAt: new Date(resource.createdAt),
|
|
1638
|
+
updatedAt: new Date(resource.updatedAt),
|
|
1639
|
+
workingMemory: typeof resource.workingMemory === "object" ? JSON.stringify(resource.workingMemory) : resource.workingMemory,
|
|
1640
|
+
metadata: typeof resource.metadata === "string" ? JSON.parse(resource.metadata) : resource.metadata
|
|
1641
|
+
};
|
|
1642
|
+
} catch (error) {
|
|
1643
|
+
this.logger.error("Error getting resource by ID:", error);
|
|
1644
|
+
throw error;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
async saveResource({ resource }) {
|
|
1648
|
+
try {
|
|
1649
|
+
const serializedResource = {
|
|
1650
|
+
...resource,
|
|
1651
|
+
metadata: JSON.stringify(resource.metadata),
|
|
1652
|
+
createdAt: resource.createdAt.toISOString(),
|
|
1653
|
+
updatedAt: resource.updatedAt.toISOString()
|
|
1654
|
+
};
|
|
1655
|
+
await this.db.set({
|
|
1656
|
+
tableName: _mastra_core_storage.TABLE_RESOURCES,
|
|
1657
|
+
key: `${_mastra_core_storage.TABLE_RESOURCES}:${resource.id}`,
|
|
1658
|
+
value: serializedResource
|
|
1659
|
+
});
|
|
1660
|
+
return resource;
|
|
1661
|
+
} catch (error) {
|
|
1662
|
+
this.logger.error("Error saving resource:", error);
|
|
1663
|
+
throw error;
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
async updateResource({ resourceId, workingMemory, metadata }) {
|
|
1667
|
+
try {
|
|
1668
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1669
|
+
if (!existingResource) {
|
|
1670
|
+
const newResource = {
|
|
1671
|
+
id: resourceId,
|
|
1672
|
+
workingMemory,
|
|
1673
|
+
metadata: metadata || {},
|
|
1674
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1675
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1676
|
+
};
|
|
1677
|
+
return this.saveResource({ resource: newResource });
|
|
1678
|
+
}
|
|
1679
|
+
const updatedResource = {
|
|
1680
|
+
...existingResource,
|
|
1681
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1682
|
+
metadata: {
|
|
1683
|
+
...existingResource.metadata,
|
|
1684
|
+
...metadata
|
|
1685
|
+
},
|
|
1686
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1687
|
+
};
|
|
1688
|
+
await this.saveResource({ resource: updatedResource });
|
|
1689
|
+
return updatedResource;
|
|
1690
|
+
} catch (error) {
|
|
1691
|
+
this.logger.error("Error updating resource:", error);
|
|
1692
|
+
throw error;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
async updateMessages(args) {
|
|
1696
|
+
const { messages } = args;
|
|
1697
|
+
if (messages.length === 0) return [];
|
|
1698
|
+
try {
|
|
1699
|
+
const messageIds = messages.map((m) => m.id);
|
|
1700
|
+
const allMessages = await this.listAllMessages();
|
|
1701
|
+
const existingMessages = [];
|
|
1702
|
+
const messageIdToKey = {};
|
|
1703
|
+
for (const messageId of messageIds) {
|
|
1704
|
+
const message = allMessages.find((msg) => msg.id === messageId);
|
|
1705
|
+
if (message?.threadId) {
|
|
1706
|
+
existingMessages.push(message);
|
|
1707
|
+
messageIdToKey[messageId] = getMessageKey(message.threadId, messageId);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
if (existingMessages.length === 0) return [];
|
|
1711
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1712
|
+
const keysToDelete = [];
|
|
1713
|
+
const entries = [];
|
|
1714
|
+
for (const existingMessage of existingMessages) {
|
|
1715
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1716
|
+
if (!updatePayload) continue;
|
|
1717
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1718
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1719
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1720
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) threadIdsToUpdate.add(updatePayload.threadId);
|
|
1721
|
+
const updatedMessage = { ...existingMessage };
|
|
1722
|
+
if (fieldsToUpdate.content) {
|
|
1723
|
+
const existingContent = existingMessage.content;
|
|
1724
|
+
updatedMessage.content = {
|
|
1725
|
+
...existingContent,
|
|
1726
|
+
...fieldsToUpdate.content,
|
|
1727
|
+
...existingContent?.metadata && fieldsToUpdate.content.metadata ? { metadata: {
|
|
1728
|
+
...existingContent.metadata,
|
|
1729
|
+
...fieldsToUpdate.content.metadata
|
|
1730
|
+
} } : {}
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
for (const key in fieldsToUpdate) if (Object.prototype.hasOwnProperty.call(fieldsToUpdate, key) && key !== "content") updatedMessage[key] = fieldsToUpdate[key];
|
|
1734
|
+
const key = messageIdToKey[id];
|
|
1735
|
+
if (!key) continue;
|
|
1736
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1737
|
+
keysToDelete.push(key);
|
|
1738
|
+
const newKey = getMessageKey(updatePayload.threadId, id);
|
|
1739
|
+
entries.push({
|
|
1740
|
+
key: newKey,
|
|
1741
|
+
value: updatedMessage
|
|
1742
|
+
});
|
|
1743
|
+
entries.push({
|
|
1744
|
+
key: getMessageIndexKey(id),
|
|
1745
|
+
value: { threadId: updatePayload.threadId }
|
|
1746
|
+
});
|
|
1747
|
+
messageIdToKey[id] = newKey;
|
|
1748
|
+
continue;
|
|
1749
|
+
}
|
|
1750
|
+
entries.push({
|
|
1751
|
+
key,
|
|
1752
|
+
value: updatedMessage
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
const now = /* @__PURE__ */ new Date();
|
|
1756
|
+
const threadEntries = [];
|
|
1757
|
+
for (const threadId of threadIdsToUpdate) if (threadId) {
|
|
1758
|
+
const existingThread = await this.db.get({
|
|
1759
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1760
|
+
keys: { id: threadId }
|
|
1761
|
+
});
|
|
1762
|
+
if (existingThread) {
|
|
1763
|
+
const updatedThread = {
|
|
1764
|
+
...existingThread,
|
|
1765
|
+
updatedAt: now
|
|
1766
|
+
};
|
|
1767
|
+
threadEntries.push({
|
|
1768
|
+
key: getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId }),
|
|
1769
|
+
value: processRecord(_mastra_core_storage.TABLE_THREADS, updatedThread).processedRecord
|
|
1770
|
+
});
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
await this.db.deleteMany({
|
|
1774
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1775
|
+
keys: keysToDelete
|
|
1776
|
+
});
|
|
1777
|
+
await this.db.bulkSet({
|
|
1778
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1779
|
+
entries
|
|
1780
|
+
});
|
|
1781
|
+
await this.db.bulkSet({
|
|
1782
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1783
|
+
entries: threadEntries
|
|
1784
|
+
});
|
|
1785
|
+
const updatedMessages = [];
|
|
1786
|
+
for (const messageId of messageIds) {
|
|
1787
|
+
const key = messageIdToKey[messageId];
|
|
1788
|
+
if (key) {
|
|
1789
|
+
const message = await this.db.getByKey({
|
|
1790
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1791
|
+
key
|
|
1792
|
+
});
|
|
1793
|
+
if (message) updatedMessages.push(message);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
return updatedMessages;
|
|
1797
|
+
} catch (error) {
|
|
1798
|
+
throw new _mastra_core_error.MastraError({
|
|
1799
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "UPDATE_MESSAGES", "FAILED"),
|
|
1800
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1801
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1802
|
+
details: { messageIds: messages.map((m) => m.id).join(",") }
|
|
1803
|
+
}, error);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
async deleteMessages(messageIds) {
|
|
1807
|
+
if (!messageIds || messageIds.length === 0) return;
|
|
1808
|
+
try {
|
|
1809
|
+
const allMessages = await this.listAllMessages();
|
|
1810
|
+
const idsToDelete = new Set(messageIds);
|
|
1811
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
1812
|
+
const keysToDelete = [];
|
|
1813
|
+
for (const message of allMessages) {
|
|
1814
|
+
if (!idsToDelete.has(message.id) || !message.threadId) continue;
|
|
1815
|
+
keysToDelete.push(getMessageKey(message.threadId, message.id));
|
|
1816
|
+
keysToDelete.push(getMessageIndexKey(message.id));
|
|
1817
|
+
threadIds.add(message.threadId);
|
|
1818
|
+
}
|
|
1819
|
+
if (keysToDelete.length === 0) return;
|
|
1820
|
+
await this.db.deleteMany({
|
|
1821
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1822
|
+
keys: keysToDelete
|
|
1823
|
+
});
|
|
1824
|
+
const threadEntries = [];
|
|
1825
|
+
for (const threadId of threadIds) {
|
|
1826
|
+
const thread = await this.db.get({
|
|
1827
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1828
|
+
keys: { id: threadId }
|
|
1829
|
+
});
|
|
1830
|
+
if (!thread) continue;
|
|
1831
|
+
const updatedThread = {
|
|
1832
|
+
...thread,
|
|
1833
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1834
|
+
};
|
|
1835
|
+
threadEntries.push({
|
|
1836
|
+
key: getKey(_mastra_core_storage.TABLE_THREADS, { id: threadId }),
|
|
1837
|
+
value: processRecord(_mastra_core_storage.TABLE_THREADS, updatedThread).processedRecord
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
await this.db.bulkSet({
|
|
1841
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1842
|
+
entries: threadEntries
|
|
1843
|
+
});
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
throw new _mastra_core_error.MastraError({
|
|
1846
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "DELETE_MESSAGES", "FAILED"),
|
|
1847
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1848
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1849
|
+
details: { messageIds: messageIds.join(", ") }
|
|
1850
|
+
}, error);
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
sortThreads(threads, field, direction) {
|
|
1854
|
+
return threads.sort((a, b) => {
|
|
1855
|
+
const aValue = new Date(a[field]).getTime();
|
|
1856
|
+
const bValue = new Date(b[field]).getTime();
|
|
1857
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1860
|
+
async cloneThread(args) {
|
|
1861
|
+
const { sourceThreadId, newThreadId: providedThreadId, resourceId, title, metadata, options } = args;
|
|
1862
|
+
const sourceThread = await this.getThreadById({ threadId: sourceThreadId });
|
|
1863
|
+
if (!sourceThread) throw new _mastra_core_error.MastraError({
|
|
1864
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "CLONE_THREAD", "SOURCE_NOT_FOUND"),
|
|
1865
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1866
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1867
|
+
text: `Source thread with id ${sourceThreadId} not found`,
|
|
1868
|
+
details: { sourceThreadId }
|
|
1869
|
+
});
|
|
1870
|
+
const newThreadId = providedThreadId || crypto.randomUUID();
|
|
1871
|
+
if (await this.getThreadById({ threadId: newThreadId })) throw new _mastra_core_error.MastraError({
|
|
1872
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "CLONE_THREAD", "THREAD_EXISTS"),
|
|
1873
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1874
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
1875
|
+
text: `Thread with id ${newThreadId} already exists`,
|
|
1876
|
+
details: { newThreadId }
|
|
1877
|
+
});
|
|
1878
|
+
try {
|
|
1879
|
+
let sourceMessages = (await this.listThreadMessages(sourceThreadId)).map((msg) => ({
|
|
1880
|
+
...msg,
|
|
1881
|
+
createdAt: new Date(msg.createdAt)
|
|
1882
|
+
}));
|
|
1883
|
+
if (options?.messageFilter?.startDate || options?.messageFilter?.endDate) sourceMessages = (0, _mastra_core_storage.filterByDateRange)(sourceMessages, (msg) => new Date(msg.createdAt), {
|
|
1884
|
+
start: options.messageFilter?.startDate,
|
|
1885
|
+
end: options.messageFilter?.endDate
|
|
1886
|
+
});
|
|
1887
|
+
if (options?.messageFilter?.messageIds && options.messageFilter.messageIds.length > 0) {
|
|
1888
|
+
const messageIdSet = new Set(options.messageFilter.messageIds);
|
|
1889
|
+
sourceMessages = sourceMessages.filter((msg) => messageIdSet.has(msg.id));
|
|
1890
|
+
}
|
|
1891
|
+
sourceMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
1892
|
+
if (options?.messageLimit && options.messageLimit > 0 && sourceMessages.length > options.messageLimit) sourceMessages = sourceMessages.slice(-options.messageLimit);
|
|
1893
|
+
const now = /* @__PURE__ */ new Date();
|
|
1894
|
+
const lastMessageId = sourceMessages.length > 0 ? sourceMessages[sourceMessages.length - 1].id : void 0;
|
|
1895
|
+
const cloneMetadata = {
|
|
1896
|
+
sourceThreadId,
|
|
1897
|
+
clonedAt: now,
|
|
1898
|
+
...lastMessageId && { lastMessageId }
|
|
1899
|
+
};
|
|
1900
|
+
const newThread = {
|
|
1901
|
+
id: newThreadId,
|
|
1902
|
+
resourceId: resourceId || sourceThread.resourceId,
|
|
1903
|
+
title: title || (sourceThread.title ? `Clone of ${sourceThread.title}` : void 0),
|
|
1904
|
+
metadata: {
|
|
1905
|
+
...metadata,
|
|
1906
|
+
clone: cloneMetadata
|
|
1907
|
+
},
|
|
1908
|
+
createdAt: now,
|
|
1909
|
+
updatedAt: now
|
|
1910
|
+
};
|
|
1911
|
+
const clonedMessages = [];
|
|
1912
|
+
const targetResourceId = resourceId || sourceThread.resourceId;
|
|
1913
|
+
const entries = [];
|
|
1914
|
+
for (let i = 0; i < sourceMessages.length; i++) {
|
|
1915
|
+
const sourceMsg = sourceMessages[i];
|
|
1916
|
+
const newMessageId = crypto.randomUUID();
|
|
1917
|
+
const { _index, ...restMsg } = sourceMsg;
|
|
1918
|
+
const newMessage = {
|
|
1919
|
+
...restMsg,
|
|
1920
|
+
id: newMessageId,
|
|
1921
|
+
threadId: newThreadId,
|
|
1922
|
+
resourceId: targetResourceId
|
|
1923
|
+
};
|
|
1924
|
+
entries.push({
|
|
1925
|
+
key: getMessageKey(newThreadId, newMessageId),
|
|
1926
|
+
value: {
|
|
1927
|
+
...newMessage,
|
|
1928
|
+
_index: i
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
entries.push({
|
|
1932
|
+
key: getMessageIndexKey(newMessageId),
|
|
1933
|
+
value: { threadId: newThreadId }
|
|
1934
|
+
});
|
|
1935
|
+
clonedMessages.push(newMessage);
|
|
1936
|
+
}
|
|
1937
|
+
await this.db.insert({
|
|
1938
|
+
tableName: _mastra_core_storage.TABLE_THREADS,
|
|
1939
|
+
record: newThread
|
|
1940
|
+
});
|
|
1941
|
+
await this.db.bulkSet({
|
|
1942
|
+
tableName: _mastra_core_storage.TABLE_MESSAGES,
|
|
1943
|
+
entries
|
|
1944
|
+
});
|
|
1945
|
+
return {
|
|
1946
|
+
thread: newThread,
|
|
1947
|
+
clonedMessages
|
|
1948
|
+
};
|
|
1949
|
+
} catch (error) {
|
|
1950
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
1951
|
+
throw new _mastra_core_error.MastraError({
|
|
1952
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "CLONE_THREAD", "FAILED"),
|
|
1953
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
1954
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1955
|
+
details: {
|
|
1956
|
+
sourceThreadId,
|
|
1957
|
+
newThreadId
|
|
1958
|
+
}
|
|
1959
|
+
}, error);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
function threadMessagesPrefix(threadId) {
|
|
1964
|
+
return `${_mastra_core_storage.TABLE_MESSAGES}:threadId:${threadId}:id:`;
|
|
1965
|
+
}
|
|
1966
|
+
function getMessageKey(threadId, messageId) {
|
|
1967
|
+
return getKey(_mastra_core_storage.TABLE_MESSAGES, {
|
|
1968
|
+
threadId,
|
|
1969
|
+
id: messageId
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1972
|
+
function getMessageIndexKey(messageId) {
|
|
1973
|
+
return `msg-idx:${messageId}`;
|
|
1974
|
+
}
|
|
1975
|
+
function getMessageScore(message) {
|
|
1976
|
+
const createdAtScore = new Date(message.createdAt).getTime();
|
|
1977
|
+
const index = typeof message._index === "number" ? message._index : 0;
|
|
1978
|
+
return createdAtScore * 1e3 + index;
|
|
1979
|
+
}
|
|
1980
|
+
//#endregion
|
|
1981
|
+
//#region src/storage/domains/scores/index.ts
|
|
1982
|
+
/** Returns true when a row matches the multi-tenant scope filters (or none provided). */
|
|
1983
|
+
function matchesTenancy(row, filters) {
|
|
1984
|
+
if (filters?.organizationId !== void 0 && row.organizationId !== filters.organizationId) return false;
|
|
1985
|
+
if (filters?.projectId !== void 0 && row.projectId !== filters.projectId) return false;
|
|
1986
|
+
return true;
|
|
1987
|
+
}
|
|
1988
|
+
var ScoresElasticSearch = class extends _mastra_core_storage.ScoresStorage {
|
|
1989
|
+
db;
|
|
1990
|
+
constructor(config) {
|
|
1991
|
+
super();
|
|
1992
|
+
this.db = new ElasticSearchDB({ client: config.client });
|
|
1993
|
+
}
|
|
1994
|
+
async dangerouslyClearAll() {
|
|
1995
|
+
await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_SCORERS });
|
|
1996
|
+
}
|
|
1997
|
+
async getScoreById({ id }) {
|
|
1998
|
+
try {
|
|
1999
|
+
const data = await this.db.get({
|
|
2000
|
+
tableName: _mastra_core_storage.TABLE_SCORERS,
|
|
2001
|
+
keys: { id }
|
|
2002
|
+
});
|
|
2003
|
+
if (!data) return null;
|
|
2004
|
+
return (0, _mastra_core_storage.transformScoreRow)(data);
|
|
2005
|
+
} catch (error) {
|
|
2006
|
+
throw new _mastra_core_error.MastraError({
|
|
2007
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "GET_SCORE_BY_ID", "FAILED"),
|
|
2008
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2009
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2010
|
+
details: { ...id && { id } }
|
|
2011
|
+
}, error);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
async listScoresByScorerId({ scorerId, entityId, entityType, source, pagination = {
|
|
2015
|
+
page: 0,
|
|
2016
|
+
perPage: 20
|
|
2017
|
+
}, filters }) {
|
|
2018
|
+
return this.fetchAndFilterScores(pagination, (row) => {
|
|
2019
|
+
if (row.scorerId !== scorerId) return false;
|
|
2020
|
+
if (entityId && row.entityId !== entityId) return false;
|
|
2021
|
+
if (entityType && row.entityType !== entityType) return false;
|
|
2022
|
+
if (source && row.source !== source) return false;
|
|
2023
|
+
if (!matchesTenancy(row, filters)) return false;
|
|
2024
|
+
return true;
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
async saveScore(score) {
|
|
2028
|
+
let validatedScore;
|
|
2029
|
+
try {
|
|
2030
|
+
validatedScore = _mastra_core_evals.saveScorePayloadSchema.parse(score);
|
|
2031
|
+
} catch (error) {
|
|
2032
|
+
throw new _mastra_core_error.MastraError({
|
|
2033
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
2034
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2035
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
2036
|
+
details: {
|
|
2037
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
2038
|
+
entityId: score.entityId ?? "unknown",
|
|
2039
|
+
entityType: score.entityType ?? "unknown",
|
|
2040
|
+
traceId: score.traceId ?? "",
|
|
2041
|
+
spanId: score.spanId ?? ""
|
|
2042
|
+
}
|
|
2043
|
+
}, error);
|
|
2044
|
+
}
|
|
2045
|
+
const now = /* @__PURE__ */ new Date();
|
|
2046
|
+
const id = crypto$1.default.randomUUID();
|
|
2047
|
+
const { key, processedRecord } = processRecord(_mastra_core_storage.TABLE_SCORERS, {
|
|
2048
|
+
...validatedScore,
|
|
2049
|
+
id,
|
|
2050
|
+
createdAt: now,
|
|
2051
|
+
updatedAt: now
|
|
2052
|
+
});
|
|
2053
|
+
try {
|
|
2054
|
+
await this.db.set({
|
|
2055
|
+
tableName: _mastra_core_storage.TABLE_SCORERS,
|
|
2056
|
+
key,
|
|
2057
|
+
value: processedRecord
|
|
2058
|
+
});
|
|
2059
|
+
return { score: {
|
|
2060
|
+
...validatedScore,
|
|
2061
|
+
id,
|
|
2062
|
+
createdAt: now,
|
|
2063
|
+
updatedAt: now
|
|
2064
|
+
} };
|
|
2065
|
+
} catch (error) {
|
|
2066
|
+
throw new _mastra_core_error.MastraError({
|
|
2067
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "SAVE_SCORE", "FAILED"),
|
|
2068
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2069
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2070
|
+
details: { id }
|
|
2071
|
+
}, error);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
async listScoresByRunId({ runId, pagination = {
|
|
2075
|
+
page: 0,
|
|
2076
|
+
perPage: 20
|
|
2077
|
+
}, filters }) {
|
|
2078
|
+
return this.fetchAndFilterScores(pagination, (row) => row.runId === runId && matchesTenancy(row, filters));
|
|
2079
|
+
}
|
|
2080
|
+
async listScoresByEntityId({ entityId, entityType, pagination = {
|
|
2081
|
+
page: 0,
|
|
2082
|
+
perPage: 20
|
|
2083
|
+
}, filters }) {
|
|
2084
|
+
return this.fetchAndFilterScores(pagination, (row) => {
|
|
2085
|
+
if (row.entityId !== entityId) return false;
|
|
2086
|
+
if (entityType && row.entityType !== entityType) return false;
|
|
2087
|
+
if (!matchesTenancy(row, filters)) return false;
|
|
2088
|
+
return true;
|
|
2089
|
+
});
|
|
2090
|
+
}
|
|
2091
|
+
async listScoresBySpan({ traceId, spanId, pagination = {
|
|
2092
|
+
page: 0,
|
|
2093
|
+
perPage: 20
|
|
2094
|
+
}, filters }) {
|
|
2095
|
+
return this.fetchAndFilterScores(pagination, (row) => row.traceId === traceId && row.spanId === spanId && matchesTenancy(row, filters));
|
|
2096
|
+
}
|
|
2097
|
+
async fetchAndFilterScores(pagination, filterFn) {
|
|
2098
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2099
|
+
const filtered = (await this.db.listAll({ tableName: _mastra_core_storage.TABLE_SCORERS })).filter((row) => !!row && typeof row === "object" && filterFn(row));
|
|
2100
|
+
const total = filtered.length;
|
|
2101
|
+
const perPage = (0, _mastra_core_storage.normalizePerPage)(perPageInput, 100);
|
|
2102
|
+
const { offset: start, perPage: perPageForResponse } = (0, _mastra_core_storage.calculatePagination)(page, perPageInput, perPage);
|
|
2103
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
2104
|
+
return {
|
|
2105
|
+
scores: filtered.slice(start, end).map((row) => (0, _mastra_core_storage.transformScoreRow)(row)),
|
|
2106
|
+
pagination: {
|
|
2107
|
+
total,
|
|
2108
|
+
page,
|
|
2109
|
+
perPage: perPageForResponse,
|
|
2110
|
+
hasMore: end < total
|
|
2111
|
+
}
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
//#endregion
|
|
2116
|
+
//#region src/storage/domains/workflows/index.ts
|
|
2117
|
+
function parseWorkflowRun(row) {
|
|
2118
|
+
let parsedSnapshot = row.snapshot;
|
|
2119
|
+
if (typeof parsedSnapshot === "string") try {
|
|
2120
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2121
|
+
} catch (e) {
|
|
2122
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2123
|
+
}
|
|
2124
|
+
return {
|
|
2125
|
+
workflowName: row.workflow_name,
|
|
2126
|
+
runId: row.run_id,
|
|
2127
|
+
snapshot: parsedSnapshot,
|
|
2128
|
+
createdAt: (0, _mastra_core_storage.ensureDate)(row.createdAt),
|
|
2129
|
+
updatedAt: (0, _mastra_core_storage.ensureDate)(row.updatedAt),
|
|
2130
|
+
resourceId: row.resourceId
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
var WorkflowsElasticSearch = class extends _mastra_core_storage.WorkflowsStorage {
|
|
2134
|
+
db;
|
|
2135
|
+
constructor(config) {
|
|
2136
|
+
super();
|
|
2137
|
+
this.db = new ElasticSearchDB({ client: config.client });
|
|
2138
|
+
}
|
|
2139
|
+
supportsConcurrentUpdates() {
|
|
2140
|
+
return false;
|
|
2141
|
+
}
|
|
2142
|
+
async dangerouslyClearAll() {
|
|
2143
|
+
await this.db.deleteData({ tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
2144
|
+
}
|
|
2145
|
+
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext }) {
|
|
2146
|
+
try {
|
|
2147
|
+
const existingRecord = await this.db.get({
|
|
2148
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2149
|
+
keys: {
|
|
2150
|
+
namespace: "workflows",
|
|
2151
|
+
workflow_name: workflowName,
|
|
2152
|
+
run_id: runId
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
let snapshot = existingRecord?.snapshot;
|
|
2156
|
+
if (!snapshot) snapshot = {
|
|
2157
|
+
context: {},
|
|
2158
|
+
activePaths: [],
|
|
2159
|
+
timestamp: Date.now(),
|
|
2160
|
+
suspendedPaths: {},
|
|
2161
|
+
activeStepsPath: {},
|
|
2162
|
+
resumeLabels: {},
|
|
2163
|
+
serializedStepGraph: [],
|
|
2164
|
+
status: "pending",
|
|
2165
|
+
value: {},
|
|
2166
|
+
waitingPaths: {},
|
|
2167
|
+
runId,
|
|
2168
|
+
requestContext: {}
|
|
2169
|
+
};
|
|
2170
|
+
snapshot.context[stepId] = result;
|
|
2171
|
+
snapshot.requestContext = {
|
|
2172
|
+
...snapshot.requestContext,
|
|
2173
|
+
...requestContext
|
|
2174
|
+
};
|
|
2175
|
+
await this.persistWorkflowSnapshot({
|
|
2176
|
+
namespace: "workflows",
|
|
2177
|
+
workflowName,
|
|
2178
|
+
runId,
|
|
2179
|
+
snapshot,
|
|
2180
|
+
createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
|
|
2181
|
+
});
|
|
2182
|
+
return snapshot.context;
|
|
2183
|
+
} catch (error) {
|
|
2184
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
2185
|
+
throw new _mastra_core_error.MastraError({
|
|
2186
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
2187
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2188
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2189
|
+
details: {
|
|
2190
|
+
workflowName,
|
|
2191
|
+
runId,
|
|
2192
|
+
stepId
|
|
2193
|
+
}
|
|
2194
|
+
}, error);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
async updateWorkflowState({ workflowName, runId, opts }) {
|
|
2198
|
+
try {
|
|
2199
|
+
const existingRecord = await this.db.get({
|
|
2200
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2201
|
+
keys: {
|
|
2202
|
+
namespace: "workflows",
|
|
2203
|
+
workflow_name: workflowName,
|
|
2204
|
+
run_id: runId
|
|
2205
|
+
}
|
|
2206
|
+
});
|
|
2207
|
+
const existingSnapshot = existingRecord?.snapshot;
|
|
2208
|
+
if (!existingSnapshot || !existingSnapshot.context) return;
|
|
2209
|
+
const { expectedStatus, ...state } = opts;
|
|
2210
|
+
if (!(0, _mastra_core_storage.matchesExpectedWorkflowStatus)(existingSnapshot.status, expectedStatus)) return;
|
|
2211
|
+
const updatedSnapshot = {
|
|
2212
|
+
...existingSnapshot,
|
|
2213
|
+
...state
|
|
2214
|
+
};
|
|
2215
|
+
await this.persistWorkflowSnapshot({
|
|
2216
|
+
namespace: "workflows",
|
|
2217
|
+
workflowName,
|
|
2218
|
+
runId,
|
|
2219
|
+
snapshot: updatedSnapshot,
|
|
2220
|
+
createdAt: existingRecord?.createdAt ? (0, _mastra_core_storage.ensureDate)(existingRecord.createdAt) : void 0
|
|
2221
|
+
});
|
|
2222
|
+
return updatedSnapshot;
|
|
2223
|
+
} catch (error) {
|
|
2224
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
2225
|
+
throw new _mastra_core_error.MastraError({
|
|
2226
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
2227
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2228
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2229
|
+
details: {
|
|
2230
|
+
workflowName,
|
|
2231
|
+
runId
|
|
2232
|
+
}
|
|
2233
|
+
}, error);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
async persistWorkflowSnapshot(params) {
|
|
2237
|
+
const { namespace = "workflows", workflowName, runId, resourceId, snapshot, createdAt, updatedAt } = params;
|
|
2238
|
+
try {
|
|
2239
|
+
let finalCreatedAt = createdAt;
|
|
2240
|
+
if (!finalCreatedAt) {
|
|
2241
|
+
const existing = await this.db.get({
|
|
2242
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2243
|
+
keys: {
|
|
2244
|
+
namespace,
|
|
2245
|
+
workflow_name: workflowName,
|
|
2246
|
+
run_id: runId
|
|
2247
|
+
}
|
|
2248
|
+
});
|
|
2249
|
+
finalCreatedAt = existing?.createdAt ? (0, _mastra_core_storage.ensureDate)(existing.createdAt) : /* @__PURE__ */ new Date();
|
|
2250
|
+
}
|
|
2251
|
+
await this.db.insert({
|
|
2252
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2253
|
+
record: {
|
|
2254
|
+
namespace,
|
|
2255
|
+
workflow_name: workflowName,
|
|
2256
|
+
run_id: runId,
|
|
2257
|
+
resourceId,
|
|
2258
|
+
snapshot,
|
|
2259
|
+
createdAt: finalCreatedAt,
|
|
2260
|
+
updatedAt: updatedAt ?? /* @__PURE__ */ new Date()
|
|
2261
|
+
}
|
|
2262
|
+
});
|
|
2263
|
+
} catch (error) {
|
|
2264
|
+
throw new _mastra_core_error.MastraError({
|
|
2265
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
2266
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2267
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2268
|
+
details: {
|
|
2269
|
+
namespace,
|
|
2270
|
+
workflowName,
|
|
2271
|
+
runId
|
|
2272
|
+
}
|
|
2273
|
+
}, error);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
async loadWorkflowSnapshot(params) {
|
|
2277
|
+
const { namespace = "workflows", workflowName, runId } = params;
|
|
2278
|
+
try {
|
|
2279
|
+
return (await this.db.get({
|
|
2280
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2281
|
+
keys: {
|
|
2282
|
+
namespace,
|
|
2283
|
+
workflow_name: workflowName,
|
|
2284
|
+
run_id: runId
|
|
2285
|
+
}
|
|
2286
|
+
}))?.snapshot ?? null;
|
|
2287
|
+
} catch (error) {
|
|
2288
|
+
throw new _mastra_core_error.MastraError({
|
|
2289
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
2290
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2291
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2292
|
+
details: {
|
|
2293
|
+
namespace,
|
|
2294
|
+
workflowName,
|
|
2295
|
+
runId
|
|
2296
|
+
}
|
|
2297
|
+
}, error);
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
async getWorkflowRunById({ runId, workflowName }) {
|
|
2301
|
+
try {
|
|
2302
|
+
const data = (await this.db.listAll({
|
|
2303
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2304
|
+
keyPrefix: getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" })
|
|
2305
|
+
})).find((workflow) => {
|
|
2306
|
+
if (!workflow) return false;
|
|
2307
|
+
const runIdMatch = workflow.run_id === runId;
|
|
2308
|
+
if (workflowName) return runIdMatch && workflow.workflow_name === workflowName;
|
|
2309
|
+
return runIdMatch;
|
|
2310
|
+
});
|
|
2311
|
+
if (!data) return null;
|
|
2312
|
+
return parseWorkflowRun(data);
|
|
2313
|
+
} catch (error) {
|
|
2314
|
+
throw new _mastra_core_error.MastraError({
|
|
2315
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
2316
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2317
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2318
|
+
details: {
|
|
2319
|
+
namespace: "workflows",
|
|
2320
|
+
runId,
|
|
2321
|
+
workflowName: workflowName || ""
|
|
2322
|
+
}
|
|
2323
|
+
}, error);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
2327
|
+
const key = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
|
|
2328
|
+
namespace: "workflows",
|
|
2329
|
+
workflow_name: workflowName,
|
|
2330
|
+
run_id: runId
|
|
2331
|
+
});
|
|
2332
|
+
try {
|
|
2333
|
+
await this.db.delete({
|
|
2334
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2335
|
+
key
|
|
2336
|
+
});
|
|
2337
|
+
} catch (error) {
|
|
2338
|
+
throw new _mastra_core_error.MastraError({
|
|
2339
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
2340
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2341
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2342
|
+
details: {
|
|
2343
|
+
namespace: "workflows",
|
|
2344
|
+
runId,
|
|
2345
|
+
workflowName
|
|
2346
|
+
}
|
|
2347
|
+
}, error);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
async listWorkflowRuns({ workflowName, fromDate, toDate, perPage, page, resourceId, status } = {}) {
|
|
2351
|
+
try {
|
|
2352
|
+
if (page !== void 0 && page < 0) throw new _mastra_core_error.MastraError({
|
|
2353
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_WORKFLOW_RUNS", "INVALID_PAGE"),
|
|
2354
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2355
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
2356
|
+
details: { page }
|
|
2357
|
+
}, /* @__PURE__ */ new Error("page must be >= 0"));
|
|
2358
|
+
const normalizedFrom = fromDate ? (0, _mastra_core_storage.ensureDate)(fromDate) : void 0;
|
|
2359
|
+
const normalizedTo = toDate ? (0, _mastra_core_storage.ensureDate)(toDate) : void 0;
|
|
2360
|
+
let keyPrefix = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, { namespace: "workflows" });
|
|
2361
|
+
if (workflowName) keyPrefix = getKey(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, {
|
|
2362
|
+
namespace: "workflows",
|
|
2363
|
+
workflow_name: workflowName
|
|
2364
|
+
}) + ":";
|
|
2365
|
+
let runs = (await this.db.listAll({
|
|
2366
|
+
tableName: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2367
|
+
keyPrefix
|
|
2368
|
+
})).filter((record) => record !== null && record !== void 0 && typeof record === "object" && "workflow_name" in record).filter((record) => !workflowName || record.workflow_name === workflowName).filter((record) => !resourceId || record.resourceId === resourceId).map((w) => parseWorkflowRun(w)).filter((w) => {
|
|
2369
|
+
if (normalizedFrom && w.createdAt < normalizedFrom) return false;
|
|
2370
|
+
if (normalizedTo && w.createdAt > normalizedTo) return false;
|
|
2371
|
+
if (status) {
|
|
2372
|
+
let snapshot = w.snapshot;
|
|
2373
|
+
if (typeof snapshot === "string") try {
|
|
2374
|
+
snapshot = JSON.parse(snapshot);
|
|
2375
|
+
} catch (e) {
|
|
2376
|
+
console.warn(`Failed to parse snapshot for workflow ${w.workflowName}: ${e}`);
|
|
2377
|
+
return false;
|
|
2378
|
+
}
|
|
2379
|
+
return snapshot.status === status;
|
|
2380
|
+
}
|
|
2381
|
+
return true;
|
|
2382
|
+
}).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2383
|
+
const total = runs.length;
|
|
2384
|
+
if (typeof perPage === "number" && typeof page === "number") {
|
|
2385
|
+
const normalizedPerPage = (0, _mastra_core_storage.normalizePerPage)(perPage, Number.MAX_SAFE_INTEGER);
|
|
2386
|
+
const offset = page * normalizedPerPage;
|
|
2387
|
+
runs = runs.slice(offset, offset + normalizedPerPage);
|
|
2388
|
+
}
|
|
2389
|
+
return {
|
|
2390
|
+
runs,
|
|
2391
|
+
total
|
|
2392
|
+
};
|
|
2393
|
+
} catch (error) {
|
|
2394
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
2395
|
+
throw new _mastra_core_error.MastraError({
|
|
2396
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("ELASTICSEARCH", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
2397
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2398
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
2399
|
+
details: {
|
|
2400
|
+
namespace: "workflows",
|
|
2401
|
+
workflowName: workflowName || "",
|
|
2402
|
+
resourceId: resourceId || ""
|
|
2403
|
+
}
|
|
2404
|
+
}, error);
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
//#endregion
|
|
2409
|
+
//#region src/storage/store.ts
|
|
2410
|
+
/**
|
|
2411
|
+
* ElasticSearch storage adapter for Mastra.
|
|
2412
|
+
*
|
|
2413
|
+
* Implements the memory, workflows, and scores storage domains on top of
|
|
2414
|
+
* ElasticSearch. Shares the same connection config surface as
|
|
2415
|
+
* `ElasticSearchVector`, so both can reuse one client or connection config.
|
|
2416
|
+
*
|
|
2417
|
+
* @example
|
|
2418
|
+
* ```typescript
|
|
2419
|
+
* // Using connection parameters
|
|
2420
|
+
* const storage = new ElasticSearchStore({
|
|
2421
|
+
* id: 'my-store',
|
|
2422
|
+
* url: 'http://localhost:9200',
|
|
2423
|
+
* auth: { apiKey: '...' },
|
|
2424
|
+
* });
|
|
2425
|
+
*
|
|
2426
|
+
* // Access memory domain
|
|
2427
|
+
* const memory = await storage.getStore('memory');
|
|
2428
|
+
* await memory?.saveThread({ thread });
|
|
2429
|
+
* ```
|
|
2430
|
+
*
|
|
2431
|
+
* @example
|
|
2432
|
+
* ```typescript
|
|
2433
|
+
* // Using a pre-configured client shared with ElasticSearchVector
|
|
2434
|
+
* import { Client } from '@elastic/elasticsearch';
|
|
2435
|
+
*
|
|
2436
|
+
* const client = new Client({ node: 'http://localhost:9200' });
|
|
2437
|
+
* const storage = new ElasticSearchStore({ id: 'my-store', client });
|
|
2438
|
+
* const vector = new ElasticSearchVector({ id: 'my-vector', client });
|
|
2439
|
+
* ```
|
|
2440
|
+
*/
|
|
2441
|
+
var ElasticSearchStore = class extends _mastra_core_storage.MastraStorage {
|
|
2442
|
+
client;
|
|
2443
|
+
shouldManageConnection;
|
|
2444
|
+
stores;
|
|
2445
|
+
constructor(config) {
|
|
2446
|
+
super({
|
|
2447
|
+
id: config.id,
|
|
2448
|
+
name: "ElasticSearch",
|
|
2449
|
+
disableInit: config.disableInit
|
|
2450
|
+
});
|
|
2451
|
+
if ("client" in config && config.client) {
|
|
2452
|
+
this.client = config.client;
|
|
2453
|
+
this.shouldManageConnection = false;
|
|
2454
|
+
} else if ("url" in config && config.url) {
|
|
2455
|
+
this.client = new _elastic_elasticsearch.Client({
|
|
2456
|
+
node: config.url,
|
|
2457
|
+
...config.auth && { auth: config.auth },
|
|
2458
|
+
name: "mastra-elasticsearch",
|
|
2459
|
+
headers: { "user-agent": `mastra-es/${version}` }
|
|
2460
|
+
});
|
|
2461
|
+
this.shouldManageConnection = true;
|
|
2462
|
+
} else throw new _mastra_core_error.MastraError({
|
|
2463
|
+
id: "ELASTIC_SEARCH_STORE_CONSTRUCTOR_ERROR",
|
|
2464
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
2465
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
2466
|
+
text: "Invalid config: provide either { client } or { url }."
|
|
2467
|
+
});
|
|
2468
|
+
this.stores = {
|
|
2469
|
+
memory: new MemoryElasticSearch({ client: this.client }),
|
|
2470
|
+
workflows: new WorkflowsElasticSearch({ client: this.client }),
|
|
2471
|
+
scores: new ScoresElasticSearch({ client: this.client })
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2474
|
+
getClient() {
|
|
2475
|
+
return this.client;
|
|
2476
|
+
}
|
|
2477
|
+
async close() {
|
|
2478
|
+
if (this.shouldManageConnection) await this.client.close();
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
//#endregion
|
|
2482
|
+
exports.ElasticSearchStore = ElasticSearchStore;
|
|
844
2483
|
exports.ElasticSearchVector = ElasticSearchVector;
|
|
2484
|
+
exports.MemoryElasticSearch = MemoryElasticSearch;
|
|
2485
|
+
exports.ScoresElasticSearch = ScoresElasticSearch;
|
|
2486
|
+
exports.WorkflowsElasticSearch = WorkflowsElasticSearch;
|
|
845
2487
|
|
|
846
2488
|
//# sourceMappingURL=index.cjs.map
|