@mastra/editor 0.4.0-alpha.0 → 0.5.0-alpha.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 +208 -0
- package/dist/index.cjs +461 -22
- package/dist/index.d.cts +126 -4
- package/dist/index.d.ts +126 -4
- package/dist/index.js +457 -22
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ var CrudEditorNamespace = class extends EditorNamespace {
|
|
|
48
48
|
}
|
|
49
49
|
async getById(id, options) {
|
|
50
50
|
this.ensureRegistered();
|
|
51
|
-
const isVersionRequest = options?.versionId || options?.versionNumber;
|
|
51
|
+
const isVersionRequest = options?.versionId || options?.versionNumber || options?.status;
|
|
52
52
|
if (!isVersionRequest) {
|
|
53
53
|
const cached = this._cache.get(id);
|
|
54
54
|
if (cached) {
|
|
@@ -117,8 +117,10 @@ var CrudEditorNamespace = class extends EditorNamespace {
|
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
// src/namespaces/agent.ts
|
|
120
|
+
import { createHash } from "crypto";
|
|
120
121
|
import { Memory } from "@mastra/memory";
|
|
121
122
|
import { Agent } from "@mastra/core/agent";
|
|
123
|
+
import { CompositeVersionedSkillSource } from "@mastra/core/workspace";
|
|
122
124
|
import { convertSchemaToZod } from "@mastra/schema-compat";
|
|
123
125
|
import { RequestContext } from "@mastra/core/request-context";
|
|
124
126
|
|
|
@@ -290,7 +292,7 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
|
|
|
290
292
|
onCacheEvict(_id) {
|
|
291
293
|
}
|
|
292
294
|
async getStorageAdapter() {
|
|
293
|
-
const storage = this.mastra
|
|
295
|
+
const storage = this.mastra?.getStorage();
|
|
294
296
|
if (!storage) throw new Error("Storage is not configured");
|
|
295
297
|
const store = await storage.getStore("mcpClients");
|
|
296
298
|
if (!store) throw new Error("MCP clients storage domain is not available");
|
|
@@ -337,7 +339,7 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
|
|
|
337
339
|
// src/namespaces/agent.ts
|
|
338
340
|
var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
339
341
|
async getStorageAdapter() {
|
|
340
|
-
const storage = this.mastra
|
|
342
|
+
const storage = this.mastra?.getStorage();
|
|
341
343
|
if (!storage) throw new Error("Storage is not configured");
|
|
342
344
|
const store = await storage.getStore("agents");
|
|
343
345
|
if (!store) throw new Error("Agents storage domain is not available");
|
|
@@ -350,7 +352,7 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
350
352
|
const version = options.versionId ? await store.getVersion(options.versionId) : await store.getVersionByNumber(id, options.versionNumber);
|
|
351
353
|
if (!version) return null;
|
|
352
354
|
const {
|
|
353
|
-
id:
|
|
355
|
+
id: versionId,
|
|
354
356
|
agentId: _aId,
|
|
355
357
|
versionNumber: _vn,
|
|
356
358
|
changedFields: _cf,
|
|
@@ -358,9 +360,9 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
358
360
|
createdAt: _ca,
|
|
359
361
|
...snapshotConfig
|
|
360
362
|
} = version;
|
|
361
|
-
return { ...agent, ...snapshotConfig };
|
|
363
|
+
return { ...agent, ...snapshotConfig, resolvedVersionId: versionId };
|
|
362
364
|
}
|
|
363
|
-
return store.getByIdResolved(id);
|
|
365
|
+
return store.getByIdResolved(id, options?.status ? { status: options.status } : void 0);
|
|
364
366
|
},
|
|
365
367
|
update: (input) => store.update(input),
|
|
366
368
|
delete: (id) => store.delete(id),
|
|
@@ -377,6 +379,33 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
377
379
|
onCacheEvict(id) {
|
|
378
380
|
this.mastra?.removeAgent(id);
|
|
379
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Evict all cached agents that reference a given skill ID.
|
|
384
|
+
* Called by EditorSkillNamespace after a skill is published so that
|
|
385
|
+
* subsequent agent.getById() calls re-hydrate with the updated skill version.
|
|
386
|
+
*/
|
|
387
|
+
invalidateAgentsReferencingSkill(skillId) {
|
|
388
|
+
for (const [agentId, agent] of this._cache.entries()) {
|
|
389
|
+
const raw = agent.toRawConfig?.();
|
|
390
|
+
if (!raw?.skills) continue;
|
|
391
|
+
const skillsField = raw.skills;
|
|
392
|
+
let found = false;
|
|
393
|
+
if (Array.isArray(skillsField)) {
|
|
394
|
+
found = skillsField.some(
|
|
395
|
+
(variant) => variant?.value && skillId in variant.value
|
|
396
|
+
);
|
|
397
|
+
} else if (typeof skillsField === "object" && skillsField !== null) {
|
|
398
|
+
found = skillId in skillsField;
|
|
399
|
+
}
|
|
400
|
+
if (found) {
|
|
401
|
+
this.logger?.debug(
|
|
402
|
+
`[invalidateAgentsReferencingSkill] Evicting agent "${agentId}" (references skill "${skillId}")`
|
|
403
|
+
);
|
|
404
|
+
this._cache.delete(agentId);
|
|
405
|
+
this.onCacheEvict(agentId);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
380
409
|
// ============================================================================
|
|
381
410
|
// Private helpers
|
|
382
411
|
// ============================================================================
|
|
@@ -433,6 +462,7 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
433
462
|
const hasConditionalOutputProcessors = storedAgent.outputProcessors != null && this.isConditionalVariants(storedAgent.outputProcessors);
|
|
434
463
|
const hasConditionalDefaultOptions = storedAgent.defaultOptions != null && this.isConditionalVariants(storedAgent.defaultOptions);
|
|
435
464
|
const hasConditionalModel = this.isConditionalVariants(storedAgent.model);
|
|
465
|
+
const hasConditionalWorkspace = storedAgent.workspace != null && this.isConditionalVariants(storedAgent.workspace);
|
|
436
466
|
const isDynamicTools = hasConditionalTools || hasConditionalMCPClients || hasConditionalIntegrationTools;
|
|
437
467
|
let tools;
|
|
438
468
|
if (isDynamicTools) {
|
|
@@ -467,16 +497,20 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
467
497
|
}
|
|
468
498
|
const workflows = hasConditionalWorkflows ? ({ requestContext }) => {
|
|
469
499
|
const ctx = requestContext.toJSON();
|
|
470
|
-
const
|
|
471
|
-
|
|
500
|
+
const variants = storedAgent.workflows;
|
|
501
|
+
const isArrayVariant = Array.isArray(variants[0]?.value);
|
|
502
|
+
const resolved = isArrayVariant ? this.accumulateArrayVariants(variants, ctx) : this.accumulateObjectVariants(
|
|
503
|
+
variants,
|
|
472
504
|
ctx
|
|
473
505
|
);
|
|
474
506
|
return this.resolveStoredWorkflows(resolved);
|
|
475
507
|
} : this.resolveStoredWorkflows(storedAgent.workflows);
|
|
476
508
|
const agents = hasConditionalAgents ? ({ requestContext }) => {
|
|
477
509
|
const ctx = requestContext.toJSON();
|
|
478
|
-
const
|
|
479
|
-
|
|
510
|
+
const variants = storedAgent.agents;
|
|
511
|
+
const isArrayVariant = Array.isArray(variants[0]?.value);
|
|
512
|
+
const resolved = isArrayVariant ? this.accumulateArrayVariants(variants, ctx) : this.accumulateObjectVariants(
|
|
513
|
+
variants,
|
|
480
514
|
ctx
|
|
481
515
|
);
|
|
482
516
|
return this.resolveStoredAgents(resolved);
|
|
@@ -580,6 +614,16 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
580
614
|
};
|
|
581
615
|
}
|
|
582
616
|
const requestContextSchema = storedAgent.requestContextSchema ? convertSchemaToZod(storedAgent.requestContextSchema) : void 0;
|
|
617
|
+
const skillSource = await this.resolveAgentSkillSource(storedAgent.skills);
|
|
618
|
+
const workspace = hasConditionalWorkspace ? async ({ requestContext }) => {
|
|
619
|
+
const ctx = requestContext.toJSON();
|
|
620
|
+
const resolvedRef = this.accumulateObjectVariants(
|
|
621
|
+
storedAgent.workspace,
|
|
622
|
+
ctx
|
|
623
|
+
);
|
|
624
|
+
return this.resolveStoredWorkspace(resolvedRef, skillSource);
|
|
625
|
+
} : await this.resolveStoredWorkspace(storedAgent.workspace, skillSource);
|
|
626
|
+
const skillsFormat = storedAgent.skillsFormat;
|
|
583
627
|
const agent = new Agent({
|
|
584
628
|
id: storedAgent.id,
|
|
585
629
|
name: storedAgent.name,
|
|
@@ -596,7 +640,9 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
596
640
|
outputProcessors,
|
|
597
641
|
rawConfig: storedAgent,
|
|
598
642
|
defaultOptions,
|
|
599
|
-
requestContextSchema
|
|
643
|
+
requestContextSchema,
|
|
644
|
+
workspace,
|
|
645
|
+
...skillsFormat && { skillsFormat }
|
|
600
646
|
});
|
|
601
647
|
this.mastra?.addAgent(agent, storedAgent.id, { source: "stored" });
|
|
602
648
|
this.logger?.debug(`[createAgentFromStoredConfig] Successfully created agent "${storedAgent.id}"`);
|
|
@@ -765,10 +811,13 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
765
811
|
return allTools;
|
|
766
812
|
}
|
|
767
813
|
resolveStoredWorkflows(storedWorkflows) {
|
|
768
|
-
if (!storedWorkflows || storedWorkflows.length === 0)
|
|
814
|
+
if (!storedWorkflows || (Array.isArray(storedWorkflows) ? storedWorkflows.length === 0 : Object.keys(storedWorkflows).length === 0)) {
|
|
815
|
+
return {};
|
|
816
|
+
}
|
|
769
817
|
if (!this.mastra) return {};
|
|
818
|
+
const normalized = Array.isArray(storedWorkflows) ? Object.fromEntries(storedWorkflows.map((key) => [key, {}])) : storedWorkflows;
|
|
770
819
|
const resolvedWorkflows = {};
|
|
771
|
-
for (const workflowKey of
|
|
820
|
+
for (const workflowKey of Object.keys(normalized)) {
|
|
772
821
|
try {
|
|
773
822
|
resolvedWorkflows[workflowKey] = this.mastra.getWorkflow(workflowKey);
|
|
774
823
|
} catch {
|
|
@@ -782,10 +831,13 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
782
831
|
return resolvedWorkflows;
|
|
783
832
|
}
|
|
784
833
|
resolveStoredAgents(storedAgents) {
|
|
785
|
-
if (!storedAgents || storedAgents.length === 0)
|
|
834
|
+
if (!storedAgents || (Array.isArray(storedAgents) ? storedAgents.length === 0 : Object.keys(storedAgents).length === 0)) {
|
|
835
|
+
return {};
|
|
836
|
+
}
|
|
786
837
|
if (!this.mastra) return {};
|
|
838
|
+
const normalized = Array.isArray(storedAgents) ? Object.fromEntries(storedAgents.map((key) => [key, {}])) : storedAgents;
|
|
787
839
|
const resolvedAgents = {};
|
|
788
|
-
for (const agentKey of
|
|
840
|
+
for (const agentKey of Object.keys(normalized)) {
|
|
789
841
|
try {
|
|
790
842
|
resolvedAgents[agentKey] = this.mastra.getAgent(agentKey);
|
|
791
843
|
} catch {
|
|
@@ -962,8 +1014,8 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
962
1014
|
const toolKeys = Object.keys(tools || {});
|
|
963
1015
|
const workflows = await agent.listWorkflows({ requestContext });
|
|
964
1016
|
const workflowKeys = Object.keys(workflows || {});
|
|
965
|
-
const
|
|
966
|
-
const agentKeys = Object.keys(
|
|
1017
|
+
const agentsResolved = await agent.listAgents({ requestContext });
|
|
1018
|
+
const agentKeys = Object.keys(agentsResolved || {});
|
|
967
1019
|
const memory = await agent.getMemory({ requestContext });
|
|
968
1020
|
const memoryConfig = memory?.getConfig();
|
|
969
1021
|
const { inputProcessorIds, outputProcessorIds } = await agent.getConfiguredProcessorIds(requestContext);
|
|
@@ -1000,8 +1052,8 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
1000
1052
|
instructions: instructionsStr,
|
|
1001
1053
|
model,
|
|
1002
1054
|
tools: toolKeys.length > 0 ? Object.fromEntries(toolKeys.map((key) => [key, {}])) : void 0,
|
|
1003
|
-
workflows: workflowKeys.length > 0 ? workflowKeys : void 0,
|
|
1004
|
-
agents: agentKeys.length > 0 ? agentKeys : void 0,
|
|
1055
|
+
workflows: workflowKeys.length > 0 ? Object.fromEntries(workflowKeys.map((key) => [key, {}])) : void 0,
|
|
1056
|
+
agents: agentKeys.length > 0 ? Object.fromEntries(agentKeys.map((key) => [key, {}])) : void 0,
|
|
1005
1057
|
memory: memoryConfig,
|
|
1006
1058
|
inputProcessors: inputProcessorKeys,
|
|
1007
1059
|
outputProcessors: outputProcessorKeys,
|
|
@@ -1018,6 +1070,105 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
1018
1070
|
}
|
|
1019
1071
|
return resolved;
|
|
1020
1072
|
}
|
|
1073
|
+
// ============================================================================
|
|
1074
|
+
// Workspace Resolution
|
|
1075
|
+
// ============================================================================
|
|
1076
|
+
/**
|
|
1077
|
+
* Resolve a stored workspace reference to a runtime Workspace instance.
|
|
1078
|
+
* Handles both ID-based references (looked up from editor.workspace) and
|
|
1079
|
+
* inline workspace configurations (hydrated directly).
|
|
1080
|
+
*
|
|
1081
|
+
* When a skillSource is provided (from resolveAgentSkillSource), it is passed
|
|
1082
|
+
* to the workspace hydration so the workspace uses versioned blob-backed skills
|
|
1083
|
+
* instead of filesystem-based discovery.
|
|
1084
|
+
*/
|
|
1085
|
+
async resolveStoredWorkspace(workspaceRef, skillSource) {
|
|
1086
|
+
if (!workspaceRef) return void 0;
|
|
1087
|
+
const workspaceNs = this.editor.workspace;
|
|
1088
|
+
if (!workspaceNs) {
|
|
1089
|
+
this.logger?.warn("[resolveStoredWorkspace] No workspace namespace available on editor");
|
|
1090
|
+
return void 0;
|
|
1091
|
+
}
|
|
1092
|
+
const hydrateOptions = skillSource ? { skillSource } : void 0;
|
|
1093
|
+
if (workspaceRef.type === "id") {
|
|
1094
|
+
const resolved = await workspaceNs.getById(workspaceRef.workspaceId);
|
|
1095
|
+
if (!resolved) {
|
|
1096
|
+
this.logger?.warn(
|
|
1097
|
+
`[resolveStoredWorkspace] Workspace '${workspaceRef.workspaceId}' not found in storage, skipping`
|
|
1098
|
+
);
|
|
1099
|
+
return void 0;
|
|
1100
|
+
}
|
|
1101
|
+
return workspaceNs.hydrateSnapshotToWorkspace(workspaceRef.workspaceId, resolved, hydrateOptions);
|
|
1102
|
+
}
|
|
1103
|
+
if (workspaceRef.type === "inline") {
|
|
1104
|
+
const configHash = createHash("sha256").update(JSON.stringify(workspaceRef.config)).digest("hex").slice(0, 12);
|
|
1105
|
+
return workspaceNs.hydrateSnapshotToWorkspace(`inline-${configHash}`, workspaceRef.config, hydrateOptions);
|
|
1106
|
+
}
|
|
1107
|
+
return void 0;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Resolve agent-level skill configurations into a CompositeVersionedSkillSource.
|
|
1111
|
+
*
|
|
1112
|
+
* For each skill in the agent's `skills` map, checks the resolution strategy:
|
|
1113
|
+
* - `pin: '<versionId>'` → reads the specific version's tree from the DB
|
|
1114
|
+
* - `strategy: 'latest'` → reads the skill's active version tree
|
|
1115
|
+
* - `strategy: 'live'` or no strategy → skips (uses filesystem-based discovery)
|
|
1116
|
+
*
|
|
1117
|
+
* Returns a CompositeVersionedSkillSource if any versioned skills were resolved,
|
|
1118
|
+
* or undefined if all skills use filesystem-based discovery.
|
|
1119
|
+
*/
|
|
1120
|
+
async resolveAgentSkillSource(skills) {
|
|
1121
|
+
if (!skills || typeof skills !== "object") return void 0;
|
|
1122
|
+
const skillConfigs = Array.isArray(skills) ? void 0 : skills;
|
|
1123
|
+
if (!skillConfigs || Object.keys(skillConfigs).length === 0) return void 0;
|
|
1124
|
+
const storage = this.mastra?.getStorage();
|
|
1125
|
+
if (!storage) return void 0;
|
|
1126
|
+
const skillStore = await storage.getStore("skills");
|
|
1127
|
+
if (!skillStore) return void 0;
|
|
1128
|
+
const blobStore = await this.editor.resolveBlobStore();
|
|
1129
|
+
if (!blobStore) return void 0;
|
|
1130
|
+
const versionedEntries = [];
|
|
1131
|
+
for (const [skillId, config] of Object.entries(skillConfigs)) {
|
|
1132
|
+
if (!config) continue;
|
|
1133
|
+
const isPinned = !!config.pin;
|
|
1134
|
+
const isLatest = config.strategy === "latest";
|
|
1135
|
+
if (!isPinned && !isLatest) {
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
try {
|
|
1139
|
+
let version;
|
|
1140
|
+
let dirName;
|
|
1141
|
+
if (isPinned) {
|
|
1142
|
+
version = await skillStore.getVersion(config.pin);
|
|
1143
|
+
dirName = version?.name || skillId;
|
|
1144
|
+
} else {
|
|
1145
|
+
const resolved = await skillStore.getByIdResolved(skillId);
|
|
1146
|
+
if (resolved?.activeVersionId) {
|
|
1147
|
+
version = await skillStore.getVersion(resolved.activeVersionId);
|
|
1148
|
+
}
|
|
1149
|
+
if (!version) {
|
|
1150
|
+
version = await skillStore.getLatestVersion(skillId);
|
|
1151
|
+
}
|
|
1152
|
+
dirName = resolved?.name || version?.name || skillId;
|
|
1153
|
+
}
|
|
1154
|
+
if (!version?.tree) {
|
|
1155
|
+
this.logger?.warn(
|
|
1156
|
+
`[resolveAgentSkillSource] Skill '${skillId}' version has no tree manifest, skipping versioned resolution`
|
|
1157
|
+
);
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
versionedEntries.push({
|
|
1161
|
+
dirName,
|
|
1162
|
+
tree: version.tree,
|
|
1163
|
+
versionCreatedAt: version.createdAt
|
|
1164
|
+
});
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
this.logger?.warn(`[resolveAgentSkillSource] Failed to resolve version for skill '${skillId}': ${error}`);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (versionedEntries.length === 0) return void 0;
|
|
1170
|
+
return new CompositeVersionedSkillSource(versionedEntries, blobStore);
|
|
1171
|
+
}
|
|
1021
1172
|
};
|
|
1022
1173
|
|
|
1023
1174
|
// src/namespaces/prompt.ts
|
|
@@ -1026,7 +1177,7 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
|
1026
1177
|
this.mastra?.removePromptBlock(id);
|
|
1027
1178
|
}
|
|
1028
1179
|
async getStorageAdapter() {
|
|
1029
|
-
const storage = this.mastra
|
|
1180
|
+
const storage = this.mastra?.getStorage();
|
|
1030
1181
|
if (!storage) throw new Error("Storage is not configured");
|
|
1031
1182
|
const store = await storage.getStore("promptBlocks");
|
|
1032
1183
|
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
@@ -1041,7 +1192,7 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
|
1041
1192
|
}
|
|
1042
1193
|
async preview(blocks, context) {
|
|
1043
1194
|
this.ensureRegistered();
|
|
1044
|
-
const storage = this.mastra
|
|
1195
|
+
const storage = this.mastra?.getStorage();
|
|
1045
1196
|
if (!storage) throw new Error("Storage is not configured");
|
|
1046
1197
|
const store = await storage.getStore("promptBlocks");
|
|
1047
1198
|
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
@@ -1068,7 +1219,7 @@ var EditorScorerNamespace = class extends CrudEditorNamespace {
|
|
|
1068
1219
|
return storedScorer;
|
|
1069
1220
|
}
|
|
1070
1221
|
async getStorageAdapter() {
|
|
1071
|
-
const storage = this.mastra
|
|
1222
|
+
const storage = this.mastra?.getStorage();
|
|
1072
1223
|
if (!storage) throw new Error("Storage is not configured");
|
|
1073
1224
|
const store = await storage.getStore("scorerDefinitions");
|
|
1074
1225
|
if (!store) throw new Error("Scorer definitions storage domain is not available");
|
|
@@ -1149,15 +1300,255 @@ Explain your reasoning for this score in a clear, concise paragraph.`;
|
|
|
1149
1300
|
}
|
|
1150
1301
|
};
|
|
1151
1302
|
|
|
1303
|
+
// src/namespaces/workspace.ts
|
|
1304
|
+
import { Workspace as Workspace2 } from "@mastra/core/workspace";
|
|
1305
|
+
var EditorWorkspaceNamespace = class extends CrudEditorNamespace {
|
|
1306
|
+
onCacheEvict(_id) {
|
|
1307
|
+
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Hydrate a stored workspace snapshot config into a runtime Workspace instance.
|
|
1310
|
+
* Resolves provider strings to actual instances using the editor's registries.
|
|
1311
|
+
*
|
|
1312
|
+
* This is NOT called from the CrudEditorNamespace flow — it is a public utility
|
|
1313
|
+
* used by EditorAgentNamespace during agent hydration.
|
|
1314
|
+
*/
|
|
1315
|
+
async hydrateSnapshotToWorkspace(id, snapshot, options) {
|
|
1316
|
+
const config = {
|
|
1317
|
+
id,
|
|
1318
|
+
name: snapshot.name
|
|
1319
|
+
};
|
|
1320
|
+
if (snapshot.filesystem) {
|
|
1321
|
+
config.filesystem = await this.resolveFilesystem(snapshot.filesystem);
|
|
1322
|
+
}
|
|
1323
|
+
if (snapshot.sandbox) {
|
|
1324
|
+
config.sandbox = await this.resolveSandbox(snapshot.sandbox);
|
|
1325
|
+
}
|
|
1326
|
+
if (snapshot.mounts) {
|
|
1327
|
+
const mounts = {};
|
|
1328
|
+
for (const [path, fsConfig] of Object.entries(snapshot.mounts)) {
|
|
1329
|
+
mounts[path] = await this.resolveFilesystem(fsConfig);
|
|
1330
|
+
}
|
|
1331
|
+
config.mounts = mounts;
|
|
1332
|
+
}
|
|
1333
|
+
if (snapshot.search) {
|
|
1334
|
+
if (snapshot.search.bm25) {
|
|
1335
|
+
config.bm25 = snapshot.search.bm25;
|
|
1336
|
+
}
|
|
1337
|
+
if (snapshot.search.searchIndexName) {
|
|
1338
|
+
config.searchIndexName = snapshot.search.searchIndexName;
|
|
1339
|
+
}
|
|
1340
|
+
if (snapshot.search.autoIndexPaths) {
|
|
1341
|
+
config.autoIndexPaths = snapshot.search.autoIndexPaths;
|
|
1342
|
+
}
|
|
1343
|
+
if (snapshot.search.vectorProvider && this.mastra) {
|
|
1344
|
+
const vectors = this.mastra.listVectors();
|
|
1345
|
+
const vectorStore = vectors?.[snapshot.search.vectorProvider];
|
|
1346
|
+
if (vectorStore) {
|
|
1347
|
+
config.vectorStore = vectorStore;
|
|
1348
|
+
} else {
|
|
1349
|
+
this.logger?.warn(
|
|
1350
|
+
`Vector provider "${snapshot.search.vectorProvider}" not found in Mastra instance. Workspace search will be limited to BM25 only.`
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
if (config.vectorStore && !config.embedder) {
|
|
1355
|
+
this.logger?.warn(
|
|
1356
|
+
`Workspace has a vector store configured but no embedder. Vector/hybrid search will not be available. Configure an embedder to enable semantic search.`
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
if (options?.skillSource) {
|
|
1361
|
+
config.skillSource = options.skillSource;
|
|
1362
|
+
config.skills = ["."];
|
|
1363
|
+
} else if (snapshot.skills && snapshot.skills.length > 0) {
|
|
1364
|
+
config.skills = snapshot.skills;
|
|
1365
|
+
}
|
|
1366
|
+
if (snapshot.tools) {
|
|
1367
|
+
config.tools = snapshot.tools;
|
|
1368
|
+
}
|
|
1369
|
+
if (snapshot.autoSync !== void 0) {
|
|
1370
|
+
config.autoSync = snapshot.autoSync;
|
|
1371
|
+
}
|
|
1372
|
+
if (snapshot.operationTimeout !== void 0) {
|
|
1373
|
+
config.operationTimeout = snapshot.operationTimeout;
|
|
1374
|
+
}
|
|
1375
|
+
return new Workspace2(config);
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
|
|
1379
|
+
* Looks up the provider by ID in the editor's registry (which includes built-in providers).
|
|
1380
|
+
*/
|
|
1381
|
+
async resolveFilesystem(fsConfig) {
|
|
1382
|
+
const provider = this.editor.__filesystems.get(fsConfig.provider);
|
|
1383
|
+
if (!provider) {
|
|
1384
|
+
throw new Error(
|
|
1385
|
+
`Filesystem provider "${fsConfig.provider}" is not registered. Register it via new MastraEditor({ filesystems: [yourProvider] })`
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
const config = { ...fsConfig.config, readOnly: fsConfig.readOnly };
|
|
1389
|
+
return await provider.createFilesystem(config);
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Resolve a stored sandbox config to a runtime WorkspaceSandbox instance.
|
|
1393
|
+
* Looks up the provider by ID in the editor's registry (which includes built-in providers).
|
|
1394
|
+
*/
|
|
1395
|
+
async resolveSandbox(sandboxConfig) {
|
|
1396
|
+
const provider = this.editor.__sandboxes.get(sandboxConfig.provider);
|
|
1397
|
+
if (!provider) {
|
|
1398
|
+
throw new Error(
|
|
1399
|
+
`Sandbox provider "${sandboxConfig.provider}" is not registered. Register it via new MastraEditor({ sandboxes: [yourProvider] })`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
return await provider.createSandbox(sandboxConfig.config);
|
|
1403
|
+
}
|
|
1404
|
+
async getStorageAdapter() {
|
|
1405
|
+
const storage = this.mastra?.getStorage();
|
|
1406
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1407
|
+
const store = await storage.getStore("workspaces");
|
|
1408
|
+
if (!store) throw new Error("Workspaces storage domain is not available");
|
|
1409
|
+
return {
|
|
1410
|
+
create: (input) => store.create({ workspace: input }),
|
|
1411
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
1412
|
+
update: (input) => store.update(input),
|
|
1413
|
+
delete: (id) => store.delete(id),
|
|
1414
|
+
list: (args) => store.list(args),
|
|
1415
|
+
listResolved: (args) => store.listResolved(args)
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
// src/namespaces/skill.ts
|
|
1421
|
+
import { publishSkillFromSource } from "@mastra/core/workspace";
|
|
1422
|
+
var EditorSkillNamespace = class extends CrudEditorNamespace {
|
|
1423
|
+
onCacheEvict(_id) {
|
|
1424
|
+
}
|
|
1425
|
+
async getStorageAdapter() {
|
|
1426
|
+
const storage = this.mastra?.getStorage();
|
|
1427
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1428
|
+
const store = await storage.getStore("skills");
|
|
1429
|
+
if (!store) throw new Error("Skills storage domain is not available");
|
|
1430
|
+
return {
|
|
1431
|
+
create: (input) => store.create({ skill: input }),
|
|
1432
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
1433
|
+
update: (input) => store.update(input),
|
|
1434
|
+
delete: (id) => store.delete(id),
|
|
1435
|
+
list: (args) => store.list(args),
|
|
1436
|
+
listResolved: (args) => store.listResolved(args)
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Publish a skill from a live filesystem source.
|
|
1441
|
+
* Walks the skill directory, hashes files into the blob store,
|
|
1442
|
+
* creates a new version with the tree manifest, and sets activeVersionId.
|
|
1443
|
+
*/
|
|
1444
|
+
async publish(skillId, source, skillPath) {
|
|
1445
|
+
this.ensureRegistered();
|
|
1446
|
+
const storage = this.mastra?.getStorage();
|
|
1447
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1448
|
+
const skillStore = await storage.getStore("skills");
|
|
1449
|
+
if (!skillStore) throw new Error("Skills storage domain is not available");
|
|
1450
|
+
const blobStore = await this.editor.resolveBlobStore();
|
|
1451
|
+
if (!blobStore)
|
|
1452
|
+
throw new Error("No blob store is configured. Register one via new MastraEditor({ blobStores: [...] })");
|
|
1453
|
+
const { snapshot, tree } = await publishSkillFromSource(source, skillPath, blobStore);
|
|
1454
|
+
await skillStore.update({
|
|
1455
|
+
id: skillId,
|
|
1456
|
+
...snapshot,
|
|
1457
|
+
tree,
|
|
1458
|
+
status: "published"
|
|
1459
|
+
});
|
|
1460
|
+
const latestVersion = await skillStore.getLatestVersion(skillId);
|
|
1461
|
+
if (!latestVersion) {
|
|
1462
|
+
throw new Error(`Failed to retrieve version after publishing skill "${skillId}"`);
|
|
1463
|
+
}
|
|
1464
|
+
await skillStore.update({
|
|
1465
|
+
id: skillId,
|
|
1466
|
+
activeVersionId: latestVersion.id
|
|
1467
|
+
});
|
|
1468
|
+
const resolved = await skillStore.getByIdResolved(skillId);
|
|
1469
|
+
if (!resolved) throw new Error(`Failed to resolve skill ${skillId} after publish`);
|
|
1470
|
+
this.clearCache(skillId);
|
|
1471
|
+
this.editor.agent.invalidateAgentsReferencingSkill(skillId);
|
|
1472
|
+
return resolved;
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
// src/providers.ts
|
|
1477
|
+
import { LocalFilesystem } from "@mastra/core/workspace";
|
|
1478
|
+
import { LocalSandbox } from "@mastra/core/workspace";
|
|
1479
|
+
var localFilesystemProvider = {
|
|
1480
|
+
id: "local",
|
|
1481
|
+
name: "Local Filesystem",
|
|
1482
|
+
description: "A folder on the local disk",
|
|
1483
|
+
configSchema: {
|
|
1484
|
+
type: "object",
|
|
1485
|
+
required: ["basePath"],
|
|
1486
|
+
properties: {
|
|
1487
|
+
basePath: { type: "string", description: "Base directory path on disk" },
|
|
1488
|
+
contained: {
|
|
1489
|
+
type: "boolean",
|
|
1490
|
+
description: "Restrict operations to stay within basePath",
|
|
1491
|
+
default: true
|
|
1492
|
+
},
|
|
1493
|
+
readOnly: {
|
|
1494
|
+
type: "boolean",
|
|
1495
|
+
description: "Block all write operations",
|
|
1496
|
+
default: false
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
},
|
|
1500
|
+
createFilesystem: (config) => new LocalFilesystem(config)
|
|
1501
|
+
};
|
|
1502
|
+
var localSandboxProvider = {
|
|
1503
|
+
id: "local",
|
|
1504
|
+
name: "Local Sandbox",
|
|
1505
|
+
description: "Execute commands on the local machine",
|
|
1506
|
+
configSchema: {
|
|
1507
|
+
type: "object",
|
|
1508
|
+
properties: {
|
|
1509
|
+
workingDirectory: { type: "string", description: "Working directory for command execution" },
|
|
1510
|
+
timeout: { type: "number", description: "Default timeout for operations in ms" },
|
|
1511
|
+
isolation: {
|
|
1512
|
+
type: "string",
|
|
1513
|
+
enum: ["none", "seatbelt", "bwrap"],
|
|
1514
|
+
description: "Isolation backend for sandboxed execution",
|
|
1515
|
+
default: "none"
|
|
1516
|
+
},
|
|
1517
|
+
env: {
|
|
1518
|
+
type: "object",
|
|
1519
|
+
description: "Environment variables for command execution",
|
|
1520
|
+
additionalProperties: { type: "string" }
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
},
|
|
1524
|
+
createSandbox: (config) => new LocalSandbox(config)
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1152
1527
|
// src/index.ts
|
|
1153
1528
|
var MastraEditor = class {
|
|
1154
1529
|
constructor(config) {
|
|
1155
1530
|
this.__logger = config?.logger;
|
|
1156
1531
|
this.__toolProviders = config?.toolProviders ?? {};
|
|
1532
|
+
this.__filesystems = /* @__PURE__ */ new Map();
|
|
1533
|
+
this.__filesystems.set(localFilesystemProvider.id, localFilesystemProvider);
|
|
1534
|
+
for (const [id, provider] of Object.entries(config?.filesystems ?? {})) {
|
|
1535
|
+
this.__filesystems.set(id, provider);
|
|
1536
|
+
}
|
|
1537
|
+
this.__sandboxes = /* @__PURE__ */ new Map();
|
|
1538
|
+
this.__sandboxes.set(localSandboxProvider.id, localSandboxProvider);
|
|
1539
|
+
for (const [id, provider] of Object.entries(config?.sandboxes ?? {})) {
|
|
1540
|
+
this.__sandboxes.set(id, provider);
|
|
1541
|
+
}
|
|
1542
|
+
this.__blobStores = /* @__PURE__ */ new Map();
|
|
1543
|
+
for (const [id, provider] of Object.entries(config?.blobStores ?? {})) {
|
|
1544
|
+
this.__blobStores.set(id, provider);
|
|
1545
|
+
}
|
|
1157
1546
|
this.agent = new EditorAgentNamespace(this);
|
|
1158
1547
|
this.mcp = new EditorMCPNamespace(this);
|
|
1159
1548
|
this.prompt = new EditorPromptNamespace(this);
|
|
1160
1549
|
this.scorer = new EditorScorerNamespace(this);
|
|
1550
|
+
this.workspace = new EditorWorkspaceNamespace(this);
|
|
1551
|
+
this.skill = new EditorSkillNamespace(this);
|
|
1161
1552
|
}
|
|
1162
1553
|
/**
|
|
1163
1554
|
* Register this editor with a Mastra instance.
|
|
@@ -1177,6 +1568,46 @@ var MastraEditor = class {
|
|
|
1177
1568
|
getToolProviders() {
|
|
1178
1569
|
return this.__toolProviders;
|
|
1179
1570
|
}
|
|
1571
|
+
/** List all registered filesystem providers */
|
|
1572
|
+
getFilesystemProviders() {
|
|
1573
|
+
return Array.from(this.__filesystems.values());
|
|
1574
|
+
}
|
|
1575
|
+
/** List all registered sandbox providers */
|
|
1576
|
+
getSandboxProviders() {
|
|
1577
|
+
return Array.from(this.__sandboxes.values());
|
|
1578
|
+
}
|
|
1579
|
+
/** List all registered blob store providers */
|
|
1580
|
+
getBlobStoreProviders() {
|
|
1581
|
+
return Array.from(this.__blobStores.values());
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* Resolve a blob store from the provider registry, or fall back to the
|
|
1585
|
+
* storage backend's blobs domain.
|
|
1586
|
+
*
|
|
1587
|
+
* @param providerId - If specified, look up a registered provider by ID
|
|
1588
|
+
* and create a blob store from the given config. If omitted, falls back
|
|
1589
|
+
* to `storage.getStore('blobs')`.
|
|
1590
|
+
* @param providerConfig - Provider-specific configuration (only used when
|
|
1591
|
+
* `providerId` is specified).
|
|
1592
|
+
*/
|
|
1593
|
+
async resolveBlobStore(providerId, providerConfig) {
|
|
1594
|
+
if (providerId) {
|
|
1595
|
+
const provider = this.__blobStores.get(providerId);
|
|
1596
|
+
if (!provider) {
|
|
1597
|
+
throw new Error(
|
|
1598
|
+
`Blob store provider "${providerId}" is not registered. Register it via new MastraEditor({ blobStores: { '${providerId}': yourProvider } })`
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
const blobStore2 = await provider.createBlobStore(providerConfig ?? {});
|
|
1602
|
+
await blobStore2.init();
|
|
1603
|
+
return blobStore2;
|
|
1604
|
+
}
|
|
1605
|
+
const storage = this.__mastra?.getStorage();
|
|
1606
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1607
|
+
const blobStore = await storage.getStore("blobs");
|
|
1608
|
+
if (!blobStore) throw new Error("Blob storage domain is not available");
|
|
1609
|
+
return blobStore;
|
|
1610
|
+
}
|
|
1180
1611
|
};
|
|
1181
1612
|
export {
|
|
1182
1613
|
CrudEditorNamespace,
|
|
@@ -1185,8 +1616,12 @@ export {
|
|
|
1185
1616
|
EditorNamespace,
|
|
1186
1617
|
EditorPromptNamespace,
|
|
1187
1618
|
EditorScorerNamespace,
|
|
1619
|
+
EditorSkillNamespace,
|
|
1620
|
+
EditorWorkspaceNamespace,
|
|
1188
1621
|
MastraEditor,
|
|
1189
1622
|
evaluateRuleGroup,
|
|
1623
|
+
localFilesystemProvider,
|
|
1624
|
+
localSandboxProvider,
|
|
1190
1625
|
renderTemplate,
|
|
1191
1626
|
resolveInstructionBlocks
|
|
1192
1627
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-alpha.0",
|
|
4
4
|
"description": "Mastra Editor for agent management and instantiation",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@arcadeai/arcadejs": "^2.2.0",
|
|
56
56
|
"@composio/core": "^0.6.3",
|
|
57
57
|
"@composio/mastra": "^0.6.3",
|
|
58
|
-
"@mastra/memory": "1.
|
|
58
|
+
"@mastra/memory": "1.4.0-alpha.0",
|
|
59
59
|
"@mastra/schema-compat": "1.1.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
@@ -63,11 +63,11 @@
|
|
|
63
63
|
"typescript": "^5.9.3",
|
|
64
64
|
"vitest": "4.0.16",
|
|
65
65
|
"zod": "^3.25.76",
|
|
66
|
-
"@internal/ai-
|
|
67
|
-
"@internal/ai-sdk-v5": "0.0.
|
|
68
|
-
"@internal/ai-
|
|
69
|
-
"@mastra/core": "1.
|
|
70
|
-
"@mastra/libsql": "1.
|
|
66
|
+
"@internal/ai-sdk-v4": "0.0.6",
|
|
67
|
+
"@internal/ai-sdk-v5": "0.0.6",
|
|
68
|
+
"@internal/ai-v6": "0.0.6",
|
|
69
|
+
"@mastra/core": "1.5.0-alpha.0",
|
|
70
|
+
"@mastra/libsql": "1.5.0-alpha.0"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"@mastra/core": ">=1.0.0-0 <2.0.0-0",
|