@mastra/editor 0.2.0 → 0.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +199 -0
- package/dist/index.cjs +804 -216
- package/dist/index.d.cts +210 -70
- package/dist/index.d.ts +210 -70
- package/dist/index.js +794 -216
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -1,189 +1,515 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// src/namespaces/base.ts
|
|
2
|
+
var EditorNamespace = class {
|
|
3
|
+
constructor(editor) {
|
|
4
|
+
this.editor = editor;
|
|
5
|
+
}
|
|
6
|
+
get mastra() {
|
|
7
|
+
return this.editor.__mastra;
|
|
8
|
+
}
|
|
9
|
+
get logger() {
|
|
10
|
+
return this.editor.__logger;
|
|
11
|
+
}
|
|
12
|
+
ensureRegistered() {
|
|
13
|
+
if (!this.editor.__mastra) {
|
|
14
|
+
throw new Error("MastraEditor is not registered with a Mastra instance");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var CrudEditorNamespace = class extends EditorNamespace {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this._cache = /* @__PURE__ */ new Map();
|
|
7
22
|
}
|
|
8
23
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
24
|
+
* Convert a raw resolved config into a runtime primitive.
|
|
25
|
+
* Override in subclasses that need hydration (e.g. agents → Agent instance).
|
|
26
|
+
* Default implementation returns the resolved config as-is.
|
|
11
27
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!this.logger) {
|
|
15
|
-
this.logger = mastra.getLogger();
|
|
16
|
-
}
|
|
28
|
+
async hydrate(resolved) {
|
|
29
|
+
return resolved;
|
|
17
30
|
}
|
|
18
31
|
/**
|
|
19
|
-
*
|
|
32
|
+
* Hook called when an entity is evicted from the cache (on delete, update, or clearCache).
|
|
33
|
+
* Override in subclasses to also remove the entity from the Mastra runtime registry.
|
|
20
34
|
*/
|
|
21
|
-
|
|
22
|
-
const storage = this.mastra.getStorage();
|
|
23
|
-
if (!storage) throw new Error("Storage is not configured");
|
|
24
|
-
const agentsStore = await storage.getStore("agents");
|
|
25
|
-
if (!agentsStore) throw new Error("Agents storage domain is not available");
|
|
26
|
-
return agentsStore;
|
|
35
|
+
onCacheEvict(_id) {
|
|
27
36
|
}
|
|
28
|
-
async
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
async create(input) {
|
|
38
|
+
this.ensureRegistered();
|
|
39
|
+
const adapter = await this.getStorageAdapter();
|
|
40
|
+
await adapter.create(input);
|
|
41
|
+
const resolved = await adapter.getByIdResolved(input.id);
|
|
42
|
+
if (!resolved) {
|
|
43
|
+
throw new Error(`Failed to resolve entity ${input.id} after creation`);
|
|
44
|
+
}
|
|
45
|
+
const hydrated = await this.hydrate(resolved);
|
|
46
|
+
this._cache.set(input.id, hydrated);
|
|
47
|
+
return hydrated;
|
|
48
|
+
}
|
|
49
|
+
async getById(id, options) {
|
|
50
|
+
this.ensureRegistered();
|
|
51
|
+
const isVersionRequest = options?.versionId || options?.versionNumber;
|
|
52
|
+
if (!isVersionRequest) {
|
|
53
|
+
const cached = this._cache.get(id);
|
|
54
|
+
if (cached) {
|
|
55
|
+
this.logger?.debug(`[getById] Cache hit for "${id}"`);
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
31
58
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
this.logger?.debug(`[getById] Cache miss for "${id}", fetching from storage`);
|
|
60
|
+
const adapter = await this.getStorageAdapter();
|
|
61
|
+
const resolved = await adapter.getByIdResolved(id, options);
|
|
62
|
+
if (!resolved) return null;
|
|
63
|
+
const hydrated = await this.hydrate(resolved);
|
|
64
|
+
if (!isVersionRequest) {
|
|
65
|
+
this._cache.set(id, hydrated);
|
|
35
66
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
67
|
+
return hydrated;
|
|
68
|
+
}
|
|
69
|
+
async update(input) {
|
|
70
|
+
this.ensureRegistered();
|
|
71
|
+
const adapter = await this.getStorageAdapter();
|
|
72
|
+
await adapter.update(input);
|
|
73
|
+
this._cache.delete(input.id);
|
|
74
|
+
this.onCacheEvict(input.id);
|
|
75
|
+
const resolved = await adapter.getByIdResolved(input.id);
|
|
76
|
+
if (!resolved) {
|
|
77
|
+
throw new Error(`Failed to resolve entity ${input.id} after update`);
|
|
78
|
+
}
|
|
79
|
+
const hydrated = await this.hydrate(resolved);
|
|
80
|
+
this._cache.set(input.id, hydrated);
|
|
81
|
+
return hydrated;
|
|
82
|
+
}
|
|
83
|
+
async delete(id) {
|
|
84
|
+
this.ensureRegistered();
|
|
85
|
+
const adapter = await this.getStorageAdapter();
|
|
86
|
+
await adapter.delete(id);
|
|
87
|
+
this._cache.delete(id);
|
|
88
|
+
this.onCacheEvict(id);
|
|
89
|
+
}
|
|
90
|
+
async list(args) {
|
|
91
|
+
this.ensureRegistered();
|
|
92
|
+
const adapter = await this.getStorageAdapter();
|
|
93
|
+
return adapter.list(args);
|
|
94
|
+
}
|
|
95
|
+
async listResolved(args) {
|
|
96
|
+
this.ensureRegistered();
|
|
97
|
+
const adapter = await this.getStorageAdapter();
|
|
98
|
+
return adapter.listResolved(args);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clear cached entities. If an id is provided, only that entity is cleared.
|
|
102
|
+
* Otherwise all cached entities in this namespace are cleared.
|
|
103
|
+
*/
|
|
104
|
+
clearCache(id) {
|
|
105
|
+
if (id) {
|
|
106
|
+
this._cache.delete(id);
|
|
107
|
+
this.onCacheEvict(id);
|
|
108
|
+
this.logger?.debug(`[clearCache] Cleared cache for "${id}"`);
|
|
109
|
+
} else {
|
|
110
|
+
for (const cachedId of Array.from(this._cache.keys())) {
|
|
111
|
+
this.onCacheEvict(cachedId);
|
|
40
112
|
}
|
|
41
|
-
|
|
42
|
-
|
|
113
|
+
this._cache.clear();
|
|
114
|
+
this.logger?.debug("[clearCache] Cleared all cached entities");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/namespaces/agent.ts
|
|
120
|
+
import { Memory } from "@mastra/memory";
|
|
121
|
+
import { Agent } from "@mastra/core";
|
|
122
|
+
import { convertSchemaToZod } from "@mastra/schema-compat";
|
|
123
|
+
import { RequestContext } from "@mastra/core/request-context";
|
|
124
|
+
|
|
125
|
+
// src/rule-evaluator.ts
|
|
126
|
+
function resolvePath(context, path) {
|
|
127
|
+
const segments = path.split(".");
|
|
128
|
+
let current = context;
|
|
129
|
+
for (const segment of segments) {
|
|
130
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
current = current[segment];
|
|
134
|
+
}
|
|
135
|
+
return current;
|
|
136
|
+
}
|
|
137
|
+
function evaluateRule(rule, context) {
|
|
138
|
+
const fieldValue = resolvePath(context, rule.field);
|
|
139
|
+
switch (rule.operator) {
|
|
140
|
+
case "equals":
|
|
141
|
+
return fieldValue === rule.value;
|
|
142
|
+
case "not_equals":
|
|
143
|
+
return fieldValue !== rule.value;
|
|
144
|
+
case "contains": {
|
|
145
|
+
if (typeof fieldValue === "string" && typeof rule.value === "string") {
|
|
146
|
+
return fieldValue.includes(rule.value);
|
|
43
147
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} = version;
|
|
53
|
-
const agentRecord = await agentsStore.getAgentById({ id });
|
|
54
|
-
if (!agentRecord) {
|
|
55
|
-
return null;
|
|
148
|
+
if (Array.isArray(fieldValue)) {
|
|
149
|
+
return fieldValue.includes(rule.value);
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
case "not_contains": {
|
|
154
|
+
if (typeof fieldValue === "string" && typeof rule.value === "string") {
|
|
155
|
+
return !fieldValue.includes(rule.value);
|
|
56
156
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (options?.returnRaw) {
|
|
60
|
-
return resolvedAgent;
|
|
157
|
+
if (Array.isArray(fieldValue)) {
|
|
158
|
+
return !fieldValue.includes(rule.value);
|
|
61
159
|
}
|
|
62
|
-
return
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
case "greater_than":
|
|
163
|
+
return typeof fieldValue === "number" && typeof rule.value === "number" && fieldValue > rule.value;
|
|
164
|
+
case "less_than":
|
|
165
|
+
return typeof fieldValue === "number" && typeof rule.value === "number" && fieldValue < rule.value;
|
|
166
|
+
case "greater_than_or_equal":
|
|
167
|
+
return typeof fieldValue === "number" && typeof rule.value === "number" && fieldValue >= rule.value;
|
|
168
|
+
case "less_than_or_equal":
|
|
169
|
+
return typeof fieldValue === "number" && typeof rule.value === "number" && fieldValue <= rule.value;
|
|
170
|
+
case "in":
|
|
171
|
+
return Array.isArray(rule.value) && rule.value.includes(fieldValue);
|
|
172
|
+
case "not_in":
|
|
173
|
+
return Array.isArray(rule.value) && !rule.value.includes(fieldValue);
|
|
174
|
+
case "exists":
|
|
175
|
+
return fieldValue !== void 0 && fieldValue !== null;
|
|
176
|
+
case "not_exists":
|
|
177
|
+
return fieldValue === void 0 || fieldValue === null;
|
|
178
|
+
default:
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function evaluateRuleGroup(ruleGroup, context) {
|
|
183
|
+
if (ruleGroup.conditions.length === 0) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
const results = ruleGroup.conditions.map((condition) => {
|
|
187
|
+
if ("conditions" in condition) {
|
|
188
|
+
return evaluateRuleGroup(condition, context);
|
|
189
|
+
}
|
|
190
|
+
return evaluateRule(condition, context);
|
|
191
|
+
});
|
|
192
|
+
if (ruleGroup.operator === "AND") {
|
|
193
|
+
return results.every(Boolean);
|
|
194
|
+
}
|
|
195
|
+
return results.some(Boolean);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/template-engine.ts
|
|
199
|
+
function resolvePath2(context, path) {
|
|
200
|
+
const segments = path.split(".");
|
|
201
|
+
let current = context;
|
|
202
|
+
for (const segment of segments) {
|
|
203
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
204
|
+
return void 0;
|
|
63
205
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
206
|
+
current = current[segment];
|
|
207
|
+
}
|
|
208
|
+
return current;
|
|
209
|
+
}
|
|
210
|
+
var TEMPLATE_PATTERN = /\{\{\s*([a-zA-Z_][\w.]*)\s*(?:\|\|\s*(?:'([^']*)'|"([^"]*)")\s*)?\}\}/g;
|
|
211
|
+
function renderTemplate(template, context) {
|
|
212
|
+
return template.replace(
|
|
213
|
+
TEMPLATE_PATTERN,
|
|
214
|
+
(match, variablePath, singleFallback, doubleFallback) => {
|
|
215
|
+
const resolved = resolvePath2(context, variablePath);
|
|
216
|
+
if (resolved !== void 0 && resolved !== null) {
|
|
217
|
+
return String(resolved);
|
|
68
218
|
}
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
versionNumber: _versionNumber,
|
|
73
|
-
changedFields: _changedFields,
|
|
74
|
-
changeMessage: _changeMessage,
|
|
75
|
-
createdAt: _createdAt,
|
|
76
|
-
...snapshotConfig
|
|
77
|
-
} = version;
|
|
78
|
-
const agentRecord = await agentsStore.getAgentById({ id });
|
|
79
|
-
if (!agentRecord) {
|
|
80
|
-
return null;
|
|
219
|
+
const fallback = singleFallback ?? doubleFallback;
|
|
220
|
+
if (fallback !== void 0) {
|
|
221
|
+
return fallback;
|
|
81
222
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
223
|
+
return match;
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/instruction-builder.ts
|
|
229
|
+
async function resolveInstructionBlocks(blocks, context, deps) {
|
|
230
|
+
const segments = [];
|
|
231
|
+
const blockIds = Array.from(
|
|
232
|
+
new Set(
|
|
233
|
+
blocks.filter((b) => b.type === "prompt_block_ref").map((b) => b.id)
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
const resolvedBlocksMap = /* @__PURE__ */ new Map();
|
|
237
|
+
if (blockIds.length > 0) {
|
|
238
|
+
const fetchResults = await Promise.all(blockIds.map((id) => deps.promptBlocksStorage.getByIdResolved(id)));
|
|
239
|
+
for (let i = 0; i < blockIds.length; i++) {
|
|
240
|
+
const result = fetchResults[i];
|
|
241
|
+
if (result) {
|
|
242
|
+
resolvedBlocksMap.set(blockIds[i], result);
|
|
86
243
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.logger?.debug(`[getStoredAgentById] Returning cached agent "${id}"`);
|
|
95
|
-
return cached;
|
|
96
|
-
}
|
|
97
|
-
this.logger?.debug(`[getStoredAgentById] Cache miss for agent "${id}", fetching from storage`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
for (const block of blocks) {
|
|
247
|
+
if (block.type === "text") {
|
|
248
|
+
const rendered2 = renderTemplate(block.content, context);
|
|
249
|
+
if (rendered2.trim()) {
|
|
250
|
+
segments.push(rendered2);
|
|
98
251
|
}
|
|
252
|
+
continue;
|
|
99
253
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
254
|
+
if (block.type === "prompt_block") {
|
|
255
|
+
if (block.rules) {
|
|
256
|
+
const passes = evaluateRuleGroup(block.rules, context);
|
|
257
|
+
if (!passes) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const rendered2 = renderTemplate(block.content, context);
|
|
262
|
+
if (rendered2.trim()) {
|
|
263
|
+
segments.push(rendered2);
|
|
264
|
+
}
|
|
265
|
+
continue;
|
|
103
266
|
}
|
|
104
|
-
|
|
105
|
-
|
|
267
|
+
const resolved = resolvedBlocksMap.get(block.id);
|
|
268
|
+
if (!resolved) {
|
|
269
|
+
continue;
|
|
106
270
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (agentCache) {
|
|
110
|
-
agentCache.set(id, agent);
|
|
271
|
+
if (resolved.status !== "published") {
|
|
272
|
+
continue;
|
|
111
273
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
274
|
+
if (resolved.rules) {
|
|
275
|
+
const passes = evaluateRuleGroup(resolved.rules, context);
|
|
276
|
+
if (!passes) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
117
279
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
perPage: options?.pageSize,
|
|
122
|
-
orderBy: { field: "createdAt", direction: "DESC" }
|
|
123
|
-
});
|
|
124
|
-
if (options?.returnRaw) {
|
|
125
|
-
return result;
|
|
280
|
+
const rendered = renderTemplate(resolved.content, context);
|
|
281
|
+
if (rendered.trim()) {
|
|
282
|
+
segments.push(rendered);
|
|
126
283
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
284
|
+
}
|
|
285
|
+
return segments.join("\n\n");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/namespaces/agent.ts
|
|
289
|
+
var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
290
|
+
async getStorageAdapter() {
|
|
291
|
+
const storage = this.mastra.getStorage();
|
|
292
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
293
|
+
const store = await storage.getStore("agents");
|
|
294
|
+
if (!store) throw new Error("Agents storage domain is not available");
|
|
130
295
|
return {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
296
|
+
create: (input) => store.create({ agent: input }),
|
|
297
|
+
getByIdResolved: async (id, options) => {
|
|
298
|
+
if (options?.versionId || options?.versionNumber) {
|
|
299
|
+
const agent = await store.getById(id);
|
|
300
|
+
if (!agent) return null;
|
|
301
|
+
const version = options.versionId ? await store.getVersion(options.versionId) : await store.getVersionByNumber(id, options.versionNumber);
|
|
302
|
+
if (!version) return null;
|
|
303
|
+
const {
|
|
304
|
+
id: _vId,
|
|
305
|
+
agentId: _aId,
|
|
306
|
+
versionNumber: _vn,
|
|
307
|
+
changedFields: _cf,
|
|
308
|
+
changeMessage: _cm,
|
|
309
|
+
createdAt: _ca,
|
|
310
|
+
...snapshotConfig
|
|
311
|
+
} = version;
|
|
312
|
+
return { ...agent, ...snapshotConfig };
|
|
313
|
+
}
|
|
314
|
+
return store.getByIdResolved(id);
|
|
315
|
+
},
|
|
316
|
+
update: (input) => store.update(input),
|
|
317
|
+
delete: (id) => store.delete(id),
|
|
318
|
+
list: (args) => store.list(args),
|
|
319
|
+
listResolved: (args) => store.listResolved(args)
|
|
136
320
|
};
|
|
137
321
|
}
|
|
138
322
|
/**
|
|
139
|
-
*
|
|
323
|
+
* Hydrate a stored agent config into a runtime Agent instance.
|
|
140
324
|
*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
325
|
+
async hydrate(storedAgent) {
|
|
326
|
+
return this.createAgentFromStoredConfig(storedAgent);
|
|
327
|
+
}
|
|
328
|
+
onCacheEvict(id) {
|
|
329
|
+
this.mastra?.removeAgent(id);
|
|
330
|
+
}
|
|
331
|
+
// ============================================================================
|
|
332
|
+
// Private helpers
|
|
333
|
+
// ============================================================================
|
|
334
|
+
/**
|
|
335
|
+
* Detect whether a StorageConditionalField value is a conditional variant array
|
|
336
|
+
* (as opposed to the plain static value T).
|
|
337
|
+
*/
|
|
338
|
+
isConditionalVariants(field) {
|
|
339
|
+
return Array.isArray(field) && field.length > 0 && typeof field[0] === "object" && field[0] !== null && "value" in field[0];
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Accumulate all matching variants for an array-typed field.
|
|
343
|
+
* Each matching variant's value (an array) is concatenated in order.
|
|
344
|
+
* Variants with no rules are treated as unconditional (always included).
|
|
345
|
+
*/
|
|
346
|
+
accumulateArrayVariants(variants, context) {
|
|
347
|
+
const result = [];
|
|
348
|
+
for (const variant of variants) {
|
|
349
|
+
if (!variant.rules || evaluateRuleGroup(variant.rules, context)) {
|
|
350
|
+
result.push(...variant.value);
|
|
351
|
+
}
|
|
151
352
|
}
|
|
353
|
+
return result;
|
|
152
354
|
}
|
|
153
355
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
356
|
+
* Accumulate all matching variants for an object/record-typed field.
|
|
357
|
+
* Each matching variant's value is shallow-merged in order, so later
|
|
358
|
+
* matches override keys from earlier ones.
|
|
359
|
+
* Variants with no rules are treated as unconditional (always included).
|
|
157
360
|
*/
|
|
158
|
-
|
|
361
|
+
accumulateObjectVariants(variants, context) {
|
|
362
|
+
let result;
|
|
363
|
+
for (const variant of variants) {
|
|
364
|
+
if (!variant.rules || evaluateRuleGroup(variant.rules, context)) {
|
|
365
|
+
result = result ? { ...result, ...variant.value } : { ...variant.value };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
async createAgentFromStoredConfig(storedAgent) {
|
|
159
371
|
if (!this.mastra) {
|
|
160
372
|
throw new Error("MastraEditor is not registered with a Mastra instance");
|
|
161
373
|
}
|
|
162
374
|
this.logger?.debug(`[createAgentFromStoredConfig] Creating agent from stored config "${storedAgent.id}"`);
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
);
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
375
|
+
const instructions = this.resolveStoredInstructions(storedAgent.instructions);
|
|
376
|
+
const hasConditionalTools = storedAgent.tools != null && this.isConditionalVariants(storedAgent.tools);
|
|
377
|
+
const hasConditionalWorkflows = storedAgent.workflows != null && this.isConditionalVariants(storedAgent.workflows);
|
|
378
|
+
const hasConditionalAgents = storedAgent.agents != null && this.isConditionalVariants(storedAgent.agents);
|
|
379
|
+
const hasConditionalMemory = storedAgent.memory != null && this.isConditionalVariants(storedAgent.memory);
|
|
380
|
+
const hasConditionalScorers = storedAgent.scorers != null && this.isConditionalVariants(storedAgent.scorers);
|
|
381
|
+
const hasConditionalInputProcessors = storedAgent.inputProcessors != null && this.isConditionalVariants(storedAgent.inputProcessors);
|
|
382
|
+
const hasConditionalOutputProcessors = storedAgent.outputProcessors != null && this.isConditionalVariants(storedAgent.outputProcessors);
|
|
383
|
+
const hasConditionalDefaultOptions = storedAgent.defaultOptions != null && this.isConditionalVariants(storedAgent.defaultOptions);
|
|
384
|
+
const hasConditionalModel = this.isConditionalVariants(storedAgent.model);
|
|
385
|
+
const tools = hasConditionalTools ? ({ requestContext }) => {
|
|
386
|
+
const ctx = requestContext.toJSON();
|
|
387
|
+
const resolved = this.accumulateObjectVariants(
|
|
388
|
+
storedAgent.tools,
|
|
389
|
+
ctx
|
|
390
|
+
);
|
|
391
|
+
return this.resolveStoredTools(resolved);
|
|
392
|
+
} : this.resolveStoredTools(storedAgent.tools);
|
|
393
|
+
const workflows = hasConditionalWorkflows ? ({ requestContext }) => {
|
|
394
|
+
const ctx = requestContext.toJSON();
|
|
395
|
+
const resolved = this.accumulateArrayVariants(
|
|
396
|
+
storedAgent.workflows,
|
|
397
|
+
ctx
|
|
398
|
+
);
|
|
399
|
+
return this.resolveStoredWorkflows(resolved);
|
|
400
|
+
} : this.resolveStoredWorkflows(storedAgent.workflows);
|
|
401
|
+
const agents = hasConditionalAgents ? ({ requestContext }) => {
|
|
402
|
+
const ctx = requestContext.toJSON();
|
|
403
|
+
const resolved = this.accumulateArrayVariants(
|
|
404
|
+
storedAgent.agents,
|
|
405
|
+
ctx
|
|
406
|
+
);
|
|
407
|
+
return this.resolveStoredAgents(resolved);
|
|
408
|
+
} : this.resolveStoredAgents(storedAgent.agents);
|
|
409
|
+
const memory = hasConditionalMemory ? ({ requestContext }) => {
|
|
410
|
+
const ctx = requestContext.toJSON();
|
|
411
|
+
const resolved = this.accumulateObjectVariants(
|
|
412
|
+
storedAgent.memory,
|
|
413
|
+
ctx
|
|
178
414
|
);
|
|
415
|
+
return this.resolveStoredMemory(resolved);
|
|
416
|
+
} : this.resolveStoredMemory(storedAgent.memory);
|
|
417
|
+
const scorers = hasConditionalScorers ? async ({ requestContext }) => {
|
|
418
|
+
const ctx = requestContext.toJSON();
|
|
419
|
+
const resolved = this.accumulateObjectVariants(
|
|
420
|
+
storedAgent.scorers,
|
|
421
|
+
ctx
|
|
422
|
+
);
|
|
423
|
+
return this.resolveStoredScorers(resolved);
|
|
424
|
+
} : await this.resolveStoredScorers(storedAgent.scorers);
|
|
425
|
+
const inputProcessors = hasConditionalInputProcessors ? ({ requestContext }) => {
|
|
426
|
+
const ctx = requestContext.toJSON();
|
|
427
|
+
const resolved = this.accumulateArrayVariants(
|
|
428
|
+
storedAgent.inputProcessors,
|
|
429
|
+
ctx
|
|
430
|
+
);
|
|
431
|
+
return this.resolveStoredInputProcessors(resolved);
|
|
432
|
+
} : this.resolveStoredInputProcessors(storedAgent.inputProcessors);
|
|
433
|
+
const outputProcessors = hasConditionalOutputProcessors ? ({ requestContext }) => {
|
|
434
|
+
const ctx = requestContext.toJSON();
|
|
435
|
+
const resolved = this.accumulateArrayVariants(
|
|
436
|
+
storedAgent.outputProcessors,
|
|
437
|
+
ctx
|
|
438
|
+
);
|
|
439
|
+
return this.resolveStoredOutputProcessors(resolved);
|
|
440
|
+
} : this.resolveStoredOutputProcessors(storedAgent.outputProcessors);
|
|
441
|
+
let model;
|
|
442
|
+
let staticModelConfig;
|
|
443
|
+
const modelSettingsFrom = (cfg) => ({
|
|
444
|
+
temperature: cfg.temperature,
|
|
445
|
+
topP: cfg.topP,
|
|
446
|
+
frequencyPenalty: cfg.frequencyPenalty,
|
|
447
|
+
presencePenalty: cfg.presencePenalty,
|
|
448
|
+
maxOutputTokens: cfg.maxCompletionTokens
|
|
449
|
+
});
|
|
450
|
+
if (hasConditionalModel) {
|
|
451
|
+
model = ({ requestContext }) => {
|
|
452
|
+
const ctx = requestContext.toJSON();
|
|
453
|
+
const resolved = this.accumulateObjectVariants(
|
|
454
|
+
storedAgent.model,
|
|
455
|
+
ctx
|
|
456
|
+
);
|
|
457
|
+
if (!resolved || !resolved.provider || !resolved.name) {
|
|
458
|
+
throw new Error(
|
|
459
|
+
`Stored agent "${storedAgent.id}" conditional model resolved to invalid configuration. Both provider and name are required.`
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
return `${resolved.provider}/${resolved.name}`;
|
|
463
|
+
};
|
|
464
|
+
} else {
|
|
465
|
+
staticModelConfig = storedAgent.model;
|
|
466
|
+
if (!staticModelConfig || !staticModelConfig.provider || !staticModelConfig.name) {
|
|
467
|
+
throw new Error(
|
|
468
|
+
`Stored agent "${storedAgent.id}" has no active version or invalid model configuration. Both provider and name are required.`
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
model = `${staticModelConfig.provider}/${staticModelConfig.name}`;
|
|
472
|
+
}
|
|
473
|
+
const staticDefaultOptions = hasConditionalDefaultOptions || hasConditionalModel ? void 0 : storedAgent.defaultOptions;
|
|
474
|
+
const resolveModelSettings = (ctx) => {
|
|
475
|
+
const resolved = this.accumulateObjectVariants(
|
|
476
|
+
storedAgent.model,
|
|
477
|
+
ctx
|
|
478
|
+
);
|
|
479
|
+
return resolved ? modelSettingsFrom(resolved) : {};
|
|
480
|
+
};
|
|
481
|
+
let defaultOptions;
|
|
482
|
+
if (hasConditionalDefaultOptions || hasConditionalModel) {
|
|
483
|
+
defaultOptions = ({ requestContext }) => {
|
|
484
|
+
const ctx = requestContext.toJSON();
|
|
485
|
+
const baseOptions = hasConditionalDefaultOptions ? this.accumulateObjectVariants(
|
|
486
|
+
storedAgent.defaultOptions,
|
|
487
|
+
ctx
|
|
488
|
+
) ?? {} : storedAgent.defaultOptions ?? {};
|
|
489
|
+
const mSettings = hasConditionalModel ? resolveModelSettings(ctx) : staticModelConfig ? modelSettingsFrom(staticModelConfig) : {};
|
|
490
|
+
return {
|
|
491
|
+
...baseOptions,
|
|
492
|
+
modelSettings: {
|
|
493
|
+
...baseOptions.modelSettings,
|
|
494
|
+
...mSettings
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
} else {
|
|
499
|
+
defaultOptions = {
|
|
500
|
+
...staticDefaultOptions,
|
|
501
|
+
modelSettings: {
|
|
502
|
+
...staticDefaultOptions?.modelSettings,
|
|
503
|
+
...staticModelConfig ? modelSettingsFrom(staticModelConfig) : void 0
|
|
504
|
+
}
|
|
505
|
+
};
|
|
179
506
|
}
|
|
180
|
-
const
|
|
181
|
-
const defaultOptions = storedAgent.defaultOptions;
|
|
507
|
+
const requestContextSchema = storedAgent.requestContextSchema ? convertSchemaToZod(storedAgent.requestContextSchema) : void 0;
|
|
182
508
|
const agent = new Agent({
|
|
183
509
|
id: storedAgent.id,
|
|
184
510
|
name: storedAgent.name,
|
|
185
511
|
description: storedAgent.description,
|
|
186
|
-
instructions:
|
|
512
|
+
instructions: instructions ?? "",
|
|
187
513
|
model,
|
|
188
514
|
memory,
|
|
189
515
|
tools,
|
|
@@ -193,61 +519,64 @@ var MastraEditor = class {
|
|
|
193
519
|
mastra: this.mastra,
|
|
194
520
|
inputProcessors,
|
|
195
521
|
outputProcessors,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
temperature: modelConfig.temperature,
|
|
200
|
-
topP: modelConfig.topP,
|
|
201
|
-
frequencyPenalty: modelConfig.frequencyPenalty,
|
|
202
|
-
presencePenalty: modelConfig.presencePenalty,
|
|
203
|
-
maxOutputTokens: modelConfig.maxCompletionTokens
|
|
204
|
-
}
|
|
205
|
-
}
|
|
522
|
+
rawConfig: storedAgent,
|
|
523
|
+
defaultOptions,
|
|
524
|
+
requestContextSchema
|
|
206
525
|
});
|
|
207
526
|
this.mastra?.addAgent(agent, storedAgent.id, { source: "stored" });
|
|
208
527
|
this.logger?.debug(`[createAgentFromStoredConfig] Successfully created agent "${storedAgent.id}"`);
|
|
209
528
|
return agent;
|
|
210
529
|
}
|
|
530
|
+
resolveStoredInstructions(instructions) {
|
|
531
|
+
if (instructions === void 0 || instructions === null) return void 0;
|
|
532
|
+
if (typeof instructions === "string") return instructions;
|
|
533
|
+
const blocks = instructions;
|
|
534
|
+
return async ({ requestContext }) => {
|
|
535
|
+
const storage = this.editor.__mastra.getStorage();
|
|
536
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
537
|
+
const promptBlocksStore = await storage.getStore("promptBlocks");
|
|
538
|
+
if (!promptBlocksStore) throw new Error("Prompt blocks storage domain is not available");
|
|
539
|
+
const context = requestContext.toJSON();
|
|
540
|
+
return resolveInstructionBlocks(blocks, context, { promptBlocksStorage: promptBlocksStore });
|
|
541
|
+
};
|
|
542
|
+
}
|
|
211
543
|
/**
|
|
212
544
|
* Resolve stored tool IDs to actual tool instances from Mastra's registry.
|
|
545
|
+
* Applies description overrides from per-tool config when present.
|
|
213
546
|
*/
|
|
214
547
|
resolveStoredTools(storedTools) {
|
|
215
|
-
if (!storedTools || storedTools.length === 0) {
|
|
548
|
+
if (!storedTools || (Array.isArray(storedTools) ? storedTools.length === 0 : Object.keys(storedTools).length === 0)) {
|
|
216
549
|
return {};
|
|
217
550
|
}
|
|
218
551
|
if (!this.mastra) {
|
|
219
552
|
return {};
|
|
220
553
|
}
|
|
554
|
+
const normalized = Array.isArray(storedTools) ? Object.fromEntries(storedTools.map((key) => [key, {}])) : storedTools;
|
|
221
555
|
const resolvedTools = {};
|
|
222
|
-
for (const toolKey of
|
|
556
|
+
for (const [toolKey, toolConfig] of Object.entries(normalized)) {
|
|
223
557
|
try {
|
|
224
558
|
const tool = this.mastra.getToolById(toolKey);
|
|
225
|
-
|
|
559
|
+
if (toolConfig.description) {
|
|
560
|
+
resolvedTools[toolKey] = { ...tool, description: toolConfig.description };
|
|
561
|
+
} else {
|
|
562
|
+
resolvedTools[toolKey] = tool;
|
|
563
|
+
}
|
|
226
564
|
} catch {
|
|
227
565
|
this.logger?.warn(`Tool "${toolKey}" referenced in stored agent but not registered in Mastra`);
|
|
228
566
|
}
|
|
229
567
|
}
|
|
230
568
|
return resolvedTools;
|
|
231
569
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Resolve stored workflow IDs to actual workflow instances from Mastra's registry.
|
|
234
|
-
*/
|
|
235
570
|
resolveStoredWorkflows(storedWorkflows) {
|
|
236
|
-
if (!storedWorkflows || storedWorkflows.length === 0) {
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
if (!this.mastra) {
|
|
240
|
-
return {};
|
|
241
|
-
}
|
|
571
|
+
if (!storedWorkflows || storedWorkflows.length === 0) return {};
|
|
572
|
+
if (!this.mastra) return {};
|
|
242
573
|
const resolvedWorkflows = {};
|
|
243
574
|
for (const workflowKey of storedWorkflows) {
|
|
244
575
|
try {
|
|
245
|
-
|
|
246
|
-
resolvedWorkflows[workflowKey] = workflow;
|
|
576
|
+
resolvedWorkflows[workflowKey] = this.mastra.getWorkflow(workflowKey);
|
|
247
577
|
} catch {
|
|
248
578
|
try {
|
|
249
|
-
|
|
250
|
-
resolvedWorkflows[workflowKey] = workflow;
|
|
579
|
+
resolvedWorkflows[workflowKey] = this.mastra.getWorkflowById(workflowKey);
|
|
251
580
|
} catch {
|
|
252
581
|
this.logger?.warn(`Workflow "${workflowKey}" referenced in stored agent but not registered in Mastra`);
|
|
253
582
|
}
|
|
@@ -255,25 +584,16 @@ var MastraEditor = class {
|
|
|
255
584
|
}
|
|
256
585
|
return resolvedWorkflows;
|
|
257
586
|
}
|
|
258
|
-
/**
|
|
259
|
-
* Resolve stored agent IDs to actual agent instances from Mastra's registry.
|
|
260
|
-
*/
|
|
261
587
|
resolveStoredAgents(storedAgents) {
|
|
262
|
-
if (!storedAgents || storedAgents.length === 0) {
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
if (!this.mastra) {
|
|
266
|
-
return {};
|
|
267
|
-
}
|
|
588
|
+
if (!storedAgents || storedAgents.length === 0) return {};
|
|
589
|
+
if (!this.mastra) return {};
|
|
268
590
|
const resolvedAgents = {};
|
|
269
591
|
for (const agentKey of storedAgents) {
|
|
270
592
|
try {
|
|
271
|
-
|
|
272
|
-
resolvedAgents[agentKey] = agent;
|
|
593
|
+
resolvedAgents[agentKey] = this.mastra.getAgent(agentKey);
|
|
273
594
|
} catch {
|
|
274
595
|
try {
|
|
275
|
-
|
|
276
|
-
resolvedAgents[agentKey] = agent;
|
|
596
|
+
resolvedAgents[agentKey] = this.mastra.getAgentById(agentKey);
|
|
277
597
|
} catch {
|
|
278
598
|
this.logger?.warn(`Agent "${agentKey}" referenced in stored agent but not registered in Mastra`);
|
|
279
599
|
}
|
|
@@ -281,12 +601,7 @@ var MastraEditor = class {
|
|
|
281
601
|
}
|
|
282
602
|
return resolvedAgents;
|
|
283
603
|
}
|
|
284
|
-
/**
|
|
285
|
-
* Resolve stored memory config to a MastraMemory instance.
|
|
286
|
-
* Uses @mastra/memory Memory class to instantiate from serialized config.
|
|
287
|
-
*/
|
|
288
604
|
resolveStoredMemory(memoryConfig) {
|
|
289
|
-
this.logger?.debug(`[resolveStoredMemory] Called with config:`, { memoryConfig });
|
|
290
605
|
if (!memoryConfig) {
|
|
291
606
|
this.logger?.debug(`[resolveStoredMemory] No memory config provided`);
|
|
292
607
|
return void 0;
|
|
@@ -304,6 +619,20 @@ var MastraEditor = class {
|
|
|
304
619
|
this.logger?.warn(`Vector provider "${memoryConfig.vector}" not found in Mastra instance`);
|
|
305
620
|
}
|
|
306
621
|
}
|
|
622
|
+
if (memoryConfig.options?.semanticRecall && (!vector || !memoryConfig.embedder)) {
|
|
623
|
+
this.logger?.warn(
|
|
624
|
+
"Semantic recall is enabled but no vector store or embedder are configured. Creating memory without semantic recall. To use semantic recall, configure a vector store and embedder in your Mastra instance."
|
|
625
|
+
);
|
|
626
|
+
const adjustedOptions = { ...memoryConfig.options, semanticRecall: false };
|
|
627
|
+
const sharedConfig2 = {
|
|
628
|
+
storage: this.mastra.getStorage(),
|
|
629
|
+
vector,
|
|
630
|
+
options: adjustedOptions,
|
|
631
|
+
embedder: memoryConfig.embedder,
|
|
632
|
+
embedderOptions: memoryConfig.embedderOptions
|
|
633
|
+
};
|
|
634
|
+
return new Memory(sharedConfig2);
|
|
635
|
+
}
|
|
307
636
|
const sharedConfig = {
|
|
308
637
|
storage: this.mastra.getStorage(),
|
|
309
638
|
vector,
|
|
@@ -317,41 +646,40 @@ var MastraEditor = class {
|
|
|
317
646
|
return void 0;
|
|
318
647
|
}
|
|
319
648
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
resolveStoredScorers(storedScorers) {
|
|
324
|
-
if (!storedScorers || Object.keys(storedScorers).length === 0) {
|
|
325
|
-
return void 0;
|
|
326
|
-
}
|
|
327
|
-
if (!this.mastra) {
|
|
328
|
-
return void 0;
|
|
329
|
-
}
|
|
649
|
+
async resolveStoredScorers(storedScorers) {
|
|
650
|
+
if (!storedScorers || Object.keys(storedScorers).length === 0) return void 0;
|
|
651
|
+
if (!this.mastra) return void 0;
|
|
330
652
|
const resolvedScorers = {};
|
|
653
|
+
const storage = this.mastra.getStorage();
|
|
654
|
+
const scorerStore = storage ? await storage.getStore("scorerDefinitions") : null;
|
|
331
655
|
for (const [scorerKey, scorerConfig] of Object.entries(storedScorers)) {
|
|
656
|
+
if (scorerStore) {
|
|
657
|
+
try {
|
|
658
|
+
const storedDef = await scorerStore.getByIdResolved(scorerKey);
|
|
659
|
+
if (storedDef) {
|
|
660
|
+
const scorer = this.editor.scorer.resolve(storedDef);
|
|
661
|
+
if (scorer) {
|
|
662
|
+
resolvedScorers[scorerKey] = { scorer, sampling: scorerConfig.sampling };
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
} catch {
|
|
667
|
+
}
|
|
668
|
+
}
|
|
332
669
|
try {
|
|
333
670
|
const scorer = this.mastra.getScorer(scorerKey);
|
|
334
|
-
resolvedScorers[scorerKey] = {
|
|
335
|
-
scorer,
|
|
336
|
-
sampling: scorerConfig.sampling
|
|
337
|
-
};
|
|
671
|
+
resolvedScorers[scorerKey] = { scorer, sampling: scorerConfig.sampling };
|
|
338
672
|
} catch {
|
|
339
673
|
try {
|
|
340
674
|
const scorer = this.mastra.getScorerById(scorerKey);
|
|
341
|
-
resolvedScorers[scorerKey] = {
|
|
342
|
-
scorer,
|
|
343
|
-
sampling: scorerConfig.sampling
|
|
344
|
-
};
|
|
675
|
+
resolvedScorers[scorerKey] = { scorer, sampling: scorerConfig.sampling };
|
|
345
676
|
} catch {
|
|
346
|
-
this.logger?.warn(`Scorer "${scorerKey}" referenced in stored agent but not
|
|
677
|
+
this.logger?.warn(`Scorer "${scorerKey}" referenced in stored agent but not found in registry or storage`);
|
|
347
678
|
}
|
|
348
679
|
}
|
|
349
680
|
}
|
|
350
681
|
return Object.keys(resolvedScorers).length > 0 ? resolvedScorers : void 0;
|
|
351
682
|
}
|
|
352
|
-
/**
|
|
353
|
-
* Look up a processor by key or ID from Mastra's registry.
|
|
354
|
-
*/
|
|
355
683
|
findProcessor(processorKey) {
|
|
356
684
|
if (!this.mastra) return void 0;
|
|
357
685
|
try {
|
|
@@ -365,9 +693,6 @@ var MastraEditor = class {
|
|
|
365
693
|
}
|
|
366
694
|
}
|
|
367
695
|
}
|
|
368
|
-
/**
|
|
369
|
-
* Resolve stored input processor keys to actual processor instances.
|
|
370
|
-
*/
|
|
371
696
|
resolveStoredInputProcessors(storedProcessors) {
|
|
372
697
|
if (!storedProcessors || storedProcessors.length === 0) return void 0;
|
|
373
698
|
const resolved = [];
|
|
@@ -379,9 +704,6 @@ var MastraEditor = class {
|
|
|
379
704
|
}
|
|
380
705
|
return resolved.length > 0 ? resolved : void 0;
|
|
381
706
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Resolve stored output processor keys to actual processor instances.
|
|
384
|
-
*/
|
|
385
707
|
resolveStoredOutputProcessors(storedProcessors) {
|
|
386
708
|
if (!storedProcessors || storedProcessors.length === 0) return void 0;
|
|
387
709
|
const resolved = [];
|
|
@@ -393,7 +715,263 @@ var MastraEditor = class {
|
|
|
393
715
|
}
|
|
394
716
|
return resolved.length > 0 ? resolved : void 0;
|
|
395
717
|
}
|
|
718
|
+
// ============================================================================
|
|
719
|
+
// Clone
|
|
720
|
+
// ============================================================================
|
|
721
|
+
/**
|
|
722
|
+
* Clone a runtime Agent instance into storage, creating a new stored agent
|
|
723
|
+
* with the resolved configuration of the source agent.
|
|
724
|
+
*/
|
|
725
|
+
async clone(agent, options) {
|
|
726
|
+
const requestContext = options.requestContext ?? new RequestContext();
|
|
727
|
+
const llm = await agent.getLLM({ requestContext });
|
|
728
|
+
const provider = llm.getProvider();
|
|
729
|
+
const modelId = llm.getModelId();
|
|
730
|
+
const defaultOptions = await agent.getDefaultOptions({ requestContext });
|
|
731
|
+
const modelSettings = defaultOptions?.modelSettings;
|
|
732
|
+
const model = {
|
|
733
|
+
provider,
|
|
734
|
+
name: modelId,
|
|
735
|
+
...modelSettings?.temperature !== void 0 && { temperature: modelSettings.temperature },
|
|
736
|
+
...modelSettings?.topP !== void 0 && { topP: modelSettings.topP },
|
|
737
|
+
...modelSettings?.frequencyPenalty !== void 0 && { frequencyPenalty: modelSettings.frequencyPenalty },
|
|
738
|
+
...modelSettings?.presencePenalty !== void 0 && { presencePenalty: modelSettings.presencePenalty },
|
|
739
|
+
...modelSettings?.maxOutputTokens !== void 0 && { maxCompletionTokens: modelSettings.maxOutputTokens }
|
|
740
|
+
};
|
|
741
|
+
const instructions = await agent.getInstructions({ requestContext });
|
|
742
|
+
let instructionsStr;
|
|
743
|
+
if (typeof instructions === "string") {
|
|
744
|
+
instructionsStr = instructions;
|
|
745
|
+
} else if (Array.isArray(instructions)) {
|
|
746
|
+
instructionsStr = instructions.map((msg) => {
|
|
747
|
+
if (typeof msg === "string") {
|
|
748
|
+
return msg;
|
|
749
|
+
}
|
|
750
|
+
return typeof msg.content === "string" ? msg.content : "";
|
|
751
|
+
}).filter(Boolean).join("\n\n");
|
|
752
|
+
} else if (instructions && typeof instructions === "object" && "content" in instructions) {
|
|
753
|
+
instructionsStr = typeof instructions.content === "string" ? instructions.content : "";
|
|
754
|
+
} else {
|
|
755
|
+
instructionsStr = "";
|
|
756
|
+
}
|
|
757
|
+
const tools = await agent.listTools({ requestContext });
|
|
758
|
+
const toolKeys = Object.keys(tools || {});
|
|
759
|
+
const workflows = await agent.listWorkflows({ requestContext });
|
|
760
|
+
const workflowKeys = Object.keys(workflows || {});
|
|
761
|
+
const agents = await agent.listAgents({ requestContext });
|
|
762
|
+
const agentKeys = Object.keys(agents || {});
|
|
763
|
+
const memory = await agent.getMemory({ requestContext });
|
|
764
|
+
const memoryConfig = memory?.getConfig();
|
|
765
|
+
const { inputProcessorIds, outputProcessorIds } = await agent.getConfiguredProcessorIds(requestContext);
|
|
766
|
+
const inputProcessorKeys = inputProcessorIds.length > 0 ? inputProcessorIds : void 0;
|
|
767
|
+
const outputProcessorKeys = outputProcessorIds.length > 0 ? outputProcessorIds : void 0;
|
|
768
|
+
let storedScorers;
|
|
769
|
+
const resolvedScorers = await agent.listScorers({ requestContext });
|
|
770
|
+
if (resolvedScorers && Object.keys(resolvedScorers).length > 0) {
|
|
771
|
+
storedScorers = {};
|
|
772
|
+
for (const [key, entry] of Object.entries(resolvedScorers)) {
|
|
773
|
+
storedScorers[key] = {
|
|
774
|
+
...entry.sampling && { sampling: entry.sampling }
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
const storageDefaultOptions = defaultOptions ? {
|
|
779
|
+
maxSteps: defaultOptions?.maxSteps,
|
|
780
|
+
runId: defaultOptions?.runId,
|
|
781
|
+
savePerStep: defaultOptions?.savePerStep,
|
|
782
|
+
activeTools: defaultOptions?.activeTools,
|
|
783
|
+
toolChoice: defaultOptions?.toolChoice,
|
|
784
|
+
modelSettings: defaultOptions?.modelSettings,
|
|
785
|
+
returnScorerData: defaultOptions?.returnScorerData,
|
|
786
|
+
requireToolApproval: defaultOptions?.requireToolApproval,
|
|
787
|
+
autoResumeSuspendedTools: defaultOptions?.autoResumeSuspendedTools,
|
|
788
|
+
toolCallConcurrency: defaultOptions?.toolCallConcurrency,
|
|
789
|
+
maxProcessorRetries: defaultOptions?.maxProcessorRetries,
|
|
790
|
+
includeRawChunks: defaultOptions?.includeRawChunks
|
|
791
|
+
} : void 0;
|
|
792
|
+
const createInput = {
|
|
793
|
+
id: options.newId,
|
|
794
|
+
name: options.newName || `${agent.name} (Clone)`,
|
|
795
|
+
description: agent.getDescription() || void 0,
|
|
796
|
+
instructions: instructionsStr,
|
|
797
|
+
model,
|
|
798
|
+
tools: toolKeys.length > 0 ? Object.fromEntries(toolKeys.map((key) => [key, {}])) : void 0,
|
|
799
|
+
workflows: workflowKeys.length > 0 ? workflowKeys : void 0,
|
|
800
|
+
agents: agentKeys.length > 0 ? agentKeys : void 0,
|
|
801
|
+
memory: memoryConfig,
|
|
802
|
+
inputProcessors: inputProcessorKeys,
|
|
803
|
+
outputProcessors: outputProcessorKeys,
|
|
804
|
+
scorers: storedScorers,
|
|
805
|
+
defaultOptions: storageDefaultOptions,
|
|
806
|
+
metadata: options.metadata,
|
|
807
|
+
authorId: options.authorId
|
|
808
|
+
};
|
|
809
|
+
const adapter = await this.getStorageAdapter();
|
|
810
|
+
await adapter.create(createInput);
|
|
811
|
+
const resolved = await adapter.getByIdResolved(options.newId);
|
|
812
|
+
if (!resolved) {
|
|
813
|
+
throw new Error(`Failed to resolve cloned agent '${options.newId}' after creation.`);
|
|
814
|
+
}
|
|
815
|
+
return resolved;
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
// src/namespaces/prompt.ts
|
|
820
|
+
var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
821
|
+
onCacheEvict(id) {
|
|
822
|
+
this.mastra?.removePromptBlock(id);
|
|
823
|
+
}
|
|
824
|
+
async getStorageAdapter() {
|
|
825
|
+
const storage = this.mastra.getStorage();
|
|
826
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
827
|
+
const store = await storage.getStore("promptBlocks");
|
|
828
|
+
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
829
|
+
return {
|
|
830
|
+
create: (input) => store.create({ promptBlock: input }),
|
|
831
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
832
|
+
update: (input) => store.update(input),
|
|
833
|
+
delete: (id) => store.delete(id),
|
|
834
|
+
list: (args) => store.list(args),
|
|
835
|
+
listResolved: (args) => store.listResolved(args)
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
async preview(blocks, context) {
|
|
839
|
+
this.ensureRegistered();
|
|
840
|
+
const storage = this.mastra.getStorage();
|
|
841
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
842
|
+
const store = await storage.getStore("promptBlocks");
|
|
843
|
+
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
844
|
+
return resolveInstructionBlocks(blocks, context, { promptBlocksStorage: store });
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// src/namespaces/scorer.ts
|
|
849
|
+
import { createScorer } from "@mastra/core/evals";
|
|
850
|
+
var EditorScorerNamespace = class extends CrudEditorNamespace {
|
|
851
|
+
onCacheEvict(id) {
|
|
852
|
+
this.mastra?.removeScorer(id);
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Hydrate a stored scorer definition into a runtime MastraScorer instance
|
|
856
|
+
* and register it on the Mastra instance so it can be discovered via
|
|
857
|
+
* `mastra.getScorer()` / `mastra.getScorerById()`.
|
|
858
|
+
*/
|
|
859
|
+
async hydrate(storedScorer) {
|
|
860
|
+
const scorer = this.resolve(storedScorer);
|
|
861
|
+
if (scorer && this.mastra) {
|
|
862
|
+
this.mastra.addScorer(scorer, storedScorer.id, { source: "stored" });
|
|
863
|
+
}
|
|
864
|
+
return storedScorer;
|
|
865
|
+
}
|
|
866
|
+
async getStorageAdapter() {
|
|
867
|
+
const storage = this.mastra.getStorage();
|
|
868
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
869
|
+
const store = await storage.getStore("scorerDefinitions");
|
|
870
|
+
if (!store) throw new Error("Scorer definitions storage domain is not available");
|
|
871
|
+
return {
|
|
872
|
+
create: (input) => store.create({ scorerDefinition: input }),
|
|
873
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
874
|
+
update: (input) => store.update(input),
|
|
875
|
+
delete: (id) => store.delete(id),
|
|
876
|
+
list: (args) => store.list(args),
|
|
877
|
+
listResolved: (args) => store.listResolved(args)
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Create a MastraScorer instance from a stored scorer definition.
|
|
882
|
+
* Supports:
|
|
883
|
+
* - 'llm-judge': Creates a scorer with a single LLM call using custom instructions
|
|
884
|
+
* - Preset types (e.g., 'bias', 'toxicity'): Not yet supported, returns null
|
|
885
|
+
*/
|
|
886
|
+
resolve(storedScorer) {
|
|
887
|
+
if (storedScorer.type === "llm-judge") {
|
|
888
|
+
if (!storedScorer.instructions) {
|
|
889
|
+
this.logger?.warn(`Stored scorer "${storedScorer.id}" is llm-judge but has no instructions`);
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
const modelConfig = storedScorer.model;
|
|
893
|
+
if (!modelConfig?.provider || !modelConfig?.name) {
|
|
894
|
+
this.logger?.warn(`Stored scorer "${storedScorer.id}" has no valid model configuration`);
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
const model = `${modelConfig.provider}/${modelConfig.name}`;
|
|
898
|
+
const min = storedScorer.scoreRange?.min ?? 0;
|
|
899
|
+
const max = storedScorer.scoreRange?.max ?? 1;
|
|
900
|
+
const scorer = createScorer({
|
|
901
|
+
id: storedScorer.id,
|
|
902
|
+
name: storedScorer.name,
|
|
903
|
+
description: storedScorer.description || `Custom LLM judge scorer: ${storedScorer.name}`,
|
|
904
|
+
type: "agent",
|
|
905
|
+
judge: {
|
|
906
|
+
model,
|
|
907
|
+
instructions: storedScorer.instructions
|
|
908
|
+
}
|
|
909
|
+
}).generateScore({
|
|
910
|
+
description: `Score the output on a scale of ${min} to ${max}`,
|
|
911
|
+
createPrompt: ({ run }) => {
|
|
912
|
+
const input = typeof run.input === "string" ? run.input : JSON.stringify(run.input);
|
|
913
|
+
const output = typeof run.output === "string" ? run.output : JSON.stringify(run.output);
|
|
914
|
+
return `Evaluate the following interaction and provide a score between ${min} and ${max}.
|
|
915
|
+
|
|
916
|
+
Input: ${input}
|
|
917
|
+
|
|
918
|
+
Output: ${output}
|
|
919
|
+
|
|
920
|
+
Provide your score as a JSON object with a "score" field containing a number between ${min} and ${max}.`;
|
|
921
|
+
}
|
|
922
|
+
}).generateReason({
|
|
923
|
+
description: "Explain the reasoning behind the score",
|
|
924
|
+
createPrompt: ({ run, score }) => {
|
|
925
|
+
const input = typeof run.input === "string" ? run.input : JSON.stringify(run.input);
|
|
926
|
+
const output = typeof run.output === "string" ? run.output : JSON.stringify(run.output);
|
|
927
|
+
return `You scored the following interaction ${score} out of ${max}.
|
|
928
|
+
|
|
929
|
+
Input: ${input}
|
|
930
|
+
|
|
931
|
+
Output: ${output}
|
|
932
|
+
|
|
933
|
+
Explain your reasoning for this score in a clear, concise paragraph.`;
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
if (this.mastra) {
|
|
937
|
+
scorer.__registerMastra(this.mastra);
|
|
938
|
+
}
|
|
939
|
+
return scorer;
|
|
940
|
+
}
|
|
941
|
+
this.logger?.warn(
|
|
942
|
+
`Stored scorer "${storedScorer.id}" has type "${storedScorer.type}" which is a preset type. Preset instantiation from stored config is not yet supported.`
|
|
943
|
+
);
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
// src/index.ts
|
|
949
|
+
var MastraEditor = class {
|
|
950
|
+
constructor(config) {
|
|
951
|
+
this.__logger = config?.logger;
|
|
952
|
+
this.agent = new EditorAgentNamespace(this);
|
|
953
|
+
this.prompt = new EditorPromptNamespace(this);
|
|
954
|
+
this.scorer = new EditorScorerNamespace(this);
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Register this editor with a Mastra instance.
|
|
958
|
+
* This gives the editor access to Mastra's storage, tools, workflows, etc.
|
|
959
|
+
*/
|
|
960
|
+
registerWithMastra(mastra) {
|
|
961
|
+
this.__mastra = mastra;
|
|
962
|
+
if (!this.__logger) {
|
|
963
|
+
this.__logger = mastra.getLogger();
|
|
964
|
+
}
|
|
965
|
+
}
|
|
396
966
|
};
|
|
397
967
|
export {
|
|
398
|
-
|
|
968
|
+
CrudEditorNamespace,
|
|
969
|
+
EditorAgentNamespace,
|
|
970
|
+
EditorNamespace,
|
|
971
|
+
EditorPromptNamespace,
|
|
972
|
+
EditorScorerNamespace,
|
|
973
|
+
MastraEditor,
|
|
974
|
+
evaluateRuleGroup,
|
|
975
|
+
renderTemplate,
|
|
976
|
+
resolveInstructionBlocks
|
|
399
977
|
};
|