@mastra/editor 0.4.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 +103 -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 +5 -5
package/dist/index.cjs
CHANGED
|
@@ -36,8 +36,12 @@ __export(index_exports, {
|
|
|
36
36
|
EditorNamespace: () => EditorNamespace,
|
|
37
37
|
EditorPromptNamespace: () => EditorPromptNamespace,
|
|
38
38
|
EditorScorerNamespace: () => EditorScorerNamespace,
|
|
39
|
+
EditorSkillNamespace: () => EditorSkillNamespace,
|
|
40
|
+
EditorWorkspaceNamespace: () => EditorWorkspaceNamespace,
|
|
39
41
|
MastraEditor: () => MastraEditor,
|
|
40
42
|
evaluateRuleGroup: () => evaluateRuleGroup,
|
|
43
|
+
localFilesystemProvider: () => localFilesystemProvider,
|
|
44
|
+
localSandboxProvider: () => localSandboxProvider,
|
|
41
45
|
renderTemplate: () => renderTemplate,
|
|
42
46
|
resolveInstructionBlocks: () => resolveInstructionBlocks
|
|
43
47
|
});
|
|
@@ -93,7 +97,7 @@ var CrudEditorNamespace = class extends EditorNamespace {
|
|
|
93
97
|
}
|
|
94
98
|
async getById(id, options) {
|
|
95
99
|
this.ensureRegistered();
|
|
96
|
-
const isVersionRequest = options?.versionId || options?.versionNumber;
|
|
100
|
+
const isVersionRequest = options?.versionId || options?.versionNumber || options?.status;
|
|
97
101
|
if (!isVersionRequest) {
|
|
98
102
|
const cached = this._cache.get(id);
|
|
99
103
|
if (cached) {
|
|
@@ -162,8 +166,10 @@ var CrudEditorNamespace = class extends EditorNamespace {
|
|
|
162
166
|
};
|
|
163
167
|
|
|
164
168
|
// src/namespaces/agent.ts
|
|
169
|
+
var import_node_crypto = require("crypto");
|
|
165
170
|
var import_memory = require("@mastra/memory");
|
|
166
171
|
var import_agent = require("@mastra/core/agent");
|
|
172
|
+
var import_workspace = require("@mastra/core/workspace");
|
|
167
173
|
var import_schema_compat = require("@mastra/schema-compat");
|
|
168
174
|
var import_request_context = require("@mastra/core/request-context");
|
|
169
175
|
|
|
@@ -335,7 +341,7 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
|
|
|
335
341
|
onCacheEvict(_id) {
|
|
336
342
|
}
|
|
337
343
|
async getStorageAdapter() {
|
|
338
|
-
const storage = this.mastra
|
|
344
|
+
const storage = this.mastra?.getStorage();
|
|
339
345
|
if (!storage) throw new Error("Storage is not configured");
|
|
340
346
|
const store = await storage.getStore("mcpClients");
|
|
341
347
|
if (!store) throw new Error("MCP clients storage domain is not available");
|
|
@@ -382,7 +388,7 @@ var EditorMCPNamespace = class _EditorMCPNamespace extends CrudEditorNamespace {
|
|
|
382
388
|
// src/namespaces/agent.ts
|
|
383
389
|
var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
384
390
|
async getStorageAdapter() {
|
|
385
|
-
const storage = this.mastra
|
|
391
|
+
const storage = this.mastra?.getStorage();
|
|
386
392
|
if (!storage) throw new Error("Storage is not configured");
|
|
387
393
|
const store = await storage.getStore("agents");
|
|
388
394
|
if (!store) throw new Error("Agents storage domain is not available");
|
|
@@ -395,7 +401,7 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
395
401
|
const version = options.versionId ? await store.getVersion(options.versionId) : await store.getVersionByNumber(id, options.versionNumber);
|
|
396
402
|
if (!version) return null;
|
|
397
403
|
const {
|
|
398
|
-
id:
|
|
404
|
+
id: versionId,
|
|
399
405
|
agentId: _aId,
|
|
400
406
|
versionNumber: _vn,
|
|
401
407
|
changedFields: _cf,
|
|
@@ -403,9 +409,9 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
403
409
|
createdAt: _ca,
|
|
404
410
|
...snapshotConfig
|
|
405
411
|
} = version;
|
|
406
|
-
return { ...agent, ...snapshotConfig };
|
|
412
|
+
return { ...agent, ...snapshotConfig, resolvedVersionId: versionId };
|
|
407
413
|
}
|
|
408
|
-
return store.getByIdResolved(id);
|
|
414
|
+
return store.getByIdResolved(id, options?.status ? { status: options.status } : void 0);
|
|
409
415
|
},
|
|
410
416
|
update: (input) => store.update(input),
|
|
411
417
|
delete: (id) => store.delete(id),
|
|
@@ -422,6 +428,33 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
422
428
|
onCacheEvict(id) {
|
|
423
429
|
this.mastra?.removeAgent(id);
|
|
424
430
|
}
|
|
431
|
+
/**
|
|
432
|
+
* Evict all cached agents that reference a given skill ID.
|
|
433
|
+
* Called by EditorSkillNamespace after a skill is published so that
|
|
434
|
+
* subsequent agent.getById() calls re-hydrate with the updated skill version.
|
|
435
|
+
*/
|
|
436
|
+
invalidateAgentsReferencingSkill(skillId) {
|
|
437
|
+
for (const [agentId, agent] of this._cache.entries()) {
|
|
438
|
+
const raw = agent.toRawConfig?.();
|
|
439
|
+
if (!raw?.skills) continue;
|
|
440
|
+
const skillsField = raw.skills;
|
|
441
|
+
let found = false;
|
|
442
|
+
if (Array.isArray(skillsField)) {
|
|
443
|
+
found = skillsField.some(
|
|
444
|
+
(variant) => variant?.value && skillId in variant.value
|
|
445
|
+
);
|
|
446
|
+
} else if (typeof skillsField === "object" && skillsField !== null) {
|
|
447
|
+
found = skillId in skillsField;
|
|
448
|
+
}
|
|
449
|
+
if (found) {
|
|
450
|
+
this.logger?.debug(
|
|
451
|
+
`[invalidateAgentsReferencingSkill] Evicting agent "${agentId}" (references skill "${skillId}")`
|
|
452
|
+
);
|
|
453
|
+
this._cache.delete(agentId);
|
|
454
|
+
this.onCacheEvict(agentId);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
425
458
|
// ============================================================================
|
|
426
459
|
// Private helpers
|
|
427
460
|
// ============================================================================
|
|
@@ -478,6 +511,7 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
478
511
|
const hasConditionalOutputProcessors = storedAgent.outputProcessors != null && this.isConditionalVariants(storedAgent.outputProcessors);
|
|
479
512
|
const hasConditionalDefaultOptions = storedAgent.defaultOptions != null && this.isConditionalVariants(storedAgent.defaultOptions);
|
|
480
513
|
const hasConditionalModel = this.isConditionalVariants(storedAgent.model);
|
|
514
|
+
const hasConditionalWorkspace = storedAgent.workspace != null && this.isConditionalVariants(storedAgent.workspace);
|
|
481
515
|
const isDynamicTools = hasConditionalTools || hasConditionalMCPClients || hasConditionalIntegrationTools;
|
|
482
516
|
let tools;
|
|
483
517
|
if (isDynamicTools) {
|
|
@@ -512,16 +546,20 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
512
546
|
}
|
|
513
547
|
const workflows = hasConditionalWorkflows ? ({ requestContext }) => {
|
|
514
548
|
const ctx = requestContext.toJSON();
|
|
515
|
-
const
|
|
516
|
-
|
|
549
|
+
const variants = storedAgent.workflows;
|
|
550
|
+
const isArrayVariant = Array.isArray(variants[0]?.value);
|
|
551
|
+
const resolved = isArrayVariant ? this.accumulateArrayVariants(variants, ctx) : this.accumulateObjectVariants(
|
|
552
|
+
variants,
|
|
517
553
|
ctx
|
|
518
554
|
);
|
|
519
555
|
return this.resolveStoredWorkflows(resolved);
|
|
520
556
|
} : this.resolveStoredWorkflows(storedAgent.workflows);
|
|
521
557
|
const agents = hasConditionalAgents ? ({ requestContext }) => {
|
|
522
558
|
const ctx = requestContext.toJSON();
|
|
523
|
-
const
|
|
524
|
-
|
|
559
|
+
const variants = storedAgent.agents;
|
|
560
|
+
const isArrayVariant = Array.isArray(variants[0]?.value);
|
|
561
|
+
const resolved = isArrayVariant ? this.accumulateArrayVariants(variants, ctx) : this.accumulateObjectVariants(
|
|
562
|
+
variants,
|
|
525
563
|
ctx
|
|
526
564
|
);
|
|
527
565
|
return this.resolveStoredAgents(resolved);
|
|
@@ -625,6 +663,16 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
625
663
|
};
|
|
626
664
|
}
|
|
627
665
|
const requestContextSchema = storedAgent.requestContextSchema ? (0, import_schema_compat.convertSchemaToZod)(storedAgent.requestContextSchema) : void 0;
|
|
666
|
+
const skillSource = await this.resolveAgentSkillSource(storedAgent.skills);
|
|
667
|
+
const workspace = hasConditionalWorkspace ? async ({ requestContext }) => {
|
|
668
|
+
const ctx = requestContext.toJSON();
|
|
669
|
+
const resolvedRef = this.accumulateObjectVariants(
|
|
670
|
+
storedAgent.workspace,
|
|
671
|
+
ctx
|
|
672
|
+
);
|
|
673
|
+
return this.resolveStoredWorkspace(resolvedRef, skillSource);
|
|
674
|
+
} : await this.resolveStoredWorkspace(storedAgent.workspace, skillSource);
|
|
675
|
+
const skillsFormat = storedAgent.skillsFormat;
|
|
628
676
|
const agent = new import_agent.Agent({
|
|
629
677
|
id: storedAgent.id,
|
|
630
678
|
name: storedAgent.name,
|
|
@@ -641,7 +689,9 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
641
689
|
outputProcessors,
|
|
642
690
|
rawConfig: storedAgent,
|
|
643
691
|
defaultOptions,
|
|
644
|
-
requestContextSchema
|
|
692
|
+
requestContextSchema,
|
|
693
|
+
workspace,
|
|
694
|
+
...skillsFormat && { skillsFormat }
|
|
645
695
|
});
|
|
646
696
|
this.mastra?.addAgent(agent, storedAgent.id, { source: "stored" });
|
|
647
697
|
this.logger?.debug(`[createAgentFromStoredConfig] Successfully created agent "${storedAgent.id}"`);
|
|
@@ -810,10 +860,13 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
810
860
|
return allTools;
|
|
811
861
|
}
|
|
812
862
|
resolveStoredWorkflows(storedWorkflows) {
|
|
813
|
-
if (!storedWorkflows || storedWorkflows.length === 0)
|
|
863
|
+
if (!storedWorkflows || (Array.isArray(storedWorkflows) ? storedWorkflows.length === 0 : Object.keys(storedWorkflows).length === 0)) {
|
|
864
|
+
return {};
|
|
865
|
+
}
|
|
814
866
|
if (!this.mastra) return {};
|
|
867
|
+
const normalized = Array.isArray(storedWorkflows) ? Object.fromEntries(storedWorkflows.map((key) => [key, {}])) : storedWorkflows;
|
|
815
868
|
const resolvedWorkflows = {};
|
|
816
|
-
for (const workflowKey of
|
|
869
|
+
for (const workflowKey of Object.keys(normalized)) {
|
|
817
870
|
try {
|
|
818
871
|
resolvedWorkflows[workflowKey] = this.mastra.getWorkflow(workflowKey);
|
|
819
872
|
} catch {
|
|
@@ -827,10 +880,13 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
827
880
|
return resolvedWorkflows;
|
|
828
881
|
}
|
|
829
882
|
resolveStoredAgents(storedAgents) {
|
|
830
|
-
if (!storedAgents || storedAgents.length === 0)
|
|
883
|
+
if (!storedAgents || (Array.isArray(storedAgents) ? storedAgents.length === 0 : Object.keys(storedAgents).length === 0)) {
|
|
884
|
+
return {};
|
|
885
|
+
}
|
|
831
886
|
if (!this.mastra) return {};
|
|
887
|
+
const normalized = Array.isArray(storedAgents) ? Object.fromEntries(storedAgents.map((key) => [key, {}])) : storedAgents;
|
|
832
888
|
const resolvedAgents = {};
|
|
833
|
-
for (const agentKey of
|
|
889
|
+
for (const agentKey of Object.keys(normalized)) {
|
|
834
890
|
try {
|
|
835
891
|
resolvedAgents[agentKey] = this.mastra.getAgent(agentKey);
|
|
836
892
|
} catch {
|
|
@@ -1007,8 +1063,8 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
1007
1063
|
const toolKeys = Object.keys(tools || {});
|
|
1008
1064
|
const workflows = await agent.listWorkflows({ requestContext });
|
|
1009
1065
|
const workflowKeys = Object.keys(workflows || {});
|
|
1010
|
-
const
|
|
1011
|
-
const agentKeys = Object.keys(
|
|
1066
|
+
const agentsResolved = await agent.listAgents({ requestContext });
|
|
1067
|
+
const agentKeys = Object.keys(agentsResolved || {});
|
|
1012
1068
|
const memory = await agent.getMemory({ requestContext });
|
|
1013
1069
|
const memoryConfig = memory?.getConfig();
|
|
1014
1070
|
const { inputProcessorIds, outputProcessorIds } = await agent.getConfiguredProcessorIds(requestContext);
|
|
@@ -1045,8 +1101,8 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
1045
1101
|
instructions: instructionsStr,
|
|
1046
1102
|
model,
|
|
1047
1103
|
tools: toolKeys.length > 0 ? Object.fromEntries(toolKeys.map((key) => [key, {}])) : void 0,
|
|
1048
|
-
workflows: workflowKeys.length > 0 ? workflowKeys : void 0,
|
|
1049
|
-
agents: agentKeys.length > 0 ? agentKeys : void 0,
|
|
1104
|
+
workflows: workflowKeys.length > 0 ? Object.fromEntries(workflowKeys.map((key) => [key, {}])) : void 0,
|
|
1105
|
+
agents: agentKeys.length > 0 ? Object.fromEntries(agentKeys.map((key) => [key, {}])) : void 0,
|
|
1050
1106
|
memory: memoryConfig,
|
|
1051
1107
|
inputProcessors: inputProcessorKeys,
|
|
1052
1108
|
outputProcessors: outputProcessorKeys,
|
|
@@ -1063,6 +1119,105 @@ var EditorAgentNamespace = class extends CrudEditorNamespace {
|
|
|
1063
1119
|
}
|
|
1064
1120
|
return resolved;
|
|
1065
1121
|
}
|
|
1122
|
+
// ============================================================================
|
|
1123
|
+
// Workspace Resolution
|
|
1124
|
+
// ============================================================================
|
|
1125
|
+
/**
|
|
1126
|
+
* Resolve a stored workspace reference to a runtime Workspace instance.
|
|
1127
|
+
* Handles both ID-based references (looked up from editor.workspace) and
|
|
1128
|
+
* inline workspace configurations (hydrated directly).
|
|
1129
|
+
*
|
|
1130
|
+
* When a skillSource is provided (from resolveAgentSkillSource), it is passed
|
|
1131
|
+
* to the workspace hydration so the workspace uses versioned blob-backed skills
|
|
1132
|
+
* instead of filesystem-based discovery.
|
|
1133
|
+
*/
|
|
1134
|
+
async resolveStoredWorkspace(workspaceRef, skillSource) {
|
|
1135
|
+
if (!workspaceRef) return void 0;
|
|
1136
|
+
const workspaceNs = this.editor.workspace;
|
|
1137
|
+
if (!workspaceNs) {
|
|
1138
|
+
this.logger?.warn("[resolveStoredWorkspace] No workspace namespace available on editor");
|
|
1139
|
+
return void 0;
|
|
1140
|
+
}
|
|
1141
|
+
const hydrateOptions = skillSource ? { skillSource } : void 0;
|
|
1142
|
+
if (workspaceRef.type === "id") {
|
|
1143
|
+
const resolved = await workspaceNs.getById(workspaceRef.workspaceId);
|
|
1144
|
+
if (!resolved) {
|
|
1145
|
+
this.logger?.warn(
|
|
1146
|
+
`[resolveStoredWorkspace] Workspace '${workspaceRef.workspaceId}' not found in storage, skipping`
|
|
1147
|
+
);
|
|
1148
|
+
return void 0;
|
|
1149
|
+
}
|
|
1150
|
+
return workspaceNs.hydrateSnapshotToWorkspace(workspaceRef.workspaceId, resolved, hydrateOptions);
|
|
1151
|
+
}
|
|
1152
|
+
if (workspaceRef.type === "inline") {
|
|
1153
|
+
const configHash = (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(workspaceRef.config)).digest("hex").slice(0, 12);
|
|
1154
|
+
return workspaceNs.hydrateSnapshotToWorkspace(`inline-${configHash}`, workspaceRef.config, hydrateOptions);
|
|
1155
|
+
}
|
|
1156
|
+
return void 0;
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Resolve agent-level skill configurations into a CompositeVersionedSkillSource.
|
|
1160
|
+
*
|
|
1161
|
+
* For each skill in the agent's `skills` map, checks the resolution strategy:
|
|
1162
|
+
* - `pin: '<versionId>'` → reads the specific version's tree from the DB
|
|
1163
|
+
* - `strategy: 'latest'` → reads the skill's active version tree
|
|
1164
|
+
* - `strategy: 'live'` or no strategy → skips (uses filesystem-based discovery)
|
|
1165
|
+
*
|
|
1166
|
+
* Returns a CompositeVersionedSkillSource if any versioned skills were resolved,
|
|
1167
|
+
* or undefined if all skills use filesystem-based discovery.
|
|
1168
|
+
*/
|
|
1169
|
+
async resolveAgentSkillSource(skills) {
|
|
1170
|
+
if (!skills || typeof skills !== "object") return void 0;
|
|
1171
|
+
const skillConfigs = Array.isArray(skills) ? void 0 : skills;
|
|
1172
|
+
if (!skillConfigs || Object.keys(skillConfigs).length === 0) return void 0;
|
|
1173
|
+
const storage = this.mastra?.getStorage();
|
|
1174
|
+
if (!storage) return void 0;
|
|
1175
|
+
const skillStore = await storage.getStore("skills");
|
|
1176
|
+
if (!skillStore) return void 0;
|
|
1177
|
+
const blobStore = await this.editor.resolveBlobStore();
|
|
1178
|
+
if (!blobStore) return void 0;
|
|
1179
|
+
const versionedEntries = [];
|
|
1180
|
+
for (const [skillId, config] of Object.entries(skillConfigs)) {
|
|
1181
|
+
if (!config) continue;
|
|
1182
|
+
const isPinned = !!config.pin;
|
|
1183
|
+
const isLatest = config.strategy === "latest";
|
|
1184
|
+
if (!isPinned && !isLatest) {
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
try {
|
|
1188
|
+
let version;
|
|
1189
|
+
let dirName;
|
|
1190
|
+
if (isPinned) {
|
|
1191
|
+
version = await skillStore.getVersion(config.pin);
|
|
1192
|
+
dirName = version?.name || skillId;
|
|
1193
|
+
} else {
|
|
1194
|
+
const resolved = await skillStore.getByIdResolved(skillId);
|
|
1195
|
+
if (resolved?.activeVersionId) {
|
|
1196
|
+
version = await skillStore.getVersion(resolved.activeVersionId);
|
|
1197
|
+
}
|
|
1198
|
+
if (!version) {
|
|
1199
|
+
version = await skillStore.getLatestVersion(skillId);
|
|
1200
|
+
}
|
|
1201
|
+
dirName = resolved?.name || version?.name || skillId;
|
|
1202
|
+
}
|
|
1203
|
+
if (!version?.tree) {
|
|
1204
|
+
this.logger?.warn(
|
|
1205
|
+
`[resolveAgentSkillSource] Skill '${skillId}' version has no tree manifest, skipping versioned resolution`
|
|
1206
|
+
);
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
versionedEntries.push({
|
|
1210
|
+
dirName,
|
|
1211
|
+
tree: version.tree,
|
|
1212
|
+
versionCreatedAt: version.createdAt
|
|
1213
|
+
});
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
this.logger?.warn(`[resolveAgentSkillSource] Failed to resolve version for skill '${skillId}': ${error}`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
if (versionedEntries.length === 0) return void 0;
|
|
1219
|
+
return new import_workspace.CompositeVersionedSkillSource(versionedEntries, blobStore);
|
|
1220
|
+
}
|
|
1066
1221
|
};
|
|
1067
1222
|
|
|
1068
1223
|
// src/namespaces/prompt.ts
|
|
@@ -1071,7 +1226,7 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
|
1071
1226
|
this.mastra?.removePromptBlock(id);
|
|
1072
1227
|
}
|
|
1073
1228
|
async getStorageAdapter() {
|
|
1074
|
-
const storage = this.mastra
|
|
1229
|
+
const storage = this.mastra?.getStorage();
|
|
1075
1230
|
if (!storage) throw new Error("Storage is not configured");
|
|
1076
1231
|
const store = await storage.getStore("promptBlocks");
|
|
1077
1232
|
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
@@ -1086,7 +1241,7 @@ var EditorPromptNamespace = class extends CrudEditorNamespace {
|
|
|
1086
1241
|
}
|
|
1087
1242
|
async preview(blocks, context) {
|
|
1088
1243
|
this.ensureRegistered();
|
|
1089
|
-
const storage = this.mastra
|
|
1244
|
+
const storage = this.mastra?.getStorage();
|
|
1090
1245
|
if (!storage) throw new Error("Storage is not configured");
|
|
1091
1246
|
const store = await storage.getStore("promptBlocks");
|
|
1092
1247
|
if (!store) throw new Error("Prompt blocks storage domain is not available");
|
|
@@ -1113,7 +1268,7 @@ var EditorScorerNamespace = class extends CrudEditorNamespace {
|
|
|
1113
1268
|
return storedScorer;
|
|
1114
1269
|
}
|
|
1115
1270
|
async getStorageAdapter() {
|
|
1116
|
-
const storage = this.mastra
|
|
1271
|
+
const storage = this.mastra?.getStorage();
|
|
1117
1272
|
if (!storage) throw new Error("Storage is not configured");
|
|
1118
1273
|
const store = await storage.getStore("scorerDefinitions");
|
|
1119
1274
|
if (!store) throw new Error("Scorer definitions storage domain is not available");
|
|
@@ -1194,15 +1349,255 @@ Explain your reasoning for this score in a clear, concise paragraph.`;
|
|
|
1194
1349
|
}
|
|
1195
1350
|
};
|
|
1196
1351
|
|
|
1352
|
+
// src/namespaces/workspace.ts
|
|
1353
|
+
var import_workspace2 = require("@mastra/core/workspace");
|
|
1354
|
+
var EditorWorkspaceNamespace = class extends CrudEditorNamespace {
|
|
1355
|
+
onCacheEvict(_id) {
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Hydrate a stored workspace snapshot config into a runtime Workspace instance.
|
|
1359
|
+
* Resolves provider strings to actual instances using the editor's registries.
|
|
1360
|
+
*
|
|
1361
|
+
* This is NOT called from the CrudEditorNamespace flow — it is a public utility
|
|
1362
|
+
* used by EditorAgentNamespace during agent hydration.
|
|
1363
|
+
*/
|
|
1364
|
+
async hydrateSnapshotToWorkspace(id, snapshot, options) {
|
|
1365
|
+
const config = {
|
|
1366
|
+
id,
|
|
1367
|
+
name: snapshot.name
|
|
1368
|
+
};
|
|
1369
|
+
if (snapshot.filesystem) {
|
|
1370
|
+
config.filesystem = await this.resolveFilesystem(snapshot.filesystem);
|
|
1371
|
+
}
|
|
1372
|
+
if (snapshot.sandbox) {
|
|
1373
|
+
config.sandbox = await this.resolveSandbox(snapshot.sandbox);
|
|
1374
|
+
}
|
|
1375
|
+
if (snapshot.mounts) {
|
|
1376
|
+
const mounts = {};
|
|
1377
|
+
for (const [path, fsConfig] of Object.entries(snapshot.mounts)) {
|
|
1378
|
+
mounts[path] = await this.resolveFilesystem(fsConfig);
|
|
1379
|
+
}
|
|
1380
|
+
config.mounts = mounts;
|
|
1381
|
+
}
|
|
1382
|
+
if (snapshot.search) {
|
|
1383
|
+
if (snapshot.search.bm25) {
|
|
1384
|
+
config.bm25 = snapshot.search.bm25;
|
|
1385
|
+
}
|
|
1386
|
+
if (snapshot.search.searchIndexName) {
|
|
1387
|
+
config.searchIndexName = snapshot.search.searchIndexName;
|
|
1388
|
+
}
|
|
1389
|
+
if (snapshot.search.autoIndexPaths) {
|
|
1390
|
+
config.autoIndexPaths = snapshot.search.autoIndexPaths;
|
|
1391
|
+
}
|
|
1392
|
+
if (snapshot.search.vectorProvider && this.mastra) {
|
|
1393
|
+
const vectors = this.mastra.listVectors();
|
|
1394
|
+
const vectorStore = vectors?.[snapshot.search.vectorProvider];
|
|
1395
|
+
if (vectorStore) {
|
|
1396
|
+
config.vectorStore = vectorStore;
|
|
1397
|
+
} else {
|
|
1398
|
+
this.logger?.warn(
|
|
1399
|
+
`Vector provider "${snapshot.search.vectorProvider}" not found in Mastra instance. Workspace search will be limited to BM25 only.`
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (config.vectorStore && !config.embedder) {
|
|
1404
|
+
this.logger?.warn(
|
|
1405
|
+
`Workspace has a vector store configured but no embedder. Vector/hybrid search will not be available. Configure an embedder to enable semantic search.`
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
if (options?.skillSource) {
|
|
1410
|
+
config.skillSource = options.skillSource;
|
|
1411
|
+
config.skills = ["."];
|
|
1412
|
+
} else if (snapshot.skills && snapshot.skills.length > 0) {
|
|
1413
|
+
config.skills = snapshot.skills;
|
|
1414
|
+
}
|
|
1415
|
+
if (snapshot.tools) {
|
|
1416
|
+
config.tools = snapshot.tools;
|
|
1417
|
+
}
|
|
1418
|
+
if (snapshot.autoSync !== void 0) {
|
|
1419
|
+
config.autoSync = snapshot.autoSync;
|
|
1420
|
+
}
|
|
1421
|
+
if (snapshot.operationTimeout !== void 0) {
|
|
1422
|
+
config.operationTimeout = snapshot.operationTimeout;
|
|
1423
|
+
}
|
|
1424
|
+
return new import_workspace2.Workspace(config);
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* Resolve a stored filesystem config to a runtime WorkspaceFilesystem instance.
|
|
1428
|
+
* Looks up the provider by ID in the editor's registry (which includes built-in providers).
|
|
1429
|
+
*/
|
|
1430
|
+
async resolveFilesystem(fsConfig) {
|
|
1431
|
+
const provider = this.editor.__filesystems.get(fsConfig.provider);
|
|
1432
|
+
if (!provider) {
|
|
1433
|
+
throw new Error(
|
|
1434
|
+
`Filesystem provider "${fsConfig.provider}" is not registered. Register it via new MastraEditor({ filesystems: [yourProvider] })`
|
|
1435
|
+
);
|
|
1436
|
+
}
|
|
1437
|
+
const config = { ...fsConfig.config, readOnly: fsConfig.readOnly };
|
|
1438
|
+
return await provider.createFilesystem(config);
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Resolve a stored sandbox config to a runtime WorkspaceSandbox instance.
|
|
1442
|
+
* Looks up the provider by ID in the editor's registry (which includes built-in providers).
|
|
1443
|
+
*/
|
|
1444
|
+
async resolveSandbox(sandboxConfig) {
|
|
1445
|
+
const provider = this.editor.__sandboxes.get(sandboxConfig.provider);
|
|
1446
|
+
if (!provider) {
|
|
1447
|
+
throw new Error(
|
|
1448
|
+
`Sandbox provider "${sandboxConfig.provider}" is not registered. Register it via new MastraEditor({ sandboxes: [yourProvider] })`
|
|
1449
|
+
);
|
|
1450
|
+
}
|
|
1451
|
+
return await provider.createSandbox(sandboxConfig.config);
|
|
1452
|
+
}
|
|
1453
|
+
async getStorageAdapter() {
|
|
1454
|
+
const storage = this.mastra?.getStorage();
|
|
1455
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1456
|
+
const store = await storage.getStore("workspaces");
|
|
1457
|
+
if (!store) throw new Error("Workspaces storage domain is not available");
|
|
1458
|
+
return {
|
|
1459
|
+
create: (input) => store.create({ workspace: input }),
|
|
1460
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
1461
|
+
update: (input) => store.update(input),
|
|
1462
|
+
delete: (id) => store.delete(id),
|
|
1463
|
+
list: (args) => store.list(args),
|
|
1464
|
+
listResolved: (args) => store.listResolved(args)
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
|
|
1469
|
+
// src/namespaces/skill.ts
|
|
1470
|
+
var import_workspace3 = require("@mastra/core/workspace");
|
|
1471
|
+
var EditorSkillNamespace = class extends CrudEditorNamespace {
|
|
1472
|
+
onCacheEvict(_id) {
|
|
1473
|
+
}
|
|
1474
|
+
async getStorageAdapter() {
|
|
1475
|
+
const storage = this.mastra?.getStorage();
|
|
1476
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1477
|
+
const store = await storage.getStore("skills");
|
|
1478
|
+
if (!store) throw new Error("Skills storage domain is not available");
|
|
1479
|
+
return {
|
|
1480
|
+
create: (input) => store.create({ skill: input }),
|
|
1481
|
+
getByIdResolved: (id) => store.getByIdResolved(id),
|
|
1482
|
+
update: (input) => store.update(input),
|
|
1483
|
+
delete: (id) => store.delete(id),
|
|
1484
|
+
list: (args) => store.list(args),
|
|
1485
|
+
listResolved: (args) => store.listResolved(args)
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Publish a skill from a live filesystem source.
|
|
1490
|
+
* Walks the skill directory, hashes files into the blob store,
|
|
1491
|
+
* creates a new version with the tree manifest, and sets activeVersionId.
|
|
1492
|
+
*/
|
|
1493
|
+
async publish(skillId, source, skillPath) {
|
|
1494
|
+
this.ensureRegistered();
|
|
1495
|
+
const storage = this.mastra?.getStorage();
|
|
1496
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1497
|
+
const skillStore = await storage.getStore("skills");
|
|
1498
|
+
if (!skillStore) throw new Error("Skills storage domain is not available");
|
|
1499
|
+
const blobStore = await this.editor.resolveBlobStore();
|
|
1500
|
+
if (!blobStore)
|
|
1501
|
+
throw new Error("No blob store is configured. Register one via new MastraEditor({ blobStores: [...] })");
|
|
1502
|
+
const { snapshot, tree } = await (0, import_workspace3.publishSkillFromSource)(source, skillPath, blobStore);
|
|
1503
|
+
await skillStore.update({
|
|
1504
|
+
id: skillId,
|
|
1505
|
+
...snapshot,
|
|
1506
|
+
tree,
|
|
1507
|
+
status: "published"
|
|
1508
|
+
});
|
|
1509
|
+
const latestVersion = await skillStore.getLatestVersion(skillId);
|
|
1510
|
+
if (!latestVersion) {
|
|
1511
|
+
throw new Error(`Failed to retrieve version after publishing skill "${skillId}"`);
|
|
1512
|
+
}
|
|
1513
|
+
await skillStore.update({
|
|
1514
|
+
id: skillId,
|
|
1515
|
+
activeVersionId: latestVersion.id
|
|
1516
|
+
});
|
|
1517
|
+
const resolved = await skillStore.getByIdResolved(skillId);
|
|
1518
|
+
if (!resolved) throw new Error(`Failed to resolve skill ${skillId} after publish`);
|
|
1519
|
+
this.clearCache(skillId);
|
|
1520
|
+
this.editor.agent.invalidateAgentsReferencingSkill(skillId);
|
|
1521
|
+
return resolved;
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
// src/providers.ts
|
|
1526
|
+
var import_workspace5 = require("@mastra/core/workspace");
|
|
1527
|
+
var import_workspace6 = require("@mastra/core/workspace");
|
|
1528
|
+
var localFilesystemProvider = {
|
|
1529
|
+
id: "local",
|
|
1530
|
+
name: "Local Filesystem",
|
|
1531
|
+
description: "A folder on the local disk",
|
|
1532
|
+
configSchema: {
|
|
1533
|
+
type: "object",
|
|
1534
|
+
required: ["basePath"],
|
|
1535
|
+
properties: {
|
|
1536
|
+
basePath: { type: "string", description: "Base directory path on disk" },
|
|
1537
|
+
contained: {
|
|
1538
|
+
type: "boolean",
|
|
1539
|
+
description: "Restrict operations to stay within basePath",
|
|
1540
|
+
default: true
|
|
1541
|
+
},
|
|
1542
|
+
readOnly: {
|
|
1543
|
+
type: "boolean",
|
|
1544
|
+
description: "Block all write operations",
|
|
1545
|
+
default: false
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
createFilesystem: (config) => new import_workspace5.LocalFilesystem(config)
|
|
1550
|
+
};
|
|
1551
|
+
var localSandboxProvider = {
|
|
1552
|
+
id: "local",
|
|
1553
|
+
name: "Local Sandbox",
|
|
1554
|
+
description: "Execute commands on the local machine",
|
|
1555
|
+
configSchema: {
|
|
1556
|
+
type: "object",
|
|
1557
|
+
properties: {
|
|
1558
|
+
workingDirectory: { type: "string", description: "Working directory for command execution" },
|
|
1559
|
+
timeout: { type: "number", description: "Default timeout for operations in ms" },
|
|
1560
|
+
isolation: {
|
|
1561
|
+
type: "string",
|
|
1562
|
+
enum: ["none", "seatbelt", "bwrap"],
|
|
1563
|
+
description: "Isolation backend for sandboxed execution",
|
|
1564
|
+
default: "none"
|
|
1565
|
+
},
|
|
1566
|
+
env: {
|
|
1567
|
+
type: "object",
|
|
1568
|
+
description: "Environment variables for command execution",
|
|
1569
|
+
additionalProperties: { type: "string" }
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
},
|
|
1573
|
+
createSandbox: (config) => new import_workspace6.LocalSandbox(config)
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1197
1576
|
// src/index.ts
|
|
1198
1577
|
var MastraEditor = class {
|
|
1199
1578
|
constructor(config) {
|
|
1200
1579
|
this.__logger = config?.logger;
|
|
1201
1580
|
this.__toolProviders = config?.toolProviders ?? {};
|
|
1581
|
+
this.__filesystems = /* @__PURE__ */ new Map();
|
|
1582
|
+
this.__filesystems.set(localFilesystemProvider.id, localFilesystemProvider);
|
|
1583
|
+
for (const [id, provider] of Object.entries(config?.filesystems ?? {})) {
|
|
1584
|
+
this.__filesystems.set(id, provider);
|
|
1585
|
+
}
|
|
1586
|
+
this.__sandboxes = /* @__PURE__ */ new Map();
|
|
1587
|
+
this.__sandboxes.set(localSandboxProvider.id, localSandboxProvider);
|
|
1588
|
+
for (const [id, provider] of Object.entries(config?.sandboxes ?? {})) {
|
|
1589
|
+
this.__sandboxes.set(id, provider);
|
|
1590
|
+
}
|
|
1591
|
+
this.__blobStores = /* @__PURE__ */ new Map();
|
|
1592
|
+
for (const [id, provider] of Object.entries(config?.blobStores ?? {})) {
|
|
1593
|
+
this.__blobStores.set(id, provider);
|
|
1594
|
+
}
|
|
1202
1595
|
this.agent = new EditorAgentNamespace(this);
|
|
1203
1596
|
this.mcp = new EditorMCPNamespace(this);
|
|
1204
1597
|
this.prompt = new EditorPromptNamespace(this);
|
|
1205
1598
|
this.scorer = new EditorScorerNamespace(this);
|
|
1599
|
+
this.workspace = new EditorWorkspaceNamespace(this);
|
|
1600
|
+
this.skill = new EditorSkillNamespace(this);
|
|
1206
1601
|
}
|
|
1207
1602
|
/**
|
|
1208
1603
|
* Register this editor with a Mastra instance.
|
|
@@ -1222,6 +1617,46 @@ var MastraEditor = class {
|
|
|
1222
1617
|
getToolProviders() {
|
|
1223
1618
|
return this.__toolProviders;
|
|
1224
1619
|
}
|
|
1620
|
+
/** List all registered filesystem providers */
|
|
1621
|
+
getFilesystemProviders() {
|
|
1622
|
+
return Array.from(this.__filesystems.values());
|
|
1623
|
+
}
|
|
1624
|
+
/** List all registered sandbox providers */
|
|
1625
|
+
getSandboxProviders() {
|
|
1626
|
+
return Array.from(this.__sandboxes.values());
|
|
1627
|
+
}
|
|
1628
|
+
/** List all registered blob store providers */
|
|
1629
|
+
getBlobStoreProviders() {
|
|
1630
|
+
return Array.from(this.__blobStores.values());
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Resolve a blob store from the provider registry, or fall back to the
|
|
1634
|
+
* storage backend's blobs domain.
|
|
1635
|
+
*
|
|
1636
|
+
* @param providerId - If specified, look up a registered provider by ID
|
|
1637
|
+
* and create a blob store from the given config. If omitted, falls back
|
|
1638
|
+
* to `storage.getStore('blobs')`.
|
|
1639
|
+
* @param providerConfig - Provider-specific configuration (only used when
|
|
1640
|
+
* `providerId` is specified).
|
|
1641
|
+
*/
|
|
1642
|
+
async resolveBlobStore(providerId, providerConfig) {
|
|
1643
|
+
if (providerId) {
|
|
1644
|
+
const provider = this.__blobStores.get(providerId);
|
|
1645
|
+
if (!provider) {
|
|
1646
|
+
throw new Error(
|
|
1647
|
+
`Blob store provider "${providerId}" is not registered. Register it via new MastraEditor({ blobStores: { '${providerId}': yourProvider } })`
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
const blobStore2 = await provider.createBlobStore(providerConfig ?? {});
|
|
1651
|
+
await blobStore2.init();
|
|
1652
|
+
return blobStore2;
|
|
1653
|
+
}
|
|
1654
|
+
const storage = this.__mastra?.getStorage();
|
|
1655
|
+
if (!storage) throw new Error("Storage is not configured");
|
|
1656
|
+
const blobStore = await storage.getStore("blobs");
|
|
1657
|
+
if (!blobStore) throw new Error("Blob storage domain is not available");
|
|
1658
|
+
return blobStore;
|
|
1659
|
+
}
|
|
1225
1660
|
};
|
|
1226
1661
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1227
1662
|
0 && (module.exports = {
|
|
@@ -1231,8 +1666,12 @@ var MastraEditor = class {
|
|
|
1231
1666
|
EditorNamespace,
|
|
1232
1667
|
EditorPromptNamespace,
|
|
1233
1668
|
EditorScorerNamespace,
|
|
1669
|
+
EditorSkillNamespace,
|
|
1670
|
+
EditorWorkspaceNamespace,
|
|
1234
1671
|
MastraEditor,
|
|
1235
1672
|
evaluateRuleGroup,
|
|
1673
|
+
localFilesystemProvider,
|
|
1674
|
+
localSandboxProvider,
|
|
1236
1675
|
renderTemplate,
|
|
1237
1676
|
resolveInstructionBlocks
|
|
1238
1677
|
});
|